Merge inbound to central, a=merge

This commit is contained in:
Wes Kocher 2017-04-13 17:24:01 -07:00
commit 514e230373
1317 changed files with 41751 additions and 12397 deletions

View File

@ -0,0 +1,22 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ISimpleDOM.h"
HRESULT STDMETHODCALLTYPE
ISimpleDOMNode_get_localInterface_Proxy(ISimpleDOMNode * This,
void **localInterface)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
ISimpleDOMNode_get_localInterface_Stub(ISimpleDOMNode * This,
IUnknown **localInterface)
{
return E_NOTIMPL;
}

View File

@ -168,6 +168,9 @@ interface ISimpleDOMNode : IUnknown
[propget, local] HRESULT localInterface([out][retval] void **localInterface);
[propget, call_as(get_localInterface)]
HRESULT remoteLocalInterface([out][retval] IUnknown **localInterface);
[propget] HRESULT language([out, retval] BSTR *language);
}

View File

@ -10,6 +10,7 @@ SOURCES += [
'!dlldata.c',
'!ISimpleDOM_i.c',
'!ISimpleDOM_p.c',
'AccessibleMarshalThunk.c',
]
DEFINES['REGISTER_PROXY_DLL'] = True

View File

@ -1513,7 +1513,7 @@ pref("dom.ipc.cpows.forbid-unsafe-from-browser", true);
pref("dom.ipc.cpows.forbid-cpows-in-compat-addons", true);
// ...except for these add-ons:
pref("dom.ipc.cpows.allow-cpows-in-compat-addons", "{b9db16a4-6edc-47ec-a1f4-b86292ed211d},firegestures@xuldev.org,{DDC359D1-844A-42a7-9AA1-88A850A938A8},privateTab@infocatcher,mousegesturessuite@lemon_juice.addons.mozilla.org,treestyletab@piro.sakura.ne.jp,cliqz@cliqz.com,{AE93811A-5C9A-4d34-8462-F7B864FC4696},contextsearch2@lwz.addons.mozilla.org,{EF522540-89F5-46b9-B6FE-1829E2B572C6},{677a8f98-fd64-40b0-a883-b8c95d0cbf17},images@wink.su,fx-devtools,toolkit/require,url_advisor@kaspersky.com,{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d},{dc572301-7619-498c-a57d-39143191b318},dta@downthemall.net,{86095750-AD15-46d8-BF32-C0789F7E6A32},screenwise-prod@google.com,{91aa5abe-9de4-4347-b7b5-322c38dd9271},secureLogin@blueimp.net,ich@maltegoetz.de,come.back.block.image.from@cat-in-136.blogspot.com,{7b1bf0b6-a1b9-42b0-b75d-252036438bdc},s3crypto@data,{1e0fd655-5aea-4b4c-a583-f76ef1e3af9c},akahuku.fx.sp@toshiakisp.github.io,{aff87fa2-a58e-4edd-b852-0a20203c1e17},{1018e4d6-728f-4b20-ad56-37578a4de76b},rehostimage@engy.us,lazarus@interclue.com,{b2e69492-2358-071a-7056-24ad0c3defb1},flashstopper@byo.co.il,{e4a8a97b-f2ed-450b-b12d-ee082ba24781},jid1-f3mYMbCpz2AZYl@jetpack,{8c550e28-88c9-4764-bb52-aa489cf2efcd},{37fa1426-b82d-11db-8314-0800200c9a66},{ac2cfa60-bc96-11e0-962b-0800200c9a66},igetter@presenta.net,killspinners@byo.co.il,abhere2@moztw.org,{fc6339b8-9581-4fc7-b824-dffcb091fcb7},wampi@wink.su,backtrack@byalexv.co.uk,Gladiator_X@mail.ru,{73a6fe31-595d-460b-a920-fcc0f8843232},{46551EC9-40F0-4e47-8E18-8E5CF550CFB8},acewebextension_unlisted@acestream.org,@screen_maker,yasearch@yandex.ru,sp@avast.com,s3google@translator,igetterextension@presenta.net,{C1A2A613-35F1-4FCF-B27F-2840527B6556},screenwise-testing@google.com,helper-sig@savefrom.net,browser-loader,ImageSaver@Merci.chao,proxtube@abz.agency,wrc@avast.com,{9AA46F4F-4DC7-4c06-97AF-5035170634FE},jid1-CikLKKPVkw6ipw@jetpack,artur.dubovoy@gmail.com,nlgfeb@nlgfeb.ext,{A065A84F-95B6-433A-A0C8-4C040B77CE8A},fdm_ffext@freedownloadmanager.org");
pref("dom.ipc.cpows.allow-cpows-in-compat-addons", "{b9db16a4-6edc-47ec-a1f4-b86292ed211d},firegestures@xuldev.org,{DDC359D1-844A-42a7-9AA1-88A850A938A8},privateTab@infocatcher,mousegesturessuite@lemon_juice.addons.mozilla.org,treestyletab@piro.sakura.ne.jp,cliqz@cliqz.com,{AE93811A-5C9A-4d34-8462-F7B864FC4696},contextsearch2@lwz.addons.mozilla.org,{EF522540-89F5-46b9-B6FE-1829E2B572C6},{677a8f98-fd64-40b0-a883-b8c95d0cbf17},images@wink.su,fx-devtools,url_advisor@kaspersky.com,{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d},{dc572301-7619-498c-a57d-39143191b318},dta@downthemall.net,{86095750-AD15-46d8-BF32-C0789F7E6A32},screenwise-prod@google.com,{91aa5abe-9de4-4347-b7b5-322c38dd9271},secureLogin@blueimp.net,ich@maltegoetz.de,come.back.block.image.from@cat-in-136.blogspot.com,{7b1bf0b6-a1b9-42b0-b75d-252036438bdc},s3crypto@data,{1e0fd655-5aea-4b4c-a583-f76ef1e3af9c},akahuku.fx.sp@toshiakisp.github.io,{aff87fa2-a58e-4edd-b852-0a20203c1e17},{1018e4d6-728f-4b20-ad56-37578a4de76b},rehostimage@engy.us,lazarus@interclue.com,{b2e69492-2358-071a-7056-24ad0c3defb1},flashstopper@byo.co.il,{e4a8a97b-f2ed-450b-b12d-ee082ba24781},jid1-f3mYMbCpz2AZYl@jetpack,{8c550e28-88c9-4764-bb52-aa489cf2efcd},{37fa1426-b82d-11db-8314-0800200c9a66},{ac2cfa60-bc96-11e0-962b-0800200c9a66},igetter@presenta.net,killspinners@byo.co.il,abhere2@moztw.org,{fc6339b8-9581-4fc7-b824-dffcb091fcb7},wampi@wink.su,backtrack@byalexv.co.uk,Gladiator_X@mail.ru,{73a6fe31-595d-460b-a920-fcc0f8843232},{46551EC9-40F0-4e47-8E18-8E5CF550CFB8},acewebextension_unlisted@acestream.org,@screen_maker,yasearch@yandex.ru,sp@avast.com,s3google@translator,igetterextension@presenta.net,{C1A2A613-35F1-4FCF-B27F-2840527B6556},screenwise-testing@google.com,helper-sig@savefrom.net,ImageSaver@Merci.chao,proxtube@abz.agency,wrc@avast.com,{9AA46F4F-4DC7-4c06-97AF-5035170634FE},jid1-CikLKKPVkw6ipw@jetpack,artur.dubovoy@gmail.com,nlgfeb@nlgfeb.ext,{A065A84F-95B6-433A-A0C8-4C040B77CE8A},fdm_ffext@freedownloadmanager.org");
// Enable e10s hang monitoring (slow script checking and plugin hang
// detection).

View File

@ -32,8 +32,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
ShortcutUtils:false, SimpleServiceDiscovery:false, SitePermissions:false,
Social:false, TabCrashHandler:false, Task:false, TelemetryStopwatch:false,
Translation:false, UITour:false, UpdateUtils:false, Weave:false,
fxAccounts:false, gDevTools:false, gDevToolsBrowser:false, webrtcUI:false,
FullZoomUI:false
WebNavigationFrames: false, fxAccounts:false, gDevTools:false,
gDevToolsBrowser:false, webrtcUI:false, FullZoomUI:false
*/
/**
@ -80,6 +80,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
["UITour", "resource:///modules/UITour.jsm"],
["UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"],
["Weave", "resource://services-sync/main.js"],
["WebNavigationFrames", "resource://gre/modules/WebNavigationFrames.js"],
["fxAccounts", "resource://gre/modules/FxAccounts.jsm"],
["gDevTools", "resource://devtools/client/framework/gDevTools.jsm"],
["gDevToolsBrowser", "resource://devtools/client/framework/gDevTools.jsm"],
@ -5803,9 +5804,7 @@ function handleLinkClick(event, href, linkNode) {
}
}
let frameOuterWindowID = doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
let frameOuterWindowID = WebNavigationFrames.getFrameId(doc.defaultView);
urlSecurityCheck(href, doc.nodePrincipal);
let params = {

View File

@ -47,6 +47,8 @@ XPCOMUtils.defineLazyGetter(this, "PageMenuChild", function() {
Cu.import("resource://gre/modules/PageMenu.jsm", tmp);
return new tmp.PageMenuChild();
});
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
"resource:///modules/Feeds.jsm");
@ -120,9 +122,7 @@ var handleContentContextMenu = function(event) {
let baseURI = doc.baseURI;
let referrer = doc.referrer;
let referrerPolicy = doc.referrerPolicy;
let frameOuterWindowID = doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
let frameOuterWindowID = WebNavigationFrames.getFrameId(doc.defaultView);
let loginFillInfo = LoginManagerContent.getFieldContext(event.target);
// The same-origin check will be done in nsContextMenu.openLinkInTab.
@ -536,9 +536,7 @@ var ClickEventHandler = {
}
}
let frameOuterWindowID = ownerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
let frameOuterWindowID = WebNavigationFrames.getFrameId(ownerDoc.defaultView);
let json = { button: event.button, shiftKey: event.shiftKey,
ctrlKey: event.ctrlKey, metaKey: event.metaKey,
@ -1055,7 +1053,7 @@ var PageInfoListener = {
let frameOuterWindowID = message.data.frameOuterWindowID;
// If inside frame then get the frame's window and document.
if (frameOuterWindowID) {
if (frameOuterWindowID != undefined) {
window = Services.wm.getOuterWindowWithId(frameOuterWindowID);
document = window.document;
} else {

View File

@ -15,6 +15,8 @@ Components.utils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
"resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
var gContextMenuContentData = null;
@ -62,7 +64,7 @@ nsContextMenu.prototype = {
pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
linkUrl: this.linkURL,
selectionText: this.isTextSelected ? this.selectionInfo.text : undefined,
windowId: this.frameOuterWindowID,
frameId: this.frameOuterWindowID,
};
subject.wrappedJSObject = subject;
Services.obs.notifyObservers(subject, "on-build-contextmenu", null);
@ -670,10 +672,7 @@ nsContextMenu.prototype = {
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
this.principal = ownerDoc.nodePrincipal;
this.frameOuterWindowID = ownerDoc.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
this.frameOuterWindowID = WebNavigationFrames.getFrameId(ownerDoc.defaultView);
}
this.onSocial = !!this.browser.getAttribute("origin");
@ -996,9 +995,7 @@ nsContextMenu.prototype = {
}
if (!this.isRemote) {
params.frameOuterWindowID = this.target.ownerGlobal
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
params.frameOuterWindowID = WebNavigationFrames.getFrameId(this.target.ownerGlobal);
}
// If we want to change userContextId, we must be sure that we don't
// propagate the referrer.

View File

@ -1,15 +1,17 @@
[DEFAULT]
# These tests can be prone to intermittent failures on slower systems.
# Since the specific flavor doesn't matter from a correctness standpoint,
# just skip the tests on ASAN and debug builds. Also known to be flaky on
# Linux32 (bug 1172468, bug 1349307), so skip them there as well.
skip-if = asan || debug || (os == 'linux' && bits == 32)
support-files =
head.js
[browser_all_files_referenced.js]
skip-if = debug || (os == 'linux' && bits == 32) # no point in running on both opt and debug, and will likely intermittently timeout on debug; oom crashes on linux32 (bug 1349307)
[browser_misused_characters_in_strings.js]
support-files =
bug1262648_string_with_newlines.dtd
[browser_parsable_css.js]
support-files =
dummy_page.html
skip-if = debug # no point in running on both opt and debug, and will likely intermittently timeout on debug
[browser_parsable_script.js]
skip-if = asan || (os == 'linux' && !debug && (bits == 32)) # disabled on asan because of timeouts, and bug 1172468 for the linux 32-bit pgo issue.

View File

@ -326,7 +326,7 @@ function openLinkIn(url, where, params) {
const sourceWindow = (w || window);
let win;
if (params.frameOuterWindowID && sourceWindow) {
if (params.frameOuterWindowID != undefined && sourceWindow) {
// Only notify it as a WebExtensions' webNavigation.onCreatedNavigationTarget
// event if it contains the expected frameOuterWindowID params.
// (e.g. we should not notify it as a onCreatedNavigationTarget if the user is
@ -450,7 +450,7 @@ function openLinkIn(url, where, params) {
});
targetBrowser = tabUsedForLoad.linkedBrowser;
if (params.frameOuterWindowID && w) {
if (params.frameOuterWindowID != undefined && w) {
// Only notify it as a WebExtensions' webNavigation.onCreatedNavigationTarget
// event if it contains the expected frameOuterWindowID params.
// (e.g. we should not notify it as a onCreatedNavigationTarget if the user is

View File

@ -496,11 +496,6 @@ MenuItem.prototype = {
mediaType = "image";
}
let frameId;
if (contextData.windowId) {
frameId = ExtensionManagement.getFrameId(contextData.windowId);
}
let info = {
menuItemId: this.id,
editable: contextData.onEditableArea || contextData.onPassword,
@ -518,7 +513,7 @@ MenuItem.prototype = {
setIfDefined("srcUrl", contextData.srcUrl);
setIfDefined("pageUrl", contextData.pageUrl);
setIfDefined("frameUrl", contextData.frameUrl);
setIfDefined("frameId", frameId);
setIfDefined("frameId", contextData.frameId);
setIfDefined("selectionText", contextData.selectionText);
if ((this.type === "checkbox") || (this.type === "radio")) {

View File

@ -124,7 +124,6 @@ support-files =
[browser_ext_tabs_update_url.js]
[browser_ext_themes_icons.js]
[browser_ext_themes_validation.js]
[browser_ext_topwindowid.js]
[browser_ext_url_overrides_newtab.js]
[browser_ext_url_overrides_home.js]
[browser_ext_webRequest.js]

View File

@ -1,23 +0,0 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* test_topwindowid_cleanup() {
let {Frames} = Cu.import("resource://gre/modules/ExtensionManagement.jsm", {});
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let {outerWindowID, messageManager} = tab.linkedBrowser;
ok(Frames.topWindowIds.has(outerWindowID), "Outer window ID is registered");
let awaitDisconnect = TestUtils.topicObserved("message-manager-disconnect",
subject => subject === messageManager);
yield BrowserTestUtils.removeTab(tab);
yield awaitDisconnect;
ok(!Frames.topWindowIds.has(outerWindowID), "Outer window ID is no longer registered");
});

View File

@ -104,6 +104,9 @@
RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}"
; Register AccessibleHandler.dll with COM (this writes to HKLM)
${RegisterAccessibleHandler}
!ifdef MOZ_MAINTENANCE_SERVICE
Call IsUserAdmin
Pop $R0
@ -850,6 +853,11 @@
!define AddMaintCertKeys "!insertmacro AddMaintCertKeys"
!endif
!macro RegisterAccessibleHandler
${RegisterDLL} "$INSTDIR\AccessibleHandler.dll"
!macroend
!define RegisterAccessibleHandler "!insertmacro RegisterAccessibleHandler"
; Removes various registry entries for reasons noted below (does not use SHCTX).
!macro RemoveDeprecatedKeys
StrCpy $0 "SOFTWARE\Classes"

View File

@ -906,7 +906,7 @@ cargo_target_flag := --target=$(RUST_TARGET)
# Permit users to pass flags to cargo from their mozconfigs (e.g. --color=always).
cargo_build_flags = $(CARGOFLAGS)
ifndef MOZ_DEBUG
ifndef MOZ_DEBUG_RUST
cargo_build_flags += --release
endif
cargo_build_flags += --frozen
@ -936,8 +936,8 @@ endif
ifndef MOZ_OPTIMIZE
rustflags = -C opt-level=0
# Unfortunately, -C opt-level=0 implies -C debug-assertions, so we need
# to explicitly disable them when MOZ_DEBUG is not set.
ifndef MOZ_DEBUG
# to explicitly disable them when MOZ_DEBUG_RUST is not set.
ifndef MOZ_DEBUG_RUST
rustflags += -C debug-assertions=no
endif
rustflags_override = RUSTFLAGS='$(rustflags)'

View File

@ -86,17 +86,22 @@ TabGroup::GetChromeTabGroup()
}
/* static */ TabGroup*
TabGroup::GetFromWindowActor(mozIDOMWindowProxy* aWindow)
TabGroup::GetFromWindow(mozIDOMWindowProxy* aWindow)
{
if (TabChild* tabChild = TabChild::GetFrom(aWindow)) {
return tabChild->TabGroup();
}
return nullptr;
}
/* static */ TabGroup*
TabGroup::GetFromActor(TabChild* aTabChild)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
TabChild* tabChild = TabChild::GetFrom(aWindow);
if (!tabChild) {
return nullptr;
}
ContentChild* cc = ContentChild::GetSingleton();
nsCOMPtr<nsIEventTarget> target = cc->GetActorEventTarget(tabChild);
nsCOMPtr<nsIEventTarget> target = cc->GetActorEventTarget(aTabChild);
if (!target) {
return nullptr;
}

View File

@ -67,13 +67,13 @@ public:
static TabGroup*
GetChromeTabGroup();
// Checks if the PBrowserChild associated with aWindow already has a TabGroup
// assigned to it in IPDL. Returns this TabGroup if it does. This could happen
// if the parent process created the PBrowser and we needed to assign a
// TabGroup immediately upon receiving the IPDL message. This method is main
// thread only.
static TabGroup*
GetFromWindowActor(mozIDOMWindowProxy* aWindow);
// Checks if the TabChild already has a TabGroup assigned to it in
// IPDL. Returns this TabGroup if it does. This could happen if the parent
// process created the PBrowser and we needed to assign a TabGroup immediately
// upon receiving the IPDL message. This method is main thread only.
static TabGroup* GetFromActor(TabChild* aTabChild);
static TabGroup* GetFromWindow(mozIDOMWindowProxy* aWindow);
explicit TabGroup(bool aIsChrome = false);

View File

@ -2415,22 +2415,6 @@ nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex,
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::BeginTabSwitch()
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return NS_ERROR_FAILURE;
LayerManager *mgr = widget->GetLayerManager();
if (!mgr)
return NS_ERROR_FAILURE;
mgr->BeginTabSwitch();
return NS_OK;
}
static bool
ComputeAnimationValue(nsCSSPropertyID aProperty,
Element* aElement,

View File

@ -2833,28 +2833,30 @@ nsFrameLoader::SetClampScrollPosition(bool aClamp)
}
static
ContentParent*
Tuple<ContentParent*, TabParent*>
GetContentParent(Element* aBrowser)
{
using ReturnTuple = Tuple<ContentParent*, TabParent*>;
nsCOMPtr<nsIBrowser> browser = do_QueryInterface(aBrowser);
if (!browser) {
return nullptr;
return ReturnTuple(nullptr, nullptr);
}
nsCOMPtr<nsIFrameLoader> otherLoader;
browser->GetSameProcessAsFrameLoader(getter_AddRefs(otherLoader));
if (!otherLoader) {
return nullptr;
return ReturnTuple(nullptr, nullptr);
}
TabParent* tabParent = TabParent::GetFrom(otherLoader);
if (tabParent &&
tabParent->Manager() &&
tabParent->Manager()->IsContentParent()) {
return tabParent->Manager()->AsContentParent();
return MakeTuple(tabParent->Manager()->AsContentParent(), tabParent);
}
return nullptr;
return ReturnTuple(nullptr, nullptr);
}
bool
@ -2889,7 +2891,8 @@ nsFrameLoader::TryRemoteBrowser()
}
TabParent* openingTab = TabParent::GetFrom(parentDocShell->GetOpener());
ContentParent* openerContentParent = nullptr;
RefPtr<ContentParent> openerContentParent;
RefPtr<TabParent> sameTabGroupAs;
if (openingTab &&
openingTab->Manager() &&
@ -2933,7 +2936,7 @@ nsFrameLoader::TryRemoteBrowser()
}
// Try to get the related content parent from our browser element.
openerContentParent = GetContentParent(mOwnerContent);
Tie(openerContentParent, sameTabGroupAs) = GetContentParent(mOwnerContent);
}
uint32_t chromeFlags = 0;
@ -2955,7 +2958,8 @@ nsFrameLoader::TryRemoteBrowser()
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<Element> ownerElement = mOwnerContent;
mRemoteBrowser = ContentParent::CreateBrowser(context, ownerElement, openerContentParent);
mRemoteBrowser = ContentParent::CreateBrowser(context, ownerElement,
openerContentParent, sameTabGroupAs);
if (!mRemoteBrowser) {
return false;
}

View File

@ -15005,15 +15005,14 @@ nsGlobalWindow::TabGroupOuter()
} else if (parent) {
toJoin = parent->TabGroup();
} else {
// If the tab was created by the parent process, the IPC code may have
// already created a TabGroup for us. Fetch it in that case.
toJoin = TabGroup::GetFromWindowActor(AsOuter());
toJoin = TabGroup::GetFromWindow(AsOuter());
}
#ifdef DEBUG
// Make sure that, if we have a tab group from the actor, it matches the one
// we're planning to join.
mozilla::dom::TabGroup* actorTabGroup = TabGroup::GetFromWindowActor(AsOuter());
MOZ_ASSERT_IF(actorTabGroup, actorTabGroup == toJoin);
mozilla::dom::TabGroup* testGroup = TabGroup::GetFromWindow(AsOuter());
MOZ_ASSERT_IF(testGroup, testGroup == toJoin);
#endif
mTabGroup = mozilla::dom::TabGroup::Join(AsOuter(), toJoin);

View File

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html>
<head>
<style>
#target5 {
position: absolute;
top: 0px;
left: 0px;
width: 20px;
height: 20px;
background: #f00;
}
</style>
<body>
<div id="target5"></div>
<script>
var io = new IntersectionObserver(function (records) {
console.log(records[0].rootBounds, location.href);
window.parent.postMessage(records[0].rootBounds == null, 'http://mochi.test:8888');
}, {});
io.observe(document.getElementById("target5"));
</script>
</body>
</html>

View File

@ -13,12 +13,5 @@
</style>
<body>
<div id="target5"></div>
<script>
var io = new IntersectionObserver(function (records) {
window.parent.postMessage(records[0].rootBounds == null, 'http://mochi.test:8888');
io.disconnect();
}, {});
io.observe(document.getElementById("target5"));
</script>
</body>
</html>

View File

@ -27,7 +27,6 @@
records[0].rootBounds.bottom === viewportHeight &&
records[0].rootBounds.height === viewportHeight;
window.opener.postMessage(passed, '*');
io.disconnect();
});
io.observe(document.getElementById("target"));
</script>

View File

@ -921,7 +921,7 @@ limitations under the License.
callDelayed(function () {
expect(spy.callCount).to.be(1);
done();
}, ASYNC_TIMEOUT);
}, ASYNC_TIMEOUT * 3);
});
});
@ -970,11 +970,11 @@ limitations under the License.
it('rootBounds should is set to null for cross-origin observations', function(done) {
window.onmessage = function (e) {
expect(e.data).to.be.ok();
expect(e.data).to.be(true);
done();
};
targetEl4.src = "http://example.org/tests/dom/base/test/intersectionobserver_iframe.html";
targetEl4.src = "http://example.org/tests/dom/base/test/intersectionobserver_cross_domain_iframe.html";
});

File diff suppressed because it is too large Load Diff

View File

@ -409,7 +409,7 @@ public:
}
void DrawWindow(nsGlobalWindow& aWindow, double aX, double aY,
double aW, double aH,
double aW, double aH,
const nsAString& aBgColor, uint32_t aFlags,
mozilla::ErrorResult& aError);
@ -451,11 +451,12 @@ public:
const char16_t* aEncoderOptions,
nsIInputStream** aStream) override;
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override
already_AddRefed<mozilla::gfx::SourceSurface>
GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType = nullptr) override
{
EnsureTarget();
if (aPremultAlpha) {
*aPremultAlpha = true;
if (aOutAlphaType) {
*aOutAlphaType = (mOpaque ? gfxAlphaType::Opaque : gfxAlphaType::Premult);
}
return mTarget->Snapshot();
}

View File

@ -388,7 +388,7 @@ static already_AddRefed<SourceSurface>
GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv)
{
nsLayoutUtils::SurfaceFromElementResult res =
nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME);
nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
// check origin-clean
if (!CheckSecurityForHTMLElements(res)) {
@ -432,13 +432,13 @@ HasRasterImage(HTMLImageElement& aImageEl)
}
ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
bool aIsPremultipliedAlpha /* = true */)
gfxAlphaType aAlphaType)
: mParent(aGlobal)
, mData(aData)
, mSurface(nullptr)
, mDataWrapper(new ImageUtils(mData))
, mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height)
, mIsPremultipliedAlpha(aIsPremultipliedAlpha)
, mAlphaType(aAlphaType)
, mIsCroppingAreaOutSideOfSourceImage(false)
{
MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor.");
@ -622,13 +622,11 @@ ImageBitmap::PrepareForDrawTarget(gfx::DrawTarget* aTarget)
}
// Pre-multiply alpha here.
// Apply pre-multiply alpha only if mIsPremultipliedAlpha is false.
// Ignore this step if the source surface does not have alpha channel; this
// kind of source surfaces might come form layers::PlanarYCbCrImage.
if (!mIsPremultipliedAlpha &&
mSurface->GetFormat() != SurfaceFormat::B8G8R8X8 &&
mSurface->GetFormat() != SurfaceFormat::R8G8B8X8 &&
mSurface->GetFormat() != SurfaceFormat::X8R8G8B8) {
if (mAlphaType == gfxAlphaType::NonPremult &&
!IsOpaque(mSurface->GetFormat()))
{
MOZ_ASSERT(mSurface->GetFormat() == SurfaceFormat::R8G8B8A8 ||
mSurface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
mSurface->GetFormat() == SurfaceFormat::A8R8G8B8);
@ -692,7 +690,7 @@ ImageBitmap::ToCloneData() const
{
UniquePtr<ImageBitmapCloneData> result(new ImageBitmapCloneData());
result->mPictureRect = mPictureRect;
result->mIsPremultipliedAlpha = mIsPremultipliedAlpha;
result->mAlphaType = mAlphaType;
result->mIsCroppingAreaOutSideOfSourceImage = mIsCroppingAreaOutSideOfSourceImage;
RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
result->mSurface = surface->GetDataSurface();
@ -707,8 +705,7 @@ ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal,
{
RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data,
aData->mIsPremultipliedAlpha);
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aData->mAlphaType);
// Report memory allocation.
RegisterAllocation(aGlobal, aData->mSurface);
@ -734,7 +731,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal,
nsLayoutUtils::SurfaceFromElementResult res =
nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas,
nsLayoutUtils::SFE_WANT_FIRST_FRAME);
nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
RefPtr<SourceSurface> surface = res.GetSourceSurface();
@ -926,6 +923,8 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
array.ComputeLengthAndData();
const SurfaceFormat FORMAT = SurfaceFormat::R8G8B8A8;
// ImageData's underlying data is not alpha-premultiplied.
const auto alphaType = gfxAlphaType::NonPremult;
const uint32_t BYTES_PER_PIXEL = BytesPerPixel(FORMAT);
const uint32_t imageWidth = aImageData.Width();
const uint32_t imageHeight = aImageData.Height();
@ -964,8 +963,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
}
// Create an ImageBimtap.
// ImageData's underlying data is not alpha-premultiplied.
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, false);
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, alphaType);
// Report memory allocation.
RegisterAllocation(aGlobal, data);
@ -1035,7 +1033,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap,
}
RefPtr<layers::Image> data = aImageBitmap.mData;
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aImageBitmap.mIsPremultipliedAlpha);
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data, aImageBitmap.mAlphaType);
// Set the picture rectangle.
if (ret && aCropRect.isSome()) {
@ -1499,12 +1497,12 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx,
uint32_t picRectY_;
uint32_t picRectWidth_;
uint32_t picRectHeight_;
uint32_t isPremultipliedAlpha_;
uint32_t alphaType_;
uint32_t isCroppingAreaOutSideOfSourceImage_;
if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) ||
!JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) ||
!JS_ReadUint32Pair(aReader, &isPremultipliedAlpha_,
!JS_ReadUint32Pair(aReader, &alphaType_,
&isCroppingAreaOutSideOfSourceImage_)) {
return nullptr;
}
@ -1513,6 +1511,7 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx,
int32_t picRectY = BitwiseCast<int32_t>(picRectY_);
int32_t picRectWidth = BitwiseCast<int32_t>(picRectWidth_);
int32_t picRectHeight = BitwiseCast<int32_t>(picRectHeight_);
const auto alphaType = BitwiseCast<gfxAlphaType>(alphaType_);
// Create a new ImageBitmap.
MOZ_ASSERT(!aClonedSurfaces.IsEmpty());
@ -1526,8 +1525,7 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx,
JS::Rooted<JS::Value> value(aCx);
{
RefPtr<layers::Image> img = CreateImageFromSurface(aClonedSurfaces[aIndex]);
RefPtr<ImageBitmap> imageBitmap =
new ImageBitmap(aParent, img, isPremultipliedAlpha_);
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aParent, img, alphaType);
imageBitmap->mIsCroppingAreaOutSideOfSourceImage =
isCroppingAreaOutSideOfSourceImage_;
@ -1563,7 +1561,7 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter,
const uint32_t picRectY = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.y);
const uint32_t picRectWidth = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.width);
const uint32_t picRectHeight = BitwiseCast<uint32_t>(aImageBitmap->mPictureRect.height);
const uint32_t isPremultipliedAlpha = aImageBitmap->mIsPremultipliedAlpha ? 1 : 0;
const uint32_t alphaType = BitwiseCast<uint32_t>(aImageBitmap->mAlphaType);
const uint32_t isCroppingAreaOutSideOfSourceImage = aImageBitmap->mIsCroppingAreaOutSideOfSourceImage ? 1 : 0;
// Indexing the cloned surfaces and send the index to the receiver.
@ -1572,7 +1570,7 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter,
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEBITMAP, index)) ||
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) ||
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) ||
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, isPremultipliedAlpha,
NS_WARN_IF(!JS_WriteUint32Pair(aWriter, alphaType,
isCroppingAreaOutSideOfSourceImage))) {
return false;
}
@ -2135,7 +2133,8 @@ ImageBitmap::Create(nsIGlobalObject* aGlobal,
// Create an ImageBimtap.
// Assume the data from an external buffer is not alpha-premultiplied.
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aGlobal, data, false);
RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(aGlobal, data,
gfxAlphaType::NonPremult);
// Report memory allocation.
RegisterAllocation(aGlobal, data);

View File

@ -63,7 +63,7 @@ struct ImageBitmapCloneData final
{
RefPtr<gfx::DataSourceSurface> mSurface;
gfx::IntRect mPictureRect;
bool mIsPremultipliedAlpha;
gfxAlphaType mAlphaType;
bool mIsCroppingAreaOutSideOfSourceImage;
};
@ -200,7 +200,7 @@ protected:
* CreateInternal(from ImageData) method.
*/
ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
bool aIsPremultipliedAlpha = true);
gfxAlphaType aAlphaType = gfxAlphaType::Premult);
virtual ~ImageBitmap();
@ -272,7 +272,7 @@ protected:
*/
gfx::IntRect mPictureRect;
const bool mIsPremultipliedAlpha;
const gfxAlphaType mAlphaType;
/*
* Set mIsCroppingAreaOutSideOfSourceImage if image bitmap was cropped to the

View File

@ -182,14 +182,14 @@ ImageBitmapRenderingContext::GetInputStream(const char* aMimeType,
}
already_AddRefed<mozilla::gfx::SourceSurface>
ImageBitmapRenderingContext::GetSurfaceSnapshot(bool* aPremultAlpha)
ImageBitmapRenderingContext::GetSurfaceSnapshot(gfxAlphaType* const aOutAlphaType)
{
if (!mImage) {
return nullptr;
}
if (aPremultAlpha) {
*aPremultAlpha = true;
if (aOutAlphaType) {
*aOutAlphaType = (GetIsOpaque() ? gfxAlphaType::Opaque : gfxAlphaType::Premult);
}
RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();

View File

@ -64,7 +64,7 @@ public:
nsIInputStream** aStream) override;
virtual already_AddRefed<mozilla::gfx::SourceSurface>
GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override;
GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType) override;
NS_IMETHOD SetIsOpaque(bool aIsOpaque) override;
virtual bool GetIsOpaque() override;

View File

@ -302,13 +302,13 @@ OffscreenCanvas::ToBlob(JSContext* aCx,
}
already_AddRefed<gfx::SourceSurface>
OffscreenCanvas::GetSurfaceSnapshot(bool* aPremultAlpha)
OffscreenCanvas::GetSurfaceSnapshot(gfxAlphaType* const aOutAlphaType)
{
if (!mCurrentContext) {
return nullptr;
}
return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType);
}
nsCOMPtr<nsIGlobalObject>

View File

@ -124,7 +124,7 @@ public:
return mCurrentContext;
}
already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr);
already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType = nullptr);
static already_AddRefed<OffscreenCanvas>
CreateFromCloneData(nsIGlobalObject* aGlobal, OffscreenCanvasCloneData* aData);

View File

@ -270,7 +270,7 @@ FallbackOnZero(uint32_t val, uint32_t fallback)
TexUnpackBlob::TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target,
uint32_t rowLength, uint32_t width, uint32_t height,
uint32_t depth, bool srcIsPremult)
uint32_t depth, gfxAlphaType srcAlphaType)
: mAlignment(webgl->mPixelStore_UnpackAlignment)
, mRowLength(rowLength)
, mImageHeight(FallbackOnZero(ZeroOn2D(target, webgl->mPixelStore_UnpackImageHeight),
@ -284,7 +284,7 @@ TexUnpackBlob::TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target,
, mHeight(height)
, mDepth(depth)
, mSrcIsPremult(srcIsPremult)
, mSrcAlphaType(srcAlphaType)
, mNeedsExactUpload(false)
{
@ -327,7 +327,18 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
if (!rowLength || !rowCount)
return true;
const auto srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha;
const auto fnHasPremultMismatch = [&]() {
if (mSrcAlphaType == gfxAlphaType::Opaque)
return false;
if (!HasColorAndAlpha(srcFormat))
return false;
return srcIsPremult != dstIsPremult;
};
const auto srcOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
: gl::OriginPos::BottomLeft);
const auto dstOrigin = gl::OriginPos::BottomLeft;
@ -336,7 +347,7 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
webgl->GeneratePerfWarning("%s: Conversion requires pixel reformatting. (%u->%u)",
funcName, uint32_t(srcFormat),
uint32_t(dstFormat));
} else if (mSrcIsPremult != dstIsPremult && HasColorAndAlpha(srcFormat)) {
} else if (fnHasPremultMismatch()) {
webgl->GeneratePerfWarning("%s: Conversion requires change in"
" alpha-premultiplication.",
funcName);
@ -369,7 +380,7 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
// And go!:
bool wasTrivial;
if (!ConvertImage(rowLength, rowCount,
srcBegin, srcStride, srcOrigin, srcFormat, mSrcIsPremult,
srcBegin, srcStride, srcOrigin, srcFormat, srcIsPremult,
dstBegin, dstStride, dstOrigin, dstFormat, dstIsPremult,
&wasTrivial))
{
@ -403,7 +414,7 @@ TexUnpackBytes::TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target,
bool isClientData, const uint8_t* ptr, size_t availBytes)
: TexUnpackBlob(webgl, target,
FallbackOnZero(webgl->mPixelStore_UnpackRowLength, width),
width, height, depth, false)
width, height, depth, gfxAlphaType::NonPremult)
, mIsClientData(isClientData)
, mPtr(ptr)
, mAvailBytes(availBytes)
@ -578,9 +589,9 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
TexUnpackImage::TexUnpackImage(const WebGLContext* webgl, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
layers::Image* image, bool isAlphaPremult)
layers::Image* image, gfxAlphaType srcAlphaType)
: TexUnpackBlob(webgl, target, image->GetSize().width, width, height, depth,
isAlphaPremult)
srcAlphaType)
, mImage(image)
{ }
@ -626,15 +637,32 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
break;
}
const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha;
if (mSrcIsPremult != dstIsPremult) {
if (webgl->mPixelStore_UnpackSkipPixels ||
webgl->mPixelStore_UnpackSkipRows ||
webgl->mPixelStore_UnpackSkipImages)
{
fallbackReason = "non-zero UNPACK_SKIP_* not yet supported";
break;
}
const auto fnHasPremultMismatch = [&]() {
if (mSrcAlphaType == gfxAlphaType::Opaque)
return false;
const bool srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha;
if (srcIsPremult == dstIsPremult)
return false;
if (dstIsPremult) {
fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true";
} else {
fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false";
}
return true;
};
if (fnHasPremultMismatch())
break;
}
if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) {
fallbackReason = "`format` is not RGB or RGBA";
@ -701,7 +729,7 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
}
const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf,
mSrcIsPremult);
mSrcAlphaType);
return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level,
dui, xOffset, yOffset, zOffset, out_error);
@ -713,9 +741,10 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
TexUnpackSurface::TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
gfx::DataSourceSurface* surf, bool isAlphaPremult)
gfx::DataSourceSurface* surf,
gfxAlphaType srcAlphaType)
: TexUnpackBlob(webgl, target, surf->GetSize().width, width, height, depth,
isAlphaPremult)
srcAlphaType)
, mSurf(surf)
{ }

View File

@ -51,13 +51,14 @@ public:
const uint32_t mHeight;
const uint32_t mDepth;
const bool mSrcIsPremult;
const gfxAlphaType mSrcAlphaType;
bool mNeedsExactUpload;
protected:
TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target, uint32_t rowLength,
uint32_t width, uint32_t height, uint32_t depth, bool isSrcPremult);
uint32_t width, uint32_t height, uint32_t depth,
gfxAlphaType srcAlphaType);
public:
virtual ~TexUnpackBlob() { }
@ -117,7 +118,7 @@ public:
TexUnpackImage(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
uint32_t height, uint32_t depth, layers::Image* image,
bool isAlphaPremult);
gfxAlphaType srcAlphaType);
~TexUnpackImage(); // Prevent needing to define layers::Image in the header.
@ -137,7 +138,7 @@ public:
TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
uint32_t height, uint32_t depth, gfx::DataSourceSurface* surf,
bool isAlphaPremult);
gfxAlphaType srcAlphaType);
virtual bool Validate(WebGLContext* webgl, const char* funcName,
const webgl::PackingInfo& pi) override;

View File

@ -1247,14 +1247,10 @@ WebGLContext::GetImageBuffer(int32_t* out_format)
*out_format = 0;
// Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
bool premult;
RefPtr<SourceSurface> snapshot =
GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult);
if (!snapshot) {
gfxAlphaType any;
RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot(&any);
if (!snapshot)
return nullptr;
}
MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");
RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
@ -1272,14 +1268,11 @@ WebGLContext::GetInputStream(const char* mimeType,
return NS_ERROR_FAILURE;
// Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
bool premult;
RefPtr<SourceSurface> snapshot =
GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult);
gfxAlphaType any;
RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot(&any);
if (!snapshot)
return NS_ERROR_FAILURE;
MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");
RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
return gfxUtils::GetInputStream(dataSurface, mOptions.premultipliedAlpha, mimeType,
encoderOptions, out_stream);
@ -1934,21 +1927,19 @@ WebGLContext::MakeContextCurrent() const
}
already_AddRefed<mozilla::gfx::SourceSurface>
WebGLContext::GetSurfaceSnapshot(bool* out_premultAlpha)
WebGLContext::GetSurfaceSnapshot(gfxAlphaType* const out_alphaType)
{
if (!gl)
return nullptr;
bool hasAlpha = mOptions.alpha;
SurfaceFormat surfFormat = hasAlpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8;
const auto surfFormat = mOptions.alpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8;
RefPtr<DataSourceSurface> surf;
surf = Factory::CreateDataSourceSurfaceWithStride(IntSize(mWidth, mHeight),
surfFormat,
mWidth * 4);
if (NS_WARN_IF(!surf)) {
if (NS_WARN_IF(!surf))
return nullptr;
}
gl->MakeCurrent();
{
@ -1968,15 +1959,22 @@ WebGLContext::GetSurfaceSnapshot(bool* out_premultAlpha)
}
}
if (out_premultAlpha) {
*out_premultAlpha = true;
gfxAlphaType alphaType;
if (!mOptions.alpha) {
alphaType = gfxAlphaType::Opaque;
} else if (mOptions.premultipliedAlpha) {
alphaType = gfxAlphaType::Premult;
} else {
alphaType = gfxAlphaType::NonPremult;
}
bool srcPremultAlpha = mOptions.premultipliedAlpha;
if (!srcPremultAlpha) {
if (out_premultAlpha) {
*out_premultAlpha = false;
} else if(hasAlpha) {
if (out_alphaType) {
*out_alphaType = alphaType;
} else {
// Expects Opaque or Premult
if (alphaType == gfxAlphaType::NonPremult) {
gfxUtils::PremultiplyDataSurface(surf, surf);
alphaType = gfxAlphaType::Premult;
}
}
@ -1984,10 +1982,8 @@ WebGLContext::GetSurfaceSnapshot(bool* out_premultAlpha)
Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetSoftwareBackend(),
IntSize(mWidth, mHeight),
SurfaceFormat::B8G8R8A8);
if (!dt) {
if (!dt)
return nullptr;
}
dt->SetTransform(Matrix::Translation(0.0, mHeight).PreScale(1.0, -1.0));

View File

@ -375,8 +375,8 @@ public:
const char16_t* encoderOptions,
nsIInputStream** out_stream) override;
already_AddRefed<mozilla::gfx::SourceSurface>
GetSurfaceSnapshot(bool* out_premultAlpha) override;
virtual already_AddRefed<mozilla::gfx::SourceSurface>
GetSurfaceSnapshot(gfxAlphaType* out_alphaType) override;
NS_IMETHOD SetIsOpaque(bool) override { return NS_OK; };
bool GetIsOpaque() override { return false; }

View File

@ -220,8 +220,6 @@ FromImageBitmap(WebGLContext* webgl, const char* funcName, TexImageTarget target
UniquePtr<dom::ImageBitmapCloneData> cloneData = Move(imageBitmap.ToCloneData());
const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface;
////
if (!width) {
width = surf->GetSize().width;
}
@ -230,15 +228,11 @@ FromImageBitmap(WebGLContext* webgl, const char* funcName, TexImageTarget target
height = surf->GetSize().height;
}
////
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
const bool isAlphaPremult = cloneData->mIsPremultipliedAlpha;
return MakeUnique<webgl::TexUnpackSurface>(webgl, target, width, height, depth, surf,
isAlphaPremult);
cloneData->mAlphaType);
}
static UniquePtr<webgl::TexUnpackBlob>
@ -257,6 +251,11 @@ FromImageData(WebGLContext* webgl, const char* funcName, TexImageTarget target,
const size_t stride = size.width * 4;
const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8;
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
const auto alphaType = gfxAlphaType::NonPremult;
MOZ_ASSERT(dataSize == stride * size.height);
uint8_t* wrappableData = (uint8_t*)data;
@ -281,12 +280,8 @@ FromImageData(WebGLContext* webgl, const char* funcName, TexImageTarget target,
////
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
const bool isAlphaPremult = false;
return MakeUnique<webgl::TexUnpackSurface>(webgl, target, width, height, depth, surf,
isAlphaPremult);
alphaType);
}
UniquePtr<webgl::TexUnpackBlob>
@ -294,7 +289,11 @@ WebGLContext::FromDomElem(const char* funcName, TexImageTarget target, uint32_t
uint32_t height, uint32_t depth, const dom::Element& elem,
ErrorResult* const out_error)
{
uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
// The canvas spec says that drawImage should draw the first frame of
// animated images. The webgl spec doesn't mention the issue, so we do the
// same as drawImage.
uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR;
if (mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
@ -375,16 +374,14 @@ WebGLContext::FromDomElem(const char* funcName, TexImageTarget target, uint32_t
//////
// Ok, we're good!
const bool isAlphaPremult = sfer.mIsPremultiplied;
if (layersImage) {
return MakeUnique<webgl::TexUnpackImage>(this, target, width, height, depth,
layersImage, isAlphaPremult);
layersImage, sfer.mAlphaType);
}
MOZ_ASSERT(dataSurf);
return MakeUnique<webgl::TexUnpackSurface>(this, target, width, height, depth,
dataSurf, isAlphaPremult);
dataSurf, sfer.mAlphaType);
}
////////////////////////////////////////

View File

@ -119,7 +119,8 @@ public:
// If premultAlpha is provided, then it assumed the callee can handle
// un-premultiplied surfaces, and *premultAlpha will be set to false
// if one is returned.
virtual already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* premultAlpha = nullptr) = 0;
virtual already_AddRefed<mozilla::gfx::SourceSurface>
GetSurfaceSnapshot(gfxAlphaType* out_alphaType = nullptr) = 0;
// If this context is opaque, the backing store of the canvas should
// be created as opaque; all compositing operators should assume the

View File

@ -88,7 +88,7 @@ InternalHeaders::Get(const nsACString& aName, nsACString& aValue, ErrorResult& a
return;
}
const char* delimiter = ",";
const char* delimiter = ", ";
bool firstValueFound = false;
for (uint32_t i = 0; i < mList.Length(); ++i) {

View File

@ -1308,12 +1308,12 @@ HTMLCanvasElement::SetFrameCapture(already_AddRefed<SourceSurface> aSurface,
}
already_AddRefed<SourceSurface>
HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha)
HTMLCanvasElement::GetSurfaceSnapshot(gfxAlphaType* const aOutAlphaType)
{
if (!mCurrentContext)
return nullptr;
return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType);
}
AsyncCanvasRenderer*

View File

@ -254,7 +254,8 @@ public:
bool GetIsOpaque();
virtual bool GetOpaqueAttr() override;
virtual already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr);
virtual already_AddRefed<gfx::SourceSurface>
GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType = nullptr);
/*
* Register a FrameCaptureListener with this canvas.

View File

@ -1454,12 +1454,6 @@ interface nsIDOMWindowUtils : nsISupports {
[optional] out unsigned long frameCount,
[retval, array, size_is(frameCount)] out float frameIntervals);
/**
* Signals that we're begining to tab switch. This is used by painting code to
* determine total tab switch time.
*/
void beginTabSwitch();
/**
* The DPI of the display
*/

View File

@ -77,6 +77,7 @@ ContentBridgeChild::SendPMemoryStreamConstructor(const uint64_t& aSize)
bool
ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -84,6 +85,7 @@ ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
{
return PContentBridgeChild::SendPBrowserConstructor(aActor,
aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,
@ -128,12 +130,14 @@ ContentBridgeChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
PBrowserChild*
ContentBridgeChild::AllocPBrowserChild(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext &aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
const bool& aIsForBrowser)
{
return nsIContentChild::AllocPBrowserChild(aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,
@ -149,6 +153,7 @@ ContentBridgeChild::DeallocPBrowserChild(PBrowserChild* aChild)
mozilla::ipc::IPCResult
ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -156,6 +161,7 @@ ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor,
{
return nsIContentChild::RecvPBrowserConstructor(aActor,
aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,

View File

@ -43,6 +43,7 @@ public:
virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -67,6 +68,7 @@ protected:
virtual ~ContentBridgeChild();
virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -74,6 +76,7 @@ protected:
virtual bool DeallocPBrowserChild(PBrowserChild*) override;
virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(PBrowserChild* aCctor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,

View File

@ -98,6 +98,7 @@ ContentBridgeParent::SendPBlobConstructor(PBlobParent* actor,
PBrowserParent*
ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -105,6 +106,7 @@ ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor,
{
return PContentBridgeParent::SendPBrowserConstructor(aActor,
aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,
@ -155,12 +157,14 @@ ContentBridgeParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
PBrowserParent*
ContentBridgeParent::AllocPBrowserParent(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext &aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
const bool& aIsForBrowser)
{
return nsIContentParent::AllocPBrowserParent(aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,

View File

@ -40,6 +40,7 @@ public:
virtual PBrowserParent*
SendPBrowserConstructor(PBrowserParent* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -124,6 +125,7 @@ protected:
virtual PBrowserParent*
AllocPBrowserParent(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext &aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,

View File

@ -776,18 +776,6 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
GetID(),
&tabId);
TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
RefPtr<TabChild> newChild = new TabChild(this, tabId,
newTabContext, aChromeFlags);
if (NS_FAILED(newChild->Init())) {
return NS_ERROR_ABORT;
}
if (aTabOpener) {
MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
}
// We need to assign a TabGroup to the PBrowser actor before we send it to the
// parent. Otherwise, the parent could send messages to us before we have a
// proper TabGroup for that actor.
@ -798,13 +786,26 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
} else {
tabGroup = new TabGroup();
}
TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
RefPtr<TabChild> newChild = new TabChild(this, tabId, tabGroup,
newTabContext, aChromeFlags);
if (NS_FAILED(newChild->Init())) {
return NS_ERROR_ABORT;
}
if (aTabOpener) {
MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
}
nsCOMPtr<nsIEventTarget> target = tabGroup->EventTargetFor(TaskCategory::Other);
SetEventTargetForActor(newChild, target);
Unused << SendPBrowserConstructor(
// We release this ref in DeallocPBrowserChild
RefPtr<TabChild>(newChild).forget().take(),
tabId, *ipcContext, aChromeFlags,
tabId, TabId(0), *ipcContext, aChromeFlags,
GetID(), IsForBrowser());
nsString name(aName);
@ -1442,12 +1443,14 @@ ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild)
PBrowserChild*
ContentChild::AllocPBrowserChild(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
const bool& aIsForBrowser)
{
return nsIContentChild::AllocPBrowserChild(aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,
@ -1457,6 +1460,7 @@ ContentChild::AllocPBrowserChild(const TabId& aTabId,
bool
ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -1468,6 +1472,7 @@ ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
return PContentChild::SendPBrowserConstructor(aActor,
aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,
@ -1477,6 +1482,7 @@ ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
mozilla::ipc::IPCResult
ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -1493,8 +1499,13 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
NS_IdleDispatchToCurrentThread(firstIdleTask.forget());
}
return nsIContentChild::RecvPBrowserConstructor(aActor, aTabId, aContext,
aChromeFlags, aCpID, aIsForBrowser);
return nsIContentChild::RecvPBrowserConstructor(aActor,
aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpID,
aIsForBrowser);
}
void
@ -3171,6 +3182,32 @@ ContentChild::GetConstructedEventTarget(const Message& aMsg)
return nullptr;
}
ActorHandle handle;
TabId tabId, sameTabGroupAs;
PickleIterator iter(aMsg);
if (!IPC::ReadParam(&aMsg, &iter, &handle)) {
return nullptr;
}
aMsg.IgnoreSentinel(&iter);
if (!IPC::ReadParam(&aMsg, &iter, &tabId)) {
return nullptr;
}
aMsg.IgnoreSentinel(&iter);
if (!IPC::ReadParam(&aMsg, &iter, &sameTabGroupAs)) {
return nullptr;
}
// If sameTabGroupAs is non-zero, then the new tab will be in the same
// TabGroup as a previously created tab. Rather than try to find the
// previously created tab (whose constructor message may not even have been
// processed yet, in theory) and look up its event target, we just use the
// default event target. This means that runnables for this tab will not be
// labeled. However, this path is only taken for print preview and view
// source, which are not performance-sensitive.
if (sameTabGroupAs) {
return nullptr;
}
// If the request for a new TabChild is coming from the parent process, then
// there is no opener. Therefore, we create a fresh TabGroup.
RefPtr<TabGroup> tabGroup = new TabGroup();

View File

@ -170,6 +170,7 @@ public:
virtual mozilla::ipc::IPCResult RecvSetProcessSandbox(const MaybeFileDesc& aBroker) override;
virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -509,6 +510,7 @@ public:
virtual bool SendPBrowserConstructor(PBrowserChild* actor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& context,
const uint32_t& chromeFlags,
const ContentParentId& aCpID,
@ -516,6 +518,7 @@ public:
virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(PBrowserChild* aCctor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,

View File

@ -1162,7 +1162,8 @@ ContentParent::RecvFindPlugins(const uint32_t& aPluginEpoch,
/*static*/ TabParent*
ContentParent::CreateBrowser(const TabContext& aContext,
Element* aFrameElement,
ContentParent* aOpenerContentParent)
ContentParent* aOpenerContentParent,
TabParent* aSameTabGroupAs)
{
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
@ -1243,6 +1244,7 @@ ContentParent::CreateBrowser(const TabContext& aContext,
constructorSender->SendPBrowserConstructor(
// DeallocPBrowserParent() releases this ref.
tp.forget().take(), tabId,
aSameTabGroupAs ? aSameTabGroupAs->GetTabId() : TabId(0),
aContext.AsIPCTabContext(),
chromeFlags,
constructorSender->ChildID(),
@ -2802,12 +2804,14 @@ ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
PBrowserParent*
ContentParent::AllocPBrowserParent(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpId,
const bool& aIsForBrowser)
{
return nsIContentParent::AllocPBrowserParent(aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpId,
@ -3844,6 +3848,7 @@ ContentParent::SendPBlobConstructor(PBlobParent* aActor,
PBrowserParent*
ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpId,
@ -3851,6 +3856,7 @@ ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
{
return PContentParent::SendPBrowserConstructor(aActor,
aTabId,
aSameTabGroupAs,
aContext,
aChromeFlags,
aCpId,

View File

@ -188,7 +188,8 @@ public:
static TabParent*
CreateBrowser(const TabContext& aContext,
Element* aFrameElement,
ContentParent* aOpenerContentParent);
ContentParent* aOpenerContentParent,
TabParent* aSameTabGroupAs);
static void GetAll(nsTArray<ContentParent*>& aArray);
@ -699,6 +700,7 @@ private:
virtual PBrowserParent* SendPBrowserConstructor(
PBrowserParent* actor,
const TabId& aTabId,
const TabId& aSameTabGroupsAs,
const IPCTabContext& context,
const uint32_t& chromeFlags,
const ContentParentId& aCpId,
@ -831,6 +833,7 @@ private:
DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) override;
virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpId,

View File

@ -325,8 +325,13 @@ both:
// type PopupIPCTabContext. The parent checks that if the opener is a
// browser element, the context is also for a browser element.
//
// If |sameTabGroupAs| is non-zero, the new tab should go in the same
// TabGroup as |sameTabGroupAs|. This parameter should always be zero
// for PBrowser messages sent from the child to the parent.
//
// Keep the last 3 attributes in sync with GetProcessAttributes!
async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
async PBrowser(TabId tabId, TabId sameTabGroupAs,
IPCTabContext context, uint32_t chromeFlags,
ContentParentId cpId, bool isForBrowser);
async PBlob(BlobConstructorParams params);

View File

@ -71,7 +71,8 @@ parent:
both:
// Both the parent and the child can construct the PBrowser.
// See the comment in PContent::PBrowser().
async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
async PBrowser(TabId tabId, TabId sameTabGroupAs,
IPCTabContext context, uint32_t chromeFlags,
ContentParentId cpId, bool isForBrowser);
async PBlob(BlobConstructorParams params);

View File

@ -356,19 +356,24 @@ TabChild::FindTabChild(const TabId& aTabId)
/*static*/ already_AddRefed<TabChild>
TabChild::Create(nsIContentChild* aManager,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const TabContext &aContext,
uint32_t aChromeFlags)
{
RefPtr<TabChild> iframe = new TabChild(aManager, aTabId,
aContext, aChromeFlags);
return iframe.forget();
RefPtr<TabChild> groupChild = FindTabChild(aSameTabGroupAs);
dom::TabGroup* group = groupChild ? groupChild->TabGroup() : nullptr;
RefPtr<TabChild> iframe = new TabChild(aManager, aTabId, group,
aContext, aChromeFlags);
return iframe.forget();
}
TabChild::TabChild(nsIContentChild* aManager,
const TabId& aTabId,
dom::TabGroup* aTabGroup,
const TabContext& aContext,
uint32_t aChromeFlags)
: TabContext(aContext)
, mTabGroup(aTabGroup)
, mRemoteFrame(nullptr)
, mManager(aManager)
, mChromeFlags(aChromeFlags)
@ -566,6 +571,10 @@ TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId,
nsresult
TabChild::Init()
{
if (!mTabGroup) {
mTabGroup = TabGroup::GetFromActor(this);
}
nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
if (!webBrowser) {
NS_ERROR("Couldn't create a nsWebBrowser?");
@ -2657,9 +2666,6 @@ TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIden
return;
}
// Cache the TabGroup so it can be fetched off the main thread.
TabGroup();
MOZ_ASSERT(aLayersId != 0);
mTextureFactoryIdentifier = aTextureFactoryIdentifier;
@ -3344,14 +3350,6 @@ TabChildSHistoryListener::SHistoryDidUpdate(bool aTruncate /* = false */)
mozilla::dom::TabGroup*
TabChild::TabGroup()
{
if (mTabGroup) {
return mTabGroup;
}
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
MOZ_ASSERT(window);
mTabGroup = window->TabGroup();
return mTabGroup;
}

View File

@ -278,6 +278,7 @@ public:
*/
TabChild(nsIContentChild* aManager,
const TabId& aTabId,
TabGroup* aTabGroup,
const TabContext& aContext,
uint32_t aChromeFlags);
@ -286,6 +287,7 @@ public:
/** Return a TabChild with the given attributes. */
static already_AddRefed<TabChild>
Create(nsIContentChild* aManager, const TabId& aTabId,
const TabId& aSameTabGroupAs,
const TabContext& aContext, uint32_t aChromeFlags);
// Let managees query if it is safe to send messages.

View File

@ -46,6 +46,7 @@ nsIContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild)
PBrowserChild*
nsIContentChild::AllocPBrowserChild(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -64,7 +65,8 @@ nsIContentChild::AllocPBrowserChild(const TabId& aTabId,
}
RefPtr<TabChild> child =
TabChild::Create(this, aTabId, tc.GetTabContext(), aChromeFlags);
TabChild::Create(this, aTabId, aSameTabGroupAs,
tc.GetTabContext(), aChromeFlags);
// The ref here is released in DeallocPBrowserChild.
return child.forget().take();
@ -81,6 +83,7 @@ nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
mozilla::ipc::IPCResult
nsIContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,

View File

@ -70,6 +70,7 @@ public:
virtual bool
SendPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,
@ -86,6 +87,7 @@ protected:
virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);
virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpId,
@ -94,6 +96,7 @@ protected:
virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(PBrowserChild* aActor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpID,

View File

@ -121,11 +121,14 @@ nsIContentParent::CanOpenBrowser(const IPCTabContext& aContext)
PBrowserParent*
nsIContentParent::AllocPBrowserParent(const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpId,
const bool& aIsForBrowser)
{
MOZ_ASSERT(!aSameTabGroupAs);
Unused << aCpId;
Unused << aIsForBrowser;

View File

@ -74,6 +74,7 @@ public:
MOZ_MUST_USE virtual PBrowserParent*
SendPBrowserConstructor(PBrowserParent* actor,
const TabId& aTabId,
const TabId& aSameTabGroupAs,
const IPCTabContext& context,
const uint32_t& chromeFlags,
const ContentParentId& aCpId,
@ -112,6 +113,7 @@ protected: // IPDL methods
virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*);
virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
const TabId& aSameTabGroupsAs,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const ContentParentId& aCpId,

View File

@ -77,12 +77,12 @@ function TestCoreBehavior(headers, name) {
headers.append(name, "bar");
checkHas(headers, name, "Has the header");
var expected = (start ? start.concat(",bar") : "bar");
var expected = (start ? start.concat(", bar") : "bar");
checkGet(headers, name, expected, "Retrieve all headers for name");
headers.append(name, "baz");
checkHas(headers, name, "Has the header");
expected = (start ? start.concat(",bar,baz") : "bar,baz");
expected = (start ? start.concat(", bar, baz") : "bar, baz");
checkGet(headers, name, expected, "Retrieve all headers for name");
headers.set(name, "snafu");
@ -151,7 +151,7 @@ function TestFilledHeaders() {
["uts", "321"]
]);
checkGet(filled, "zxy", "987", "Has first sequence filled key");
checkGet(filled, "xwv", "654,abc", "Has second sequence filled key");
checkGet(filled, "xwv", "654, abc", "Has second sequence filled key");
checkGet(filled, "uts", "321", "Has third sequence filled key");
TestCoreBehavior(filled, "xwv");

View File

@ -756,9 +756,13 @@ GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage)
mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
}
BindAndUploadYUVTexture(Channel_Y, yuvData->mYStride, yuvData->mYSize.height, yuvData->mYChannel, needsAllocation);
BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation);
BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation);
{
const ResetUnpackState reset(mGL);
BindAndUploadYUVTexture(Channel_Y, yuvData->mYStride, yuvData->mYSize.height, yuvData->mYChannel, needsAllocation);
BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation);
BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation);
}
if (needsAllocation) {
mGL->fUniform2f(mYTexScaleLoc, (float)yuvData->mYSize.width/yuvData->mYStride, 1.0f);
@ -868,13 +872,8 @@ GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
mGL->fViewport(0, 0, destSize.width, destSize.height);
switch (type) {
case ConvertPlanarYCbCr: {
const auto saved = mGL->GetIntAs<GLint>(LOCAL_GL_UNPACK_ALIGNMENT);
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
const auto ret = BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage));
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, saved);
return ret;
}
case ConvertPlanarYCbCr:
return BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage));
#ifdef MOZ_WIDGET_ANDROID
case ConvertSurfaceTexture:

View File

@ -530,6 +530,52 @@ ScopedPackState::UnwrapImpl()
mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows);
}
////////////////////////////////////////////////////////////////////////
// ResetUnpackState
ResetUnpackState::ResetUnpackState(GLContext* gl)
: ScopedGLWrapper<ResetUnpackState>(gl)
{
const auto fnReset = [&](GLenum pname, GLuint val, GLuint* const out_old) {
mGL->GetUIntegerv(pname, out_old);
if (*out_old != val) {
mGL->fPixelStorei(pname, val);
}
};
// Default is 4, but 1 is more useful.
fnReset(LOCAL_GL_UNPACK_ALIGNMENT, 1, &mAlignment);
if (!mGL->HasPBOState())
return;
mGL->GetUIntegerv(LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING, &mPBO);
if (mPBO != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
fnReset(LOCAL_GL_UNPACK_ROW_LENGTH , 0, &mRowLength);
fnReset(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0, &mImageHeight);
fnReset(LOCAL_GL_UNPACK_SKIP_PIXELS , 0, &mSkipPixels);
fnReset(LOCAL_GL_UNPACK_SKIP_ROWS , 0, &mSkipRows);
fnReset(LOCAL_GL_UNPACK_SKIP_IMAGES , 0, &mSkipImages);
}
void
ResetUnpackState::UnwrapImpl()
{
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mAlignment);
if (!mGL->HasPBOState())
return;
mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength);
mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight);
mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mSkipPixels);
mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mSkipRows);
mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mSkipImages);
}
////////////////////////////////////////////////////////////////////////
// ScopedBindPBO

View File

@ -362,6 +362,28 @@ protected:
void UnwrapImpl();
};
struct ResetUnpackState
: public ScopedGLWrapper<ResetUnpackState>
{
friend struct ScopedGLWrapper<ResetUnpackState>;
protected:
GLuint mAlignment;
GLuint mPBO;
GLuint mRowLength;
GLuint mImageHeight;
GLuint mSkipPixels;
GLuint mSkipRows;
GLuint mSkipImages;
public:
explicit ResetUnpackState(GLContext* gl);
protected:
void UnwrapImpl();
};
struct ScopedBindPBO final
: public ScopedGLWrapper<ScopedBindPBO>
{

View File

@ -174,14 +174,14 @@ class MacIOSurfaceImage;
/**
* A class representing a buffer of pixel data. The data can be in one
* of various formats including YCbCr.
*
*
* Create an image using an ImageContainer. Fill the image with data, and
* then call ImageContainer::SetImage to display it. An image must not be
* modified after calling SetImage. Image implementations do not need to
* perform locking; when filling an Image, the Image client is responsible
* for ensuring only one thread accesses the Image at a time, and after
* SetImage the image is immutable.
*
*
* When resampling an Image, only pixels within the buffer should be
* sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
*/
@ -258,7 +258,7 @@ protected:
/**
* A RecycleBin is owned by an ImageContainer. We store buffers in it that we
* want to recycle from one image to the next.It's a separate object from
* want to recycle from one image to the next.It's a separate object from
* ImageContainer because images need to store a strong ref to their RecycleBin
* and we must avoid creating a reference loop between an ImageContainer and
* its active image.
@ -341,7 +341,7 @@ private:
Mutex mLock;
ImageContainer* mImageContainer;
};
/**
* A class that manages Images for an ImageLayer. The only reason
* we need a separate class here is that ImageLayers aren't threadsafe
@ -421,7 +421,7 @@ public:
* mProducerID is a unique ID for the stream of images. A change in the
* mProducerID means changing to a new mFrameID namespace. All frames in
* aImages must have the same mProducerID.
*
*
* The Image data must not be modified after this method is called!
* Note that this must not be called if ENABLE_ASYNC has not been set.
*
@ -457,11 +457,11 @@ public:
* Set an Image as the current image to display. The Image must have
* been created by this ImageContainer.
* Must be called on the main thread, within a layers transaction.
*
*
* This method takes mReentrantMonitor
* when accessing thread-shared state.
* aImage can be null. While it's null, nothing will be painted.
*
*
* The Image data must not be modified after this method is called!
* Note that this must not be called if ENABLE_ASYNC been set.
*
@ -726,7 +726,7 @@ struct PlanarYCbCrData {
*
* The color format is detected based on the height/width ratios
* defined above.
*
*
* The Image that is rendered is the picture region defined by
* mPicX, mPicY and mPicSize. The size of the rendered image is
* mPicSize, not mYSize or mCbCrSize.

View File

@ -1489,7 +1489,7 @@ RefLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
* to get valid results (because the cyclic buffer was overwritten since that call).
*
* To determine availability of the data upon StopFrameTimeRecording:
* - mRecording.mNextIndex increases on each PostPresent, and never resets.
* - mRecording.mNextIndex increases on each RecordFrame, and never resets.
* - Cyclic buffer position is realized as mNextIndex % bufferSize.
* - StartFrameTimeRecording returns mNextIndex. When StopFrameTimeRecording is called,
* the required start index is passed as an arg, and we're able to calculate the required
@ -1544,16 +1544,6 @@ LayerManager::RecordFrame()
}
}
void
LayerManager::PostPresent()
{
if (!mTabSwitchStart.IsNull()) {
Telemetry::Accumulate(Telemetry::FX_TAB_SWITCH_TOTAL_MS,
uint32_t((TimeStamp::Now() - mTabSwitchStart).ToMilliseconds()));
mTabSwitchStart = TimeStamp();
}
}
void
LayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
nsTArray<float>& aFrameIntervals)
@ -1582,12 +1572,6 @@ LayerManager::StopFrameTimeRecording(uint32_t aStartIndex,
}
}
void
LayerManager::BeginTabSwitch()
{
mTabSwitchStart = TimeStamp::Now();
}
static void PrintInfo(std::stringstream& aStream, HostLayer* aLayerComposite);
#ifdef MOZ_DUMP_PAINTING

View File

@ -660,9 +660,6 @@ public:
nsTArray<float>& aFrameIntervals);
void RecordFrame();
void PostPresent();
void BeginTabSwitch();
static bool IsLogEnabled();
static mozilla::LogModule* GetLog();
@ -775,8 +772,6 @@ private:
};
FramesTimingRecording mRecording;
TimeStamp mTabSwitchStart;
public:
/*
* Methods to store/get/clear a "pending scroll info update" object on a

View File

@ -1150,19 +1150,17 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore;
}
ParentLayerPoint touchPoint = GetFirstTouchPoint(aEvent);
MOZ_ASSERT(GetCurrentTouchBlock());
if (gfxPrefs::TouchActionEnabled() && GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
// User tries to trigger a touch behavior. If allowed touch behavior is vertical pan
// + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault
// status immediately to trigger cancel event further. It should happen independent of
// the parent type (whether it is scrolling or not).
StartPanning(touchPoint);
StartPanning(aEvent);
return nsEventStatus_eConsumeNoDefault;
}
return StartPanning(touchPoint);
return StartPanning(aEvent);
}
case PANNING:
@ -1253,9 +1251,43 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
case PAN_MOMENTUM:
{
MOZ_ASSERT(GetCurrentTouchBlock());
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
mX.EndTouch(aEvent.mTime);
mY.EndTouch(aEvent.mTime);
return HandleEndOfPan();
ParentLayerPoint flingVelocity = GetVelocityVector();
// Clear our velocities; if DispatchFling() gives the fling to us,
// the fling velocity gets *added* to our existing velocity in
// AcceptFling().
mX.SetVelocity(0);
mY.SetVelocity(0);
// Clear our state so that we don't stay in the PANNING state
// if DispatchFling() gives the fling to somone else. However,
// don't send the state change notification until we've determined
// what our final state is to avoid notification churn.
StateChangeNotificationBlocker blocker(this);
SetState(NOTHING);
APZC_LOG("%p starting a fling animation if %f >= %f\n", this,
flingVelocity.Length().value, gfxPrefs::APZFlingMinVelocityThreshold());
if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) {
// Relieve overscroll now if needed, since we will not transition to a fling
// animation and then an overscroll animation, and relieve it then.
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
return nsEventStatus_eConsumeNoDefault;
}
// Make a local copy of the tree manager pointer and check that it's not
// null before calling DispatchFling(). This is necessary because Destroy(),
// which nulls out mTreeManager, could be called concurrently.
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
FlingHandoffState handoffState{flingVelocity,
GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
false /* not handoff */,
GetCurrentTouchBlock()->GetScrolledApzc()};
treeManagerLocal->DispatchFling(this, handoffState);
}
return nsEventStatus_eConsumeNoDefault;
}
case PINCHING:
SetState(NOTHING);
@ -1286,8 +1318,6 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
mPinchPaintTimerSet = false;
mX.StartTouch(aEvent.mLocalFocusPoint.x, aEvent.mTime);
mY.StartTouch(aEvent.mLocalFocusPoint.y, aEvent.mTime);
// Note that there may not be a touch block at this point, if we received the
// PinchGestureEvent directly from widget code without any touch events.
if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
@ -1312,8 +1342,6 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
APZC_LOG("%p got a scale in state %d\n", this, mState);
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.x, 0, aEvent.mTime);
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.y, 0, aEvent.mTime);
if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
return nsEventStatus_eIgnore;
@ -1449,6 +1477,8 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
}
}
SetState(NOTHING);
{
ReentrantMonitorAutoEnter lock(mMonitor);
ScheduleComposite();
@ -1458,86 +1488,32 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
// Non-negative focus point would indicate that one finger is still down
if (aEvent.mLocalFocusPoint.x != -1 && aEvent.mLocalFocusPoint.y != -1) {
if (mZoomConstraints.mAllowZoom) {
mPanDirRestricted = false;
SetState(TOUCHING);
} else {
StartPanning(aEvent.mLocalFocusPoint);
}
mPanDirRestricted = false;
mX.StartTouch(aEvent.mLocalFocusPoint.x, aEvent.mTime);
mY.StartTouch(aEvent.mLocalFocusPoint.y, aEvent.mTime);
SetState(TOUCHING);
} else {
// Otherwise, handle the fingers being lifted.
mX.EndTouch(aEvent.mTime);
mY.EndTouch(aEvent.mTime);
if (mZoomConstraints.mAllowZoom) {
ReentrantMonitorAutoEnter lock(mMonitor);
ReentrantMonitorAutoEnter lock(mMonitor);
// We can get into a situation where we are overscrolled at the end of a
// pinch if we go into overscroll with a two-finger pan, and then turn
// that into a pinch by increasing the span sufficiently. In such a case,
// there is no snap-back animation to get us out of overscroll, so we need
// to get out of it somehow.
// Moreover, in cases of scroll handoff, the overscroll can be on an APZC
// further up in the handoff chain rather than on the current APZC, so
// we need to clear overscroll along the entire handoff chain.
if (HasReadyTouchBlock()) {
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
} else {
ClearOverscroll();
}
// Along with clearing the overscroll, we also want to snap to the nearest
// snap point as appropriate.
ScrollSnap();
// We can get into a situation where we are overscrolled at the end of a
// pinch if we go into overscroll with a two-finger pan, and then turn
// that into a pinch by increasing the span sufficiently. In such a case,
// there is no snap-back animation to get us out of overscroll, so we need
// to get out of it somehow.
// Moreover, in cases of scroll handoff, the overscroll can be on an APZC
// further up in the handoff chain rather than on the current APZC, so
// we need to clear overscroll along the entire handoff chain.
if (HasReadyTouchBlock()) {
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
} else {
// when zoom is not allowed
if (mState == PINCHING) {
// still pinching
if (HasReadyTouchBlock()) {
return HandleEndOfPan();
}
}
ClearOverscroll();
}
}
return nsEventStatus_eConsumeNoDefault;
}
nsEventStatus AsyncPanZoomController::HandleEndOfPan()
{
MOZ_ASSERT(GetCurrentTouchBlock());
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
ParentLayerPoint flingVelocity = GetVelocityVector();
// Clear our velocities; if DispatchFling() gives the fling to us,
// the fling velocity gets *added* to our existing velocity in
// AcceptFling().
mX.SetVelocity(0);
mY.SetVelocity(0);
// Clear our state so that we don't stay in the PANNING state
// if DispatchFling() gives the fling to somone else. However,
// don't send the state change notification until we've determined
// what our final state is to avoid notification churn.
StateChangeNotificationBlocker blocker(this);
SetState(NOTHING);
APZC_LOG("%p starting a fling animation if %f >= %f\n", this,
flingVelocity.Length().value, gfxPrefs::APZFlingMinVelocityThreshold());
if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) {
// Relieve overscroll now if needed, since we will not transition to a fling
// animation and then an overscroll animation, and relieve it then.
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
return nsEventStatus_eConsumeNoDefault;
// Along with clearing the overscroll, we also want to snap to the nearest
// snap point as appropriate.
ScrollSnap();
}
// Make a local copy of the tree manager pointer and check that it's not
// null before calling DispatchFling(). This is necessary because Destroy(),
// which nulls out mTreeManager, could be called concurrently.
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
FlingHandoffState handoffState{flingVelocity,
GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
false /* not handoff */,
GetCurrentTouchBlock()->GetScrolledApzc()};
treeManagerLocal->DispatchFling(this, handoffState);
}
return nsEventStatus_eConsumeNoDefault;
}
@ -2348,12 +2324,12 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
}
}
nsEventStatus
AsyncPanZoomController::StartPanning(const ParentLayerPoint& aStartPoint) {
nsEventStatus AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
ReentrantMonitorAutoEnter lock(mMonitor);
float dx = mX.PanDistance(aStartPoint.x);
float dy = mY.PanDistance(aStartPoint.y);
ParentLayerPoint point = GetFirstTouchPoint(aEvent);
float dx = mX.PanDistance(point.x);
float dy = mY.PanDistance(point.y);
double angle = atan2(dy, dx); // range [-pi, pi]
angle = fabs(angle); // range [0, pi]

View File

@ -457,7 +457,6 @@ protected:
nsEventStatus OnPanEnd(const PanGestureInput& aEvent);
nsEventStatus OnPanMomentumStart(const PanGestureInput& aEvent);
nsEventStatus OnPanMomentumEnd(const PanGestureInput& aEvent);
nsEventStatus HandleEndOfPan();
/**
* Helper methods for handling scroll wheel events.
@ -577,7 +576,7 @@ protected:
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
* state and starts actually panning us.
*/
nsEventStatus StartPanning(const ParentLayerPoint& aStartPoint);
nsEventStatus StartPanning(const MultiTouchInput& aStartPoint);
/**
* Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for

View File

@ -138,7 +138,7 @@ PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
// note: negative values here tell APZC
// not to turn the pinch into a pan
ScreenIntPoint(-1, -1), 10.0 * aScale, 10.0 * aScale),
aFocus, -1.0, -1.0),
nullptr);
if (aOutEventStatuses) {
(*aOutEventStatuses)[2] = actualStatus;

View File

@ -630,7 +630,6 @@ BasicLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
FlashWidgetUpdateArea(mTarget);
}
RecordFrame();
PostPresent();
if (!mTransactionIncomplete) {
// Clear out target if we have a complete transaction.

View File

@ -194,6 +194,10 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag
// This can also happen if all images in the list are invalid.
// We return true because the caller would attempt to recreate the
// ImageClient otherwise, and that isn't going to help.
for (auto& b : mBuffers) {
RemoveTexture(b.mTextureClient);
}
mBuffers.Clear();
return true;
}

View File

@ -79,4 +79,10 @@ enum class gfxContentType {
SENTINEL = 0xffff
};
enum class gfxAlphaType {
Opaque,
Premult,
NonPremult,
};
#endif /* GFX_TYPES_H */

View File

@ -8,9 +8,12 @@
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "mozilla/intl/LocaleService.h"
#include "OSPreferences.h"
#include "mozIOSPreferences.h"
#include "unicode/udatpg.h"
namespace mozilla {
using namespace mozilla::intl;
nsCString* DateTimeFormat::mLocale = nullptr;
@ -84,48 +87,115 @@ DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
return rv;
}
// Get the date style for the formatter:
UDateFormatStyle dateStyle;
// Get the date style for the formatter.
nsAutoString skeletonDate;
nsAutoString patternDate;
bool haveSkeleton = true;
switch (aDateFormatSelector) {
case kDateFormatLong:
dateStyle = UDAT_LONG;
break;
case kDateFormatShort:
dateStyle = UDAT_SHORT;
break;
case kDateFormatYearMonth:
case kDateFormatYearMonthLong:
case kDateFormatMonthLong:
case kDateFormatWeekday:
dateStyle = UDAT_PATTERN;
break;
case kDateFormatNone:
dateStyle = UDAT_NONE;
break;
default:
NS_ERROR("Unknown nsDateFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
case kDateFormatLong:
rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleLong,
mozIOSPreferences::dateTimeFormatStyleNone,
nsDependentCString(mLocale->get()),
patternDate);
NS_ENSURE_SUCCESS(rv, rv);
haveSkeleton = false;
break;
case kDateFormatShort:
rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleShort,
mozIOSPreferences::dateTimeFormatStyleNone,
nsDependentCString(mLocale->get()),
patternDate);
NS_ENSURE_SUCCESS(rv, rv);
haveSkeleton = false;
break;
case kDateFormatYearMonth:
skeletonDate.AssignLiteral("yyyyMM");
break;
case kDateFormatYearMonthLong:
skeletonDate.AssignLiteral("yyyyMMMM");
break;
case kDateFormatMonthLong:
skeletonDate.AssignLiteral("MMMM");
break;
case kDateFormatWeekday:
skeletonDate.AssignLiteral("EEE");
break;
case kDateFormatNone:
haveSkeleton = false;
break;
default:
NS_ERROR("Unknown nsDateFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
}
// Get the time style for the formatter:
UDateFormatStyle timeStyle;
UErrorCode status = U_ZERO_ERROR;
if (haveSkeleton) {
// Get pattern for skeleton.
UDateTimePatternGenerator* patternGenerator = udatpg_open(mLocale->get(), &status);
if (U_SUCCESS(status)) {
int32_t patternLength;
patternDate.SetLength(DATETIME_FORMAT_INITIAL_LEN);
patternLength = udatpg_getBestPattern(patternGenerator,
reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
skeletonDate.Length(),
reinterpret_cast<UChar*>(patternDate.BeginWriting()),
DATETIME_FORMAT_INITIAL_LEN,
&status);
patternDate.SetLength(patternLength);
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udatpg_getBestPattern(patternGenerator,
reinterpret_cast<const UChar*>(skeletonDate.BeginReading()),
skeletonDate.Length(),
reinterpret_cast<UChar*>(patternDate.BeginWriting()),
patternLength,
&status);
}
}
udatpg_close(patternGenerator);
}
// Get the time style for the formatter.
nsAutoString patternTime;
switch (aTimeFormatSelector) {
case kTimeFormatSeconds:
timeStyle = UDAT_MEDIUM;
break;
case kTimeFormatNoSeconds:
timeStyle = UDAT_SHORT;
break;
case kTimeFormatNone:
timeStyle = UDAT_NONE;
break;
default:
NS_ERROR("Unknown nsTimeFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
case kTimeFormatSeconds:
rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone,
mozIOSPreferences::dateTimeFormatStyleLong,
nsDependentCString(mLocale->get()),
patternTime);
NS_ENSURE_SUCCESS(rv, rv);
break;
case kTimeFormatNoSeconds:
rv = OSPreferences::GetInstance()->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone,
mozIOSPreferences::dateTimeFormatStyleShort,
nsDependentCString(mLocale->get()),
patternTime);
NS_ENSURE_SUCCESS(rv, rv);
break;
case kTimeFormatNone:
break;
default:
NS_ERROR("Unknown nsTimeFormatSelector");
return NS_ERROR_ILLEGAL_VALUE;
}
// generate date/time string
nsAutoString pattern;
if (patternTime.Length() == 0) {
pattern.Assign(patternDate);
} else if (patternDate.Length() == 0) {
pattern.Assign(patternTime);
} else {
OSPreferences::GetDateTimeConnectorPattern(nsDependentCString(mLocale->get()), pattern);
int32_t index = pattern.Find("{1}");
if (index != kNotFound)
pattern.Replace(index, 3, patternDate);
index = pattern.Find("{0}");
if (index != kNotFound)
pattern.Replace(index, 3, patternTime);
}
// Generate date/time string.
nsAutoString timeZoneID(u"GMT");
if (aTimeParameters) {
int32_t totalOffsetMinutes = (aTimeParameters->tp_gmt_offset + aTimeParameters->tp_dst_offset) / 60;
@ -137,100 +207,38 @@ DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
}
}
UErrorCode status = U_ZERO_ERROR;
UDateFormat* dateTimeFormat;
if (dateStyle == UDAT_PATTERN) {
nsAutoString pattern;
dateTimeFormat = udat_open(timeStyle, UDAT_NONE, mLocale->get(), nullptr, -1, nullptr, -1, &status);
if (U_SUCCESS(status) && dateTimeFormat) {
int32_t patternLength;
if (timeStyle != UDAT_NONE) {
pattern.SetLength(DATETIME_FORMAT_INITIAL_LEN);
patternLength = udat_toPattern(dateTimeFormat, FALSE, reinterpret_cast<UChar*>(pattern.BeginWriting()), DATETIME_FORMAT_INITIAL_LEN, &status);
pattern.SetLength(patternLength);
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udat_toPattern(dateTimeFormat, FALSE, reinterpret_cast<UChar*>(pattern.BeginWriting()), patternLength, &status);
}
}
nsAutoString skeleton;
switch (aDateFormatSelector) {
case kDateFormatYearMonth:
skeleton.AssignLiteral("yyyyMM ");
break;
case kDateFormatYearMonthLong:
skeleton.AssignLiteral("yyyyMMMM ");
break;
case kDateFormatMonthLong:
skeleton.AssignLiteral("MMMM ");
break;
case kDateFormatWeekday:
skeleton.AssignLiteral("EEE ");
break;
default:
break;
}
int32_t dateSkeletonLen = skeleton.Length();
if (timeStyle != UDAT_NONE) {
skeleton.SetLength(DATETIME_FORMAT_INITIAL_LEN);
int32_t skeletonLength = udatpg_getSkeleton(nullptr, reinterpret_cast<const UChar*>(pattern.BeginReading()), patternLength,
reinterpret_cast<UChar*>(skeleton.BeginWriting() + dateSkeletonLen), DATETIME_FORMAT_INITIAL_LEN - dateSkeletonLen, &status);
skeleton.SetLength(dateSkeletonLen + skeletonLength);
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udatpg_getSkeleton(nullptr, reinterpret_cast<const UChar*>(pattern.BeginReading()), patternLength,
reinterpret_cast<UChar*>(skeleton.BeginWriting() + dateSkeletonLen), dateSkeletonLen + skeletonLength, &status);
}
}
UDateTimePatternGenerator* patternGenerator = udatpg_open(mLocale->get(), &status);
if (U_SUCCESS(status)) {
pattern.SetLength(DATETIME_FORMAT_INITIAL_LEN);
patternLength = udatpg_getBestPattern(patternGenerator, reinterpret_cast<const UChar*>(skeleton.BeginReading()), skeleton.Length(),
reinterpret_cast<UChar*>(pattern.BeginWriting()), DATETIME_FORMAT_INITIAL_LEN, &status);
pattern.SetLength(patternLength);
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udatpg_getBestPattern(patternGenerator, reinterpret_cast<const UChar*>(skeleton.BeginReading()), skeleton.Length(),
reinterpret_cast<UChar*>(pattern.BeginWriting()), patternLength, &status);
}
}
udatpg_close(patternGenerator);
}
udat_close(dateTimeFormat);
if (aTimeParameters) {
dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(), reinterpret_cast<const UChar*>(timeZoneID.BeginReading()), timeZoneID.Length(),
reinterpret_cast<const UChar*>(pattern.BeginReading()), pattern.Length(), &status);
} else {
dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(), nullptr, -1, reinterpret_cast<const UChar*>(pattern.BeginReading()), pattern.Length(), &status);
}
if (aTimeParameters) {
dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
reinterpret_cast<const UChar*>(timeZoneID.BeginReading()),
timeZoneID.Length(),
reinterpret_cast<const UChar*>(pattern.BeginReading()),
pattern.Length(),
&status);
} else {
if (aTimeParameters) {
dateTimeFormat = udat_open(timeStyle, dateStyle, mLocale->get(), reinterpret_cast<const UChar*>(timeZoneID.BeginReading()), timeZoneID.Length(), nullptr, -1, &status);
} else {
dateTimeFormat = udat_open(timeStyle, dateStyle, mLocale->get(), nullptr, -1, nullptr, -1, &status);
}
dateTimeFormat = udat_open(UDAT_PATTERN, UDAT_PATTERN, mLocale->get(),
nullptr, -1,
reinterpret_cast<const UChar*>(pattern.BeginReading()),
pattern.Length(),
&status);
}
if (U_SUCCESS(status) && dateTimeFormat) {
aStringOut.SetLength(DATETIME_FORMAT_INITIAL_LEN);
dateTimeLen = udat_format(dateTimeFormat, aUDateTime, reinterpret_cast<UChar*>(aStringOut.BeginWriting()), DATETIME_FORMAT_INITIAL_LEN, nullptr, &status);
dateTimeLen = udat_format(dateTimeFormat, aUDateTime,
reinterpret_cast<UChar*>(aStringOut.BeginWriting()),
DATETIME_FORMAT_INITIAL_LEN,
nullptr,
&status);
aStringOut.SetLength(dateTimeLen);
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udat_format(dateTimeFormat, aUDateTime, reinterpret_cast<UChar*>(aStringOut.BeginWriting()), dateTimeLen, nullptr, &status);
udat_format(dateTimeFormat, aUDateTime,
reinterpret_cast<UChar*>(aStringOut.BeginWriting()),
dateTimeLen,
nullptr,
&status);
}
}

View File

@ -279,22 +279,21 @@ bool
OSPreferences::GetDateTimeConnectorPattern(const nsACString& aLocale,
nsAString& aRetVal)
{
bool result = false;
#ifdef ENABLE_INTL_API
UErrorCode status = U_ZERO_ERROR;
UDateTimePatternGenerator* pg = udatpg_open(PromiseFlatCString(aLocale).get(), &status);
if (U_FAILURE(status)) {
return false;
if (U_SUCCESS(status)) {
int32_t resultSize;
const UChar* value = udatpg_getDateTimeFormat(pg, &resultSize);
MOZ_ASSERT(resultSize >= 0);
aRetVal.Assign((char16_t*)value, resultSize);
result = true;
}
int32_t resultSize;
const UChar* value = udatpg_getDateTimeFormat(pg, &resultSize);
MOZ_ASSERT(resultSize >= 0);
aRetVal.Assign((char16_t*)value, resultSize);
return true;
#else
return false;
udatpg_close(pg);
#endif
return result;
}
/**

View File

@ -101,6 +101,9 @@ public:
*/
bool GetSystemLocales(nsTArray<nsCString>& aRetVal);
static bool GetDateTimeConnectorPattern(const nsACString& aLocale,
nsAString& aRetVal);
protected:
nsTArray<nsCString> mSystemLocales;
@ -129,9 +132,6 @@ private:
const nsACString& aLocale,
nsAString& aRetVal);
bool GetDateTimeConnectorPattern(const nsACString& aLocale,
nsAString& aRetVal);
/**
* This is a host environment specific method that will be implemented
* separately for each platform.

View File

@ -3,6 +3,32 @@
namespace mozilla {
// Normalise time.
static nsAutoCString nt(nsAutoCString aDatetime)
{
nsAutoCString datetime = aDatetime;
// Replace "January 01" with "January 1" (found on Windows).
int32_t ind = datetime.Find("January 01");
if (ind != kNotFound)
datetime.Replace(ind, 10, "January 1");
// Strip trailing " GMT" (found on Mac/Linux).
ind = datetime.Find(" GMT");
if (ind != kNotFound)
datetime.Truncate(ind);
// Strip leading "Thursday, " or "Wednesday, " (found on Windows).
ind = datetime.Find("Thursday, ");
if (ind == 0)
datetime.Replace(0, 10, "");
ind = datetime.Find("Wednesday, ");
if (ind == 0)
datetime.Replace(0, 11, "");
return datetime;
}
TEST(DateTimeFormat, FormatPRExplodedTime) {
PRTime prTime = 0;
PRExplodedTime prExplodedTime;
@ -13,37 +39,37 @@ TEST(DateTimeFormat, FormatPRExplodedTime) {
nsAutoString formattedTime;
nsresult rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 12:00:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("January 1, 1970, 12:00:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
prExplodedTime = { 0, 0, 19, 0, 1, 0, 1970, 4, 0, { (19 * 60), 0 } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 12:19:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("January 1, 1970, 12:19:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
prExplodedTime = { 0, 0, 0, 7, 1, 0, 1970, 4, 0, { (6 * 60 * 60), (1 * 60 * 60) } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 7:00:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("January 1, 1970, 7:00:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
prExplodedTime = { 0, 0, 29, 11, 1, 0, 1970, 4, 0, { (10 * 60 * 60) + (29 * 60), (1 * 60 * 60) } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 11:29:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("January 1, 1970, 11:29:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
prExplodedTime = { 0, 0, 37, 23, 31, 11, 1969, 3, 364, { -(23 * 60), 0 } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("December 31, 1969 at 11:37:00 PM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("December 31, 1969, 11:37:00 PM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
prExplodedTime = { 0, 0, 0, 17, 31, 11, 1969, 3, 364, { -(7 * 60 * 60), 0 } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("December 31, 1969 at 5:00:00 PM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("December 31, 1969, 5:00:00 PM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
prExplodedTime = { 0, 0, 47, 14, 31, 11, 1969, 3, 364, { -((10 * 60 * 60) + (13 * 60)), (1 * 60 * 60) } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("December 31, 1969 at 2:47:00 PM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("December 31, 1969, 2:47:00 PM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
}
TEST(DateTimeFormat, DateFormatSelectors) {
@ -68,11 +94,11 @@ TEST(DateTimeFormat, DateFormatSelectors) {
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatYearMonth, kTimeFormatNoSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("01/1970, 12:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("01/1970, 12:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatYearMonth, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("01/1970, 12:00:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("01/1970, 12:00:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatWeekday, kTimeFormatNone, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
@ -80,11 +106,11 @@ TEST(DateTimeFormat, DateFormatSelectors) {
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatWeekday, kTimeFormatNoSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("Thu 12:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("Thu, 12:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatWeekday, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("Thu 12:00:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
ASSERT_STREQ("Thu, 12:00:00 AM", nt(NS_ConvertUTF16toUTF8(formattedTime)).get());
}
}

View File

@ -457,6 +457,11 @@ bool Pickle::ReadSentinel(PickleIterator* iter, uint32_t sentinel) const {
return found == sentinel;
}
bool Pickle::IgnoreSentinel(PickleIterator* iter) const {
uint32_t found;
return ReadUInt32(iter, &found);
}
bool Pickle::WriteSentinel(uint32_t sentinel) {
return WriteUInt32(sentinel);
}

View File

@ -129,6 +129,15 @@ class Pickle {
}
#endif
bool IgnoreSentinel(PickleIterator* iter) const
#ifdef MOZ_PICKLE_SENTINEL_CHECKING
;
#else
{
return true;
}
#endif
// NOTE: The message type optional parameter should _only_ be called from
// generated IPDL code, as it is used to trigger the IPC_READ_LATENCY_MS
// telemetry probe.

View File

@ -490,16 +490,19 @@ EnqueuePromiseReactionJob(JSContext* cx, HandleObject reactionObj,
Rooted<PromiseReactionRecord*> reaction(cx);
RootedValue handlerArg(cx, handlerArg_);
mozilla::Maybe<AutoCompartment> ac;
if (IsWrapper(reactionObj)) {
RootedObject unwrappedReactionObj(cx, UncheckedUnwrap(reactionObj));
if (!unwrappedReactionObj)
return false;
ac.emplace(cx, unwrappedReactionObj);
reaction = &unwrappedReactionObj->as<PromiseReactionRecord>();
if (!cx->compartment()->wrap(cx, &handlerArg))
return false;
} else {
if (!IsProxy(reactionObj)) {
MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
reaction = &reactionObj->as<PromiseReactionRecord>();
} else {
if (JS_IsDeadWrapper(UncheckedUnwrap(reactionObj))) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
reaction = &UncheckedUnwrap(reactionObj)->as<PromiseReactionRecord>();
MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
ac.emplace(cx, reaction);
if (!reaction->compartment()->wrap(cx, &handlerArg))
return false;
}
// Must not enqueue a reaction job more than once.
@ -640,7 +643,7 @@ FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue v
if (!IsProxy(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
if (JS_IsDeadWrapper(promiseObj)) {
if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
@ -790,7 +793,7 @@ RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue re
if (!IsProxy(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
if (JS_IsDeadWrapper(promiseObj)) {
if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
@ -931,8 +934,15 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
// back, we check if the reaction is a wrapper and if so, unwrap it and
// enter its compartment.
mozilla::Maybe<AutoCompartment> ac;
if (IsWrapper(reactionObj)) {
if (!IsProxy(reactionObj)) {
MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
} else {
reactionObj = UncheckedUnwrap(reactionObj);
if (JS_IsDeadWrapper(reactionObj)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
ac.emplace(cx, reactionObj);
}
@ -2810,10 +2820,14 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis
RootedObject blockedPromise(cx, blockedPromise_);
mozilla::Maybe<AutoCompartment> ac;
if (IsWrapper(promiseObj)) {
if (IsProxy(promiseObj)) {
unwrappedPromiseObj = CheckedUnwrap(promiseObj);
if (!unwrappedPromiseObj)
return false;
if (JS_IsDeadWrapper(unwrappedPromiseObj)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
ac.emplace(cx, unwrappedPromiseObj);
if (!cx->compartment()->wrap(cx, &blockedPromise))
return false;
@ -2864,8 +2878,12 @@ AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise,
// If only a single reaction exists, it's stored directly instead of in a
// list. In that case, `reactionsObj` might be a wrapper, which we can
// always safely unwrap.
if (IsWrapper(reactionsObj)) {
if (IsProxy(reactionsObj)) {
reactionsObj = UncheckedUnwrap(reactionsObj);
if (JS_IsDeadWrapper(reactionsObj)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
MOZ_ASSERT(reactionsObj->is<PromiseReactionRecord>());
}

View File

@ -43,9 +43,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
SourceBufferHolder& sourceBuffer,
HandleScope enclosingScope);
// Call setters for optional arguments.
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
JSScript* compileGlobalScript(ScopeKind scopeKind);
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule();
@ -54,12 +51,13 @@ class MOZ_STACK_CLASS BytecodeCompiler
const Maybe<uint32_t>& parameterListEnd);
ScriptSourceObject* sourceObjectPtr() const;
SourceCompressionTask* sourceCompressionTask() const;
private:
JSScript* compileScript(HandleObject environment, SharedContext* sc);
bool checkLength();
bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
bool maybeCompressSource();
bool enqueueOffThreadSourceCompression();
bool canLazilyParse();
bool createParser();
bool createSourceAndParser(const Maybe<uint32_t>& parameterListEnd = Nothing());
@ -67,7 +65,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
bool maybeCompleteCompressSource();
AutoKeepAtoms keepAtoms;
@ -80,9 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
RootedScriptSource sourceObject;
ScriptSource* scriptSource;
Maybe<SourceCompressionTask> maybeSourceCompressor;
SourceCompressionTask* sourceCompressor;
SourceCompressionTask* sourceCompressionTask_;
Maybe<UsedNameTracker> usedNames;
Maybe<Parser<SyntaxParseHandler>> syntaxParser;
@ -172,7 +167,7 @@ BytecodeCompiler::BytecodeCompiler(JSContext* cx,
enclosingScope(cx, enclosingScope),
sourceObject(cx),
scriptSource(nullptr),
sourceCompressor(nullptr),
sourceCompressionTask_(nullptr),
directives(options.strictOption),
startPosition(keepAtoms),
script(cx)
@ -180,12 +175,6 @@ BytecodeCompiler::BytecodeCompiler(JSContext* cx,
MOZ_ASSERT(sourceBuffer.get());
}
void
BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor)
{
this->sourceCompressor = sourceCompressor;
}
bool
BytecodeCompiler::checkLength()
{
@ -212,21 +201,11 @@ BytecodeCompiler::createScriptSource(const Maybe<uint32_t>& parameterListEnd)
return false;
scriptSource = sourceObject->source();
return true;
}
bool
BytecodeCompiler::maybeCompressSource()
{
if (!sourceCompressor) {
maybeSourceCompressor.emplace(cx);
sourceCompressor = maybeSourceCompressor.ptr();
}
if (!cx->compartment()->behaviors().discardSource()) {
if (options.sourceIsLazy) {
scriptSource->setSourceRetrievable();
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer)) {
return false;
}
}
@ -234,6 +213,40 @@ BytecodeCompiler::maybeCompressSource()
return true;
}
bool
BytecodeCompiler::enqueueOffThreadSourceCompression()
{
// There are several cases where source compression is not a good idea:
// - If the script is tiny, then compression will save little or no space.
// - If there is only one core, then compression will contend with JS
// execution (which hurts benchmarketing).
//
// Otherwise, enqueue a compression task to be processed when a major
// GC is requested.
if (!scriptSource->hasUncompressedSource())
return true;
bool canCompressOffThread =
HelperThreadState().cpuCount > 1 &&
HelperThreadState().threadCount >= 2 &&
CanUseExtraThreads();
const size_t TINY_SCRIPT = 256;
if (TINY_SCRIPT <= sourceBuffer.length() && canCompressOffThread) {
// Heap allocate the task. It will be freed upon compression
// completing in AttachFinishedCompressedSources.
SourceCompressionTask* task = cx->new_<SourceCompressionTask>(cx->runtime(),
scriptSource);
if (!task)
return false;
if (!EnqueueOffThreadCompression(cx, task))
return false;
sourceCompressionTask_ = task;
}
return true;
}
bool
BytecodeCompiler::canLazilyParse()
{
@ -263,7 +276,6 @@ BytecodeCompiler::createParser()
parser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(),
/* foldConstants = */ true, *usedNames, syntaxParser.ptrOr(nullptr), nullptr);
parser->sct = sourceCompressor;
parser->ss = scriptSource;
if (!parser->checkOptions())
return false;
@ -276,7 +288,6 @@ bool
BytecodeCompiler::createSourceAndParser(const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
{
return createScriptSource(parameterListEnd) &&
maybeCompressSource() &&
createParser();
}
@ -341,12 +352,6 @@ BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObj
return true;
}
bool
BytecodeCompiler::maybeCompleteCompressSource()
{
return !maybeSourceCompressor || maybeSourceCompressor->complete();
}
JSScript*
BytecodeCompiler::compileScript(HandleObject environment, SharedContext* sc)
{
@ -394,13 +399,14 @@ BytecodeCompiler::compileScript(HandleObject environment, SharedContext* sc)
usedNames->reset();
}
if (!maybeCompleteCompressSource())
return nullptr;
// We have just finished parsing the source. Inform the source so that we
// can compute statistics (e.g. how much time our functions remain lazy).
script->scriptSource()->recordParseEnded();
// Enqueue an off-thread source compression task after finishing parsing.
if (!enqueueOffThreadSourceCompression())
return nullptr;
MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
return script;
@ -462,7 +468,8 @@ BytecodeCompiler::compileModule()
module->setInitialEnvironment(env);
if (!maybeCompleteCompressSource())
// Enqueue an off-thread source compression task after finishing parsing.
if (!enqueueOffThreadSourceCompression())
return nullptr;
MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
@ -517,7 +524,8 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
if (!NameFunctions(cx, fn))
return false;
if (!maybeCompleteCompressSource())
// Enqueue an off-thread source compression task after finishing parsing.
if (!enqueueOffThreadSourceCompression())
return false;
return true;
@ -529,6 +537,12 @@ BytecodeCompiler::sourceObjectPtr() const
return sourceObject.get();
}
SourceCompressionTask*
BytecodeCompiler::sourceCompressionTask() const
{
return sourceCompressionTask_;
}
ScriptSourceObject*
frontend::CreateScriptSourceObject(JSContext* cx, const ReadOnlyCompileOptions& options,
const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
@ -580,16 +594,22 @@ class MOZ_STACK_CLASS AutoInitializeSourceObject
{
BytecodeCompiler& compiler_;
ScriptSourceObject** sourceObjectOut_;
SourceCompressionTask** sourceCompressionTaskOut_;
public:
AutoInitializeSourceObject(BytecodeCompiler& compiler, ScriptSourceObject** sourceObjectOut)
AutoInitializeSourceObject(BytecodeCompiler& compiler,
ScriptSourceObject** sourceObjectOut,
SourceCompressionTask** sourceCompressionTaskOut)
: compiler_(compiler),
sourceObjectOut_(sourceObjectOut)
sourceObjectOut_(sourceObjectOut),
sourceCompressionTaskOut_(sourceCompressionTaskOut)
{ }
~AutoInitializeSourceObject() {
if (sourceObjectOut_)
*sourceObjectOut_ = compiler_.sourceObjectPtr();
if (sourceCompressionTaskOut_)
*sourceCompressionTaskOut_ = compiler_.sourceCompressionTask();
}
};
@ -597,13 +617,12 @@ JSScript*
frontend::CompileGlobalScript(JSContext* cx, LifoAlloc& alloc, ScopeKind scopeKind,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct,
ScriptSourceObject** sourceObjectOut)
ScriptSourceObject** sourceObjectOut,
SourceCompressionTask** sourceCompressionTaskOut)
{
MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
BytecodeCompiler compiler(cx, alloc, options, srcBuf, /* enclosingScope = */ nullptr);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
compiler.maybeSetSourceCompressor(extraSct);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut, sourceCompressionTaskOut);
return compiler.compileGlobalScript(scopeKind);
}
@ -612,19 +631,19 @@ frontend::CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
HandleObject environment, HandleScope enclosingScope,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct,
ScriptSourceObject** sourceObjectOut)
ScriptSourceObject** sourceObjectOut,
SourceCompressionTask** sourceCompressionTaskOut)
{
BytecodeCompiler compiler(cx, alloc, options, srcBuf, enclosingScope);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
compiler.maybeSetSourceCompressor(extraSct);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut, sourceCompressionTaskOut);
return compiler.compileEvalScript(environment, enclosingScope);
}
ModuleObject*
frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& optionsInput,
SourceBufferHolder& srcBuf, LifoAlloc& alloc,
ScriptSourceObject** sourceObjectOut /* = nullptr */)
ScriptSourceObject** sourceObjectOut,
SourceCompressionTask** sourceCompressionTaskOut)
{
MOZ_ASSERT(srcBuf.get());
MOZ_ASSERT_IF(sourceObjectOut, *sourceObjectOut == nullptr);
@ -636,7 +655,7 @@ frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& optionsInpu
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
BytecodeCompiler compiler(cx, alloc, options, srcBuf, emptyGlobalScope);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut, sourceCompressionTaskOut);
return compiler.compileModule();
}

View File

@ -23,7 +23,7 @@ class LazyScript;
class LifoAlloc;
class ModuleObject;
class ScriptSourceObject;
struct SourceCompressionTask;
class SourceCompressionTask;
namespace frontend {
@ -35,16 +35,16 @@ JSScript*
CompileGlobalScript(JSContext* cx, LifoAlloc& alloc, ScopeKind scopeKind,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct = nullptr,
ScriptSourceObject** sourceObjectOut = nullptr);
ScriptSourceObject** sourceObjectOut = nullptr,
SourceCompressionTask** sourceCompressionTaskOut = nullptr);
JSScript*
CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
HandleObject scopeChain, HandleScope enclosingScope,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct = nullptr,
ScriptSourceObject** sourceObjectOut = nullptr);
ScriptSourceObject** sourceObjectOut = nullptr,
SourceCompressionTask** sourceCompressionTaskOut = nullptr);
ModuleObject*
CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
@ -53,7 +53,8 @@ CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
ModuleObject*
CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, LifoAlloc& alloc,
ScriptSourceObject** sourceObjectOut = nullptr);
ScriptSourceObject** sourceObjectOut = nullptr,
SourceCompressionTask** sourceCompressionTaskOut = nullptr);
MOZ_MUST_USE bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);

View File

@ -3593,7 +3593,7 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
TokenStream& ts = tokenStream();
ErrorMetadata metadata;
if (ts.computeErrorMetadata(&metadata, pos.begin))
ts.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
va_end(args);
}

View File

@ -52,10 +52,6 @@ class FullParseHandler
size_t lazyInnerFunctionIndex;
size_t lazyClosedOverBindingIndex;
const TokenPos& pos() {
return tokenStream.currentToken().pos;
}
public:
/*
@ -247,15 +243,9 @@ class FullParseHandler
return new_<UnaryNode>(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, pos, kid);
}
ParseNode* newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) {
return new_<BinaryNode>(kind, op, pos(), (ParseNode*) nullptr, (ParseNode*) nullptr);
}
ParseNode* newBinary(ParseNodeKind kind, ParseNode* left,
JSOp op = JSOP_NOP) {
return new_<BinaryNode>(kind, op, left->pn_pos, left, (ParseNode*) nullptr);
}
ParseNode* newBinary(ParseNodeKind kind, ParseNode* left, ParseNode* right,
JSOp op = JSOP_NOP) {
JSOp op = JSOP_NOP)
{
TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
return new_<BinaryNode>(kind, op, pos, left, right);
}
@ -317,12 +307,12 @@ class FullParseHandler
literal->append(element);
}
ParseNode* newCall() {
return newList(PNK_CALL, JSOP_CALL);
ParseNode* newCall(const TokenPos& pos) {
return newList(PNK_CALL, pos, JSOP_CALL);
}
ParseNode* newTaggedTemplate() {
return newList(PNK_TAGGED_TEMPLATE, JSOP_CALL);
ParseNode* newTaggedTemplate(const TokenPos& pos) {
return newList(PNK_TAGGED_TEMPLATE, pos, JSOP_CALL);
}
ParseNode* newObjectLiteral(uint32_t begin) {
@ -634,6 +624,10 @@ class FullParseHandler
return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr);
}
ParseNode* newExpressionBody(ParseNode* expr) {
return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, expr->pn_pos, expr);
}
ParseNode* newWithStatement(uint32_t begin, ParseNode* expr, ParseNode* body) {
return new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end),
expr, body);
@ -679,16 +673,16 @@ class FullParseHandler
pn->setDirectRHSAnonFunction(true);
}
ParseNode* newFunctionStatement() {
return new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, pos());
ParseNode* newFunctionStatement(const TokenPos& pos) {
return new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, pos);
}
ParseNode* newFunctionExpression() {
return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA, pos());
ParseNode* newFunctionExpression(const TokenPos& pos) {
return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA, pos);
}
ParseNode* newArrowFunction() {
return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos());
ParseNode* newArrowFunction(const TokenPos& pos) {
return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos);
}
bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) {
@ -716,14 +710,23 @@ class FullParseHandler
fn->pn_body->append(body);
}
ParseNode* newModule() {
return new_<CodeNode>(PNK_MODULE, JSOP_NOP, pos());
ParseNode* newModule(const TokenPos& pos) {
return new_<CodeNode>(PNK_MODULE, JSOP_NOP, pos);
}
ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
return new_<LexicalScopeNode>(bindings, body);
}
Node newNewExpression(uint32_t begin, ParseNode* ctor) {
ParseNode* newExpr = newList(PNK_NEW, begin, JSOP_NEW);
if (!newExpr)
return nullptr;
addList(newExpr, ctor);
return newExpr;
}
ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs,
JSOp op)
{
@ -802,29 +805,28 @@ class FullParseHandler
return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST;
}
ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
ParseNode* newList(ParseNodeKind kind, const TokenPos& pos, JSOp op = JSOP_NOP) {
MOZ_ASSERT(!isDeclarationKind(kind));
return new_<ListNode>(kind, op, pos());
return new_<ListNode>(kind, op, pos);
}
private:
ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
MOZ_ASSERT(!isDeclarationKind(kind));
return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
return newList(kind, TokenPos(begin, begin + 1), op);
}
template<typename T>
ParseNode* newList(ParseNodeKind kind, const T& begin, JSOp op = JSOP_NOP) = delete;
public:
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(!isDeclarationKind(kind));
return new_<ListNode>(kind, op, kid);
}
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
ParseNode* newDeclarationList(ParseNodeKind kind, const TokenPos& pos, JSOp op) {
MOZ_ASSERT(isDeclarationKind(kind));
return new_<ListNode>(kind, op, pos());
}
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(isDeclarationKind(kind));
return new_<ListNode>(kind, op, kid);
return new_<ListNode>(kind, op, pos);
}
bool isDeclarationList(ParseNode* node) {
@ -837,8 +839,8 @@ class FullParseHandler
return decl->pn_head;
}
ParseNode* newCatchList() {
return new_<ListNode>(PNK_CATCHLIST, JSOP_NOP, pos());
ParseNode* newCatchList(const TokenPos& pos) {
return new_<ListNode>(PNK_CATCHLIST, JSOP_NOP, pos);
}
ParseNode* newCommaExpressionList(ParseNode* kid) {

View File

@ -596,7 +596,7 @@ ParserBase::error(unsigned errorNumber, ...)
ErrorMetadata metadata;
if (tokenStream.computeErrorMetadata(&metadata, pos().begin))
tokenStream.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(context, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
va_end(args);
}
@ -608,8 +608,10 @@ ParserBase::errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber,
va_start(args, errorNumber);
ErrorMetadata metadata;
if (tokenStream.computeErrorMetadata(&metadata, pos().begin))
tokenStream.compileError(Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber, args);
if (tokenStream.computeErrorMetadata(&metadata, pos().begin)) {
ReportCompileError(context, Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber,
args);
}
va_end(args);
}
@ -622,7 +624,7 @@ ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...)
ErrorMetadata metadata;
if (tokenStream.computeErrorMetadata(&metadata, offset))
tokenStream.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(context, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
va_end(args);
}
@ -635,8 +637,10 @@ ParserBase::errorWithNotesAt(UniquePtr<JSErrorNotes> notes, uint32_t offset,
va_start(args, errorNumber);
ErrorMetadata metadata;
if (tokenStream.computeErrorMetadata(&metadata, offset))
tokenStream.compileError(Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber, args);
if (tokenStream.computeErrorMetadata(&metadata, offset)) {
ReportCompileError(context, Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber,
args);
}
va_end(args);
}
@ -667,7 +671,7 @@ ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...)
if (result) {
result =
tokenStream.compileWarning(Move(metadata), nullptr, JSREPORT_WARNING, errorNumber,
args);
args);
}
va_end(args);
@ -729,7 +733,8 @@ ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumb
tokenStream.computeErrorMetadataNoOffset(&metadata);
if (kind == ParseError) {
tokenStream.compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(context, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber,
args);
MOZ_ASSERT(!result);
} else {
result =
@ -774,7 +779,6 @@ ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
const char16_t* chars, size_t length,
bool foldConstants,
UsedNameTracker& usedNames,
Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction)
: context(cx),
alloc(alloc),
@ -782,7 +786,6 @@ ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
traceListHead(nullptr),
pc(nullptr),
usedNames(usedNames),
sct(nullptr),
ss(nullptr),
keepAtoms(cx),
foldConstants(foldConstants),
@ -819,8 +822,7 @@ Parser<ParseHandler>::Parser(JSContext* cx, LifoAlloc& alloc,
UsedNameTracker& usedNames,
Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction)
: ParserBase(cx, alloc, options, chars, length, foldConstants, usedNames, syntaxParser,
lazyOuterFunction),
: ParserBase(cx, alloc, options, chars, length, foldConstants, usedNames, lazyOuterFunction),
AutoGCRooter(cx, PARSER),
handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction)
{
@ -864,9 +866,8 @@ Parser<FullParseHandler>::setAwaitIsKeyword(bool isKeyword)
parser->setAwaitIsKeyword(isKeyword);
}
template <typename ParseHandler>
ObjectBox*
Parser<ParseHandler>::newObjectBox(JSObject* obj)
ParserBase::newObjectBox(JSObject* obj)
{
MOZ_ASSERT(obj);
@ -1007,9 +1008,8 @@ ParserBase::isValidStrictBinding(PropertyName* name)
* Returns true if all parameter names are valid strict mode binding names and
* no duplicate parameter names are present.
*/
template <typename ParseHandler>
bool
Parser<ParseHandler>::hasValidSimpleStrictParameterNames()
ParserBase::hasValidSimpleStrictParameterNames()
{
MOZ_ASSERT(pc->isFunctionBox() && pc->functionBox()->hasSimpleParameterList());
@ -2203,7 +2203,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc)
if (!varScope.init(pc))
return nullptr;
Node mn = handler.newModule();
Node mn = handler.newModule(pos());
if (!mn)
return null();
@ -2514,11 +2514,11 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
tokenStream.ungetToken();
}
Node fn = handler.newFunctionStatement();
Node fn = handler.newFunctionStatement(pos());
if (!fn)
return null();
ParseNode* argsbody = handler.newList(PNK_PARAMSBODY);
ParseNode* argsbody = handler.newList(PNK_PARAMSBODY, pos());
if (!argsbody)
return null();
fn->pn_body = argsbody;
@ -2680,7 +2680,7 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
if (!kid)
return null();
pn = handler.newReturnStatement(kid, handler.getPosition(kid));
pn = handler.newExpressionBody(kid);
if (!pn)
return null();
@ -2737,11 +2737,10 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
return finishLexicalScope(pc->varScope(), pn);
}
template <typename ParseHandler>
JSFunction*
Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
HandleObject proto)
ParserBase::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
HandleObject proto)
{
MOZ_ASSERT_IF(kind == Statement, atom != nullptr);
@ -2982,7 +2981,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
funbox->setStart(tokenStream);
}
Node argsbody = handler.newList(PNK_PARAMSBODY);
Node argsbody = handler.newList(PNK_PARAMSBODY, pos());
if (!argsbody)
return false;
handler.setFunctionFormalParametersAndBody(funcpn, argsbody);
@ -3551,7 +3550,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
{
MOZ_ASSERT(checkOptionsCalled);
Node pn = handler.newFunctionStatement();
Node pn = handler.newFunctionStatement(pos());
if (!pn)
return null();
@ -3825,7 +3824,7 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
return null();
}
Node pn = handler.newFunctionStatement();
Node pn = handler.newFunctionStatement(pos());
if (!pn)
return null();
@ -3870,7 +3869,7 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo
tokenStream.ungetToken();
}
Node pn = handler.newFunctionExpression();
Node pn = handler.newFunctionExpression(pos());
if (!pn)
return null();
@ -4781,7 +4780,7 @@ Parser<ParseHandler>::declarationList(YieldHandling yieldHandling,
MOZ_CRASH("Unknown declaration kind");
}
Node decl = handler.newDeclarationList(kind, op);
Node decl = handler.newDeclarationList(kind, pos(), op);
if (!decl)
return null();
@ -4983,7 +4982,7 @@ Parser<FullParseHandler>::importDeclaration()
if (!tokenStream.getToken(&tt))
return null();
Node importSpecSet = handler.newList(PNK_IMPORT_SPEC_LIST);
Node importSpecSet = handler.newList(PNK_IMPORT_SPEC_LIST, pos());
if (!importSpecSet)
return null();
@ -5234,7 +5233,7 @@ Parser<ParseHandler>::exportBatch(uint32_t begin)
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_MUL));
Node kid = handler.newList(PNK_EXPORT_SPEC_LIST);
Node kid = handler.newList(PNK_EXPORT_SPEC_LIST, pos());
if (!kid)
return null();
@ -5285,7 +5284,7 @@ Parser<ParseHandler>::exportClause(uint32_t begin)
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
Node kid = handler.newList(PNK_EXPORT_SPEC_LIST);
Node kid = handler.newList(PNK_EXPORT_SPEC_LIST, pos());
if (!kid)
return null();
@ -6796,7 +6795,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!tokenStream.getToken(&tt))
return null();
if (tt == TOK_CATCH) {
catchList = handler.newCatchList();
catchList = handler.newCatchList(pos());
if (!catchList)
return null();
@ -8122,7 +8121,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
tokenStream.ungetToken();
}
Node pn = handler.newArrowFunction();
Node pn = handler.newArrowFunction(pos());
if (!pn)
return null();
@ -8418,7 +8417,7 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
{
Node genfn = handler.newFunctionExpression();
Node genfn = handler.newFunctionExpression(pos());
if (!genfn)
return null();
@ -8818,10 +8817,6 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
if (newTarget) {
lhs = newTarget;
} else {
lhs = handler.newList(PNK_NEW, newBegin, JSOP_NEW);
if (!lhs)
return null();
// Gotten by tryNewTarget
tt = tokenStream.currentToken().type;
Node ctorExpr = memberExpr(yieldHandling, TripledotProhibited, tt,
@ -8830,7 +8825,9 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
if (!ctorExpr)
return null();
handler.addList(lhs, ctorExpr);
lhs = handler.newNewExpression(newBegin, ctorExpr);
if (!lhs)
return null();
bool matched;
if (!tokenStream.matchToken(&matched, TOK_LP))
@ -8937,7 +8934,10 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
return null();
}
nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();
TokenPos nextMemberPos = pos();
nextMember = tt == TOK_LP
? handler.newCall(nextMemberPos)
: handler.newTaggedTemplate(nextMemberPos);
if (!nextMember)
return null();
@ -9169,7 +9169,7 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::stringLiteral()
{
return handler.newStringLiteral(stopStringCompression(), pos());
return handler.newStringLiteral(tokenStream.currentToken().atom(), pos());
}
template <typename ParseHandler>
@ -9181,7 +9181,7 @@ Parser<ParseHandler>::noSubstitutionTaggedTemplate()
return handler.newRawUndefinedLiteral(pos());
}
return handler.newTemplateStringLiteral(stopStringCompression(), pos());
return handler.newTemplateStringLiteral(tokenStream.currentToken().atom(), pos());
}
template <typename ParseHandler>
@ -9191,20 +9191,7 @@ Parser<ParseHandler>::noSubstitutionUntaggedTemplate()
if (!tokenStream.checkForInvalidTemplateEscapeError())
return null();
return handler.newTemplateStringLiteral(stopStringCompression(), pos());
}
template <typename ParseHandler>
JSAtom * Parser<ParseHandler>::stopStringCompression() {
JSAtom* atom = tokenStream.currentToken().atom();
// Large strings are fast to parse but slow to compress. Stop compression on
// them, so we don't wait for a long time for compression to finish at the
// end of compilation.
const size_t HUGE_STRING = 50000;
if (sct && sct->active() && atom->length() >= HUGE_STRING)
sct->abort();
return atom;
return handler.newTemplateStringLiteral(tokenStream.currentToken().atom(), pos());
}
template <typename ParseHandler>
@ -9776,7 +9763,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propT
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
Node pn = handler.newFunctionExpression();
Node pn = handler.newFunctionExpression(pos());
if (!pn)
return null();

View File

@ -770,9 +770,6 @@ class ParserBase : public StrictModeGetter
// For tracking used names in this parsing session.
UsedNameTracker& usedNames;
/* Compression token for aborting. */
SourceCompressionTask* sct;
ScriptSource* ss;
/* Root atoms and objects allocated for the parsed tree. */
@ -806,8 +803,7 @@ class ParserBase : public StrictModeGetter
ParserBase(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, bool foldConstants,
UsedNameTracker& usedNames, Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction);
UsedNameTracker& usedNames, LazyScript* lazyOuterFunction);
~ParserBase();
const char* getFilename() const { return tokenStream.getFilename(); }
@ -896,6 +892,47 @@ class ParserBase : public StrictModeGetter
bool warnOnceAboutExprClosure();
bool warnOnceAboutForEach();
bool allowsForEachIn() {
#if !JS_HAS_FOR_EACH_IN
return false;
#else
return options().forEachStatementOption && versionNumber() >= JSVERSION_1_6;
#endif
}
bool hasValidSimpleStrictParameterNames();
/*
* Create a new function object given a name (which is optional if this is
* a function expression).
*/
JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
HandleObject proto);
// A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
// Parser's state. Note: clients must still take care that any ParseContext
// that points into released ParseNodes is destroyed.
class Mark
{
friend class ParserBase;
LifoAlloc::Mark mark;
ObjectBox* traceListHead;
};
Mark mark() const {
Mark m;
m.mark = alloc.mark();
m.traceListHead = traceListHead;
return m;
}
void release(Mark m) {
alloc.release(m.mark);
traceListHead = m.traceListHead;
}
ObjectBox* newObjectBox(JSObject* obj);
protected:
enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
enum ForInitLocation { InForInit, NotInForInit };
@ -1037,26 +1074,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
bool checkOptions();
// A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
// Parser's state. Note: clients must still take care that any ParseContext
// that points into released ParseNodes is destroyed.
class Mark
{
friend class Parser;
LifoAlloc::Mark mark;
ObjectBox* traceListHead;
};
Mark mark() const {
Mark m;
m.mark = alloc.mark();
m.traceListHead = traceListHead;
return m;
}
void release(Mark m) {
alloc.release(m.mark);
traceListHead = m.traceListHead;
}
friend void js::frontend::TraceParser(JSTracer* trc, JS::AutoGCRooter* parser);
/*
@ -1064,31 +1081,16 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
*/
Node parse();
/*
* Allocate a new parsed object or function container from
* cx->tempLifoAlloc.
*/
ObjectBox* newObjectBox(JSObject* obj);
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
Directives directives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB);
/*
* Create a new function object given a name (which is optional if this is
* a function expression).
*/
JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
HandleObject proto);
void trace(JSTracer* trc);
private:
Parser* thisForCtor() { return this; }
JSAtom* stopStringCompression();
Node stringLiteral();
Node noSubstitutionTaggedTemplate();
Node noSubstitutionUntaggedTemplate();
@ -1407,14 +1409,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
bool matchLabel(YieldHandling yieldHandling, MutableHandle<PropertyName*> label);
bool allowsForEachIn() {
#if !JS_HAS_FOR_EACH_IN
return false;
#else
return options().forEachStatementOption && versionNumber() >= JSVERSION_1_6;
#endif
}
bool matchInOrOf(bool* isForInp, bool* isForOfp);
bool hasUsedFunctionSpecialName(HandlePropertyName name);
@ -1459,8 +1453,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
bool checkIncDecOperand(Node operand, uint32_t operandOffset);
bool checkStrictAssignment(Node lhs);
bool hasValidSimpleStrictParameterNames();
void reportMissingClosing(unsigned errorNumber, unsigned noteNumber, uint32_t openedPos);
void reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, TokenPos pos,

View File

@ -261,8 +261,6 @@ class SyntaxParseHandler
return NodeGeneric;
}
Node newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { return NodeGeneric; }
Node newBinary(ParseNodeKind kind, Node left, JSOp op = JSOP_NOP) { return NodeGeneric; }
Node newBinary(ParseNodeKind kind, Node left, Node right, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
@ -283,8 +281,8 @@ class SyntaxParseHandler
MOZ_MUST_USE bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
void addArrayElement(Node literal, Node element) { }
Node newCall() { return NodeFunctionCall; }
Node newTaggedTemplate() { return NodeGeneric; }
Node newCall(const TokenPos& pos) { return NodeFunctionCall; }
Node newTaggedTemplate(const TokenPos& pos) { return NodeGeneric; }
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
@ -336,6 +334,7 @@ class SyntaxParseHandler
Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
Node newReturnStatement(Node expr, const TokenPos& pos) { return NodeReturn; }
Node newExpressionBody(Node expr) { return NodeReturn; }
Node newWithStatement(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
Node newLabeledStatement(PropertyName* label, Node stmt, uint32_t begin) {
@ -362,9 +361,9 @@ class SyntaxParseHandler
void checkAndSetIsDirectRHSAnonFunction(Node pn) {}
Node newFunctionStatement() { return NodeFunctionDefinition; }
Node newFunctionExpression() { return NodeFunctionDefinition; }
Node newArrowFunction() { return NodeFunctionDefinition; }
Node newFunctionStatement(const TokenPos& pos) { return NodeFunctionDefinition; }
Node newFunctionExpression(const TokenPos& pos) { return NodeFunctionDefinition; }
Node newArrowFunction(const TokenPos& pos) { return NodeFunctionDefinition; }
bool setComprehensionLambdaBody(Node pn, Node body) { return true; }
void setFunctionFormalParametersAndBody(Node pn, Node kid) {}
@ -409,28 +408,32 @@ class SyntaxParseHandler
return tokenStream.currentToken().pos;
}
Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
Node newList(ParseNodeKind kind, const TokenPos& pos, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
MOZ_ASSERT(kind != PNK_LET);
MOZ_ASSERT(kind != PNK_CONST);
return NodeGeneric;
}
private:
Node newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
return newList(kind, op);
}
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
return newList(kind, op);
return newList(kind, TokenPos(begin, begin + 1), op);
}
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
template<typename T>
Node newList(ParseNodeKind kind, const T& begin, JSOp op = JSOP_NOP) = delete;
public:
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
return newList(kind, TokenPos(), op);
}
Node newDeclarationList(ParseNodeKind kind, const TokenPos& pos, JSOp op = JSOP_NOP) {
if (kind == PNK_VAR)
return NodeVarDeclaration;
MOZ_ASSERT(kind == PNK_LET || kind == PNK_CONST);
return NodeLexicalDeclaration;
}
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
return newDeclarationList(kind, op);
}
bool isDeclarationList(Node node) {
return node == NodeVarDeclaration || node == NodeLexicalDeclaration;
@ -456,8 +459,8 @@ class SyntaxParseHandler
return NodeUnparenthesizedName;
}
Node newCatchList() {
return newList(PNK_CATCHLIST, JSOP_NOP);
Node newCatchList(const TokenPos& pos) {
return newList(PNK_CATCHLIST, pos, JSOP_NOP);
}
Node newCommaExpressionList(Node kid) {
@ -474,6 +477,15 @@ class SyntaxParseHandler
list == NodeFunctionCall);
}
Node newNewExpression(uint32_t begin, Node ctor) {
Node newExpr = newList(PNK_NEW, begin, JSOP_NEW);
if (!newExpr)
return newExpr;
addList(newExpr, ctor);
return newExpr;
}
Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs, JSOp op) {
if (kind == PNK_ASSIGN)
return NodeUnparenthesizedAssignment;

View File

@ -305,7 +305,7 @@ TokenStream::SourceCoords::add(uint32_t lineNum, uint32_t lineStartOffset)
}
MOZ_ALWAYS_INLINE bool
TokenStream::SourceCoords::fill(const TokenStream::SourceCoords& other)
TokenStreamBase::SourceCoords::fill(const TokenStreamBase::SourceCoords& other)
{
MOZ_ASSERT(lineStartOffsets_.back() == MAX_PTR);
MOZ_ASSERT(other.lineStartOffsets_.back() == MAX_PTR);
@ -324,7 +324,7 @@ TokenStream::SourceCoords::fill(const TokenStream::SourceCoords& other)
}
MOZ_ALWAYS_INLINE uint32_t
TokenStream::SourceCoords::lineIndexOf(uint32_t offset) const
TokenStreamBase::SourceCoords::lineIndexOf(uint32_t offset) const
{
uint32_t iMin, iMax, iMid;
@ -375,14 +375,14 @@ TokenStream::SourceCoords::lineIndexOf(uint32_t offset) const
}
uint32_t
TokenStream::SourceCoords::lineNum(uint32_t offset) const
TokenStreamBase::SourceCoords::lineNum(uint32_t offset) const
{
uint32_t lineIndex = lineIndexOf(offset);
return lineIndexToNum(lineIndex);
}
uint32_t
TokenStream::SourceCoords::columnIndex(uint32_t offset) const
TokenStreamBase::SourceCoords::columnIndex(uint32_t offset) const
{
uint32_t lineIndex = lineIndexOf(offset);
uint32_t lineStartOffset = lineStartOffsets_[lineIndex];
@ -391,8 +391,8 @@ TokenStream::SourceCoords::columnIndex(uint32_t offset) const
}
void
TokenStream::SourceCoords::lineNumAndColumnIndex(uint32_t offset, uint32_t* lineNum,
uint32_t* columnIndex) const
TokenStreamBase::SourceCoords::lineNumAndColumnIndex(uint32_t offset, uint32_t* lineNum,
uint32_t* columnIndex) const
{
uint32_t lineIndex = lineIndexOf(offset);
*lineNum = lineIndexToNum(lineIndex);
@ -427,7 +427,7 @@ TokenStreamBase::TokenStreamBase(JSContext* cx, const ReadOnlyCompileOptions& op
}
TokenStream::TokenStream(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* base, size_t length, StrictModeGetter* smg)
const CharT* base, size_t length, StrictModeGetter* smg)
: TokenStreamBase(cx, options, smg),
userbuf(cx, base, length, options.column),
tokenbuf(cx)
@ -451,7 +451,7 @@ TokenStream::TokenStream(JSContext* cx, const ReadOnlyCompileOptions& options,
#endif
bool
TokenStream::checkOptions()
TokenStreamBase::checkOptions()
{
// Constrain starting columns to half of the range of a signed 32-bit value,
// to avoid overflow.
@ -604,7 +604,7 @@ TokenStream::peekChars(int n, char16_t* cp)
size_t
TokenStream::TokenBuf::findEOLMax(size_t start, size_t max)
{
const char16_t* p = rawCharPtrAt(start);
const CharT* p = rawCharPtrAt(start);
size_t n = 0;
while (true) {
@ -622,7 +622,7 @@ TokenStream::TokenBuf::findEOLMax(size_t start, size_t max)
bool
TokenStream::advance(size_t position)
{
const char16_t* end = userbuf.rawCharPtrAt(position);
const CharT* end = userbuf.rawCharPtrAt(position);
while (userbuf.addressOfNextRawChar() < end) {
int32_t c;
if (!getChar(&c))
@ -686,7 +686,7 @@ TokenStream::reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32
return false;
if (strictMode) {
compileError(Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber, args);
ReportCompileError(cx, Move(metadata), Move(notes), JSREPORT_ERROR, errorNumber, args);
return false;
}
@ -694,31 +694,23 @@ TokenStream::reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32
errorNumber, args);
}
void
CompileError::throwError(JSContext* cx)
bool
TokenStreamBase::compileWarning(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
unsigned flags, unsigned errorNumber, va_list args)
{
if (JSREPORT_IS_WARNING(flags)) {
CallWarningReporter(cx, this);
return;
if (options().werrorOption) {
flags &= ~JSREPORT_WARNING;
ReportCompileError(cx, Move(metadata), Move(notes), flags, errorNumber, args);
return false;
}
// If there's a runtime exception type associated with this error
// number, set that as the pending exception. For errors occuring at
// compile time, this is very likely to be a JSEXN_SYNTAXERR.
//
// If an exception is thrown but not caught, the JSREPORT_EXCEPTION
// flag will be set in report.flags. Proper behavior for an error
// reporter is to ignore a report with this flag for all but top-level
// compilation errors. The exception will remain pending, and so long
// as the non-top-level "load", "eval", or "compile" native function
// returns false, the top-level reporter will eventually receive the
// uncaught exception report.
ErrorToException(cx, this, nullptr, nullptr);
return ReportCompileWarning(cx, Move(metadata), Move(notes), flags, errorNumber, args);
}
void
TokenStream::computeErrorMetadataNoOffset(ErrorMetadata* err)
TokenStreamBase::computeErrorMetadataNoOffset(ErrorMetadata* err)
{
err->isMuted = mutedErrors;
err->filename = filename;
err->lineNumber = 0;
err->columnNumber = 0;
@ -734,6 +726,8 @@ TokenStream::computeErrorMetadata(ErrorMetadata* err, uint32_t offset)
return true;
}
err->isMuted = mutedErrors;
// If this TokenStream doesn't have location information, try to get it
// from the caller.
if (!filename && !cx->helperThread()) {
@ -816,82 +810,6 @@ TokenStream::computeLineOfContext(ErrorMetadata* err, uint32_t offset)
return true;
}
void
TokenStream::compileError(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, unsigned flags,
unsigned errorNumber, va_list args)
{
// On the active thread, report the error immediately. When compiling off
// thread, save the error so that the thread finishing the parse can report
// it later.
CompileError tempErr;
CompileError* err = &tempErr;
if (cx->helperThread() && !cx->addPendingCompileError(&err))
return;
err->notes = Move(notes);
err->flags = flags;
err->errorNumber = errorNumber;
err->isMuted = mutedErrors;
err->filename = metadata.filename;
err->lineno = metadata.lineNumber;
err->column = metadata.columnNumber;
if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext))
err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset);
if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber,
nullptr, ArgumentsAreLatin1, err, args))
{
return;
}
if (!cx->helperThread())
err->throwError(cx);
}
bool
TokenStream::compileWarning(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
unsigned flags, unsigned errorNumber, va_list args)
{
if (options().werrorOption) {
flags &= ~JSREPORT_WARNING;
compileError(Move(metadata), Move(notes), flags, errorNumber, args);
return false;
}
// On the active thread, report the error immediately. When compiling off
// thread, save the error so that the thread finishing the parse can report
// it later.
CompileError tempErr;
CompileError* err = &tempErr;
if (cx->helperThread() && !cx->addPendingCompileError(&err))
return false;
err->notes = Move(notes);
err->flags = flags;
err->errorNumber = errorNumber;
err->isMuted = mutedErrors;
err->filename = metadata.filename;
err->lineno = metadata.lineNumber;
err->column = metadata.columnNumber;
if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext))
err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset);
if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber,
nullptr, ArgumentsAreLatin1, err, args))
{
return false;
}
if (!cx->helperThread())
err->throwError(cx);
return true;
}
bool
TokenStream::reportStrictModeError(unsigned errorNumber, ...)
{
@ -911,13 +829,13 @@ TokenStream::reportError(unsigned errorNumber, ...)
ErrorMetadata metadata;
if (computeErrorMetadata(&metadata, currentToken().pos.begin))
compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
va_end(args);
}
void
TokenStream::reportErrorNoOffset(unsigned errorNumber, ...)
TokenStreamBase::reportErrorNoOffset(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
@ -925,7 +843,7 @@ TokenStream::reportErrorNoOffset(unsigned errorNumber, ...)
ErrorMetadata metadata;
computeErrorMetadataNoOffset(&metadata);
compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
va_end(args);
}
@ -968,7 +886,7 @@ TokenStream::error(unsigned errorNumber, ...)
ErrorMetadata metadata;
if (computeErrorMetadata(&metadata, currentToken().pos.begin))
compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
va_end(args);
}
@ -981,7 +899,7 @@ TokenStream::errorAt(uint32_t offset, unsigned errorNumber, ...)
ErrorMetadata metadata;
if (computeErrorMetadata(&metadata, offset))
compileError(Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
va_end(args);
}
@ -999,7 +917,7 @@ TokenStream::peekUnicodeEscape(uint32_t* codePoint)
return 0;
}
char16_t cp[3];
CharT cp[3];
uint32_t length;
c = getCharIgnoreEOL();
if (JS7_ISHEX(c) && peekChars(3, cp) &&
@ -1034,7 +952,7 @@ TokenStream::peekExtendedUnicodeEscape(uint32_t* codePoint)
c = getCharIgnoreEOL();
}
char16_t cp[6];
CharT cp[6];
size_t i = 0;
uint32_t code = 0;
while (JS7_ISHEX(c) && i < 6) {
@ -1084,12 +1002,15 @@ TokenStream::matchUnicodeEscapeIdent(uint32_t* codePoint)
// Helper function which returns true if the first length(q) characters in p are
// the same as the characters in q.
template<typename CharT>
static bool
CharsMatch(const char16_t* p, const char* q) {
CharsMatch(const CharT* p, const char* q)
{
while (*q) {
if (*p++ != *q++)
return false;
}
return true;
}
@ -1263,7 +1184,7 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart)
{
int32_t c;
uint32_t qc;
const char16_t* tmp = userbuf.addressOfNextRawChar();
const CharT* tmp = userbuf.addressOfNextRawChar();
userbuf.setAddressOfNextRawChar(identStart);
tokenbuf.clear();
@ -1387,10 +1308,10 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
uint32_t qc;
Token* tp;
FirstCharKind c1kind;
const char16_t* numStart;
const CharT* numStart;
bool hasExp;
DecimalPoint decimalPoint;
const char16_t* identStart;
const CharT* identStart;
bool hadUnicodeEscape;
// Check if in the middle of a template string. Have to get this out of
@ -1523,7 +1444,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
// Identifiers containing no Unicode escapes can be processed directly
// from userbuf. The rest must use the escapes converted via tokenbuf
// before atomizing.
const char16_t* chars;
const CharT* chars;
size_t length;
if (hadUnicodeEscape) {
if (!putIdentInTokenbuf(identStart))
@ -1612,7 +1533,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
if (!GetDecimalInteger(cx, numStart, userbuf.addressOfNextRawChar(), &dval))
goto error;
} else {
const char16_t* dummy;
const CharT* dummy;
if (!js_strtod(cx, numStart, userbuf.addressOfNextRawChar(), &dummy, &dval))
goto error;
}
@ -2151,7 +2072,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
break;
}
char16_t cp[4];
CharT cp[4];
if (peekChars(4, cp) &&
JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3]))
{
@ -2173,7 +2094,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
// Hexadecimal character specification.
case 'x': {
char16_t cp[2];
CharT cp[2];
if (peekChars(2, cp) && JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) {
c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
skipChars(2);

View File

@ -26,6 +26,7 @@
#include "frontend/TokenKind.h"
#include "js/UniquePtr.h"
#include "js/Vector.h"
#include "vm/ErrorReporting.h"
#include "vm/RegExpObject.h"
#include "vm/String.h"
@ -241,11 +242,6 @@ struct Token
}
};
class CompileError : public JSErrorReport {
public:
void throwError(JSContext* cx);
};
extern const char*
ReservedWordToCharZ(PropertyName* str);
@ -270,37 +266,6 @@ class StrictModeGetter {
virtual bool strictMode() = 0;
};
/**
* Metadata for a compilation error (or warning) at a particular offset, or at
* no offset (i.e. with respect to a script overall).
*/
struct ErrorMetadata
{
// The file/URL where the error occurred.
const char* filename;
// The line and column numbers where the error occurred. If the error
// is with respect to the entire script and not with respect to a
// particular location, these will both be zero.
uint32_t lineNumber;
uint32_t columnNumber;
// If the error occurs at a particular location, context surrounding the
// location of the error: the line that contained the error, or a small
// portion of it if the line is long.
//
// This information is provided on a best-effort basis: code populating
// ErrorMetadata instances isn't obligated to supply this.
UniqueTwoByteChars lineOfContext;
// If |lineOfContext| is non-null, its length.
size_t lineLength;
// If |lineOfContext| is non-null, the offset within it of the token that
// triggered the error.
size_t tokenOffset;
};
class TokenStreamBase
{
protected:
@ -329,6 +294,8 @@ class TokenStreamBase
JSVersion versionNumber() const { return VersionNumber(options().version); }
JSVersion versionWithFlags() const { return options().version; }
MOZ_MUST_USE bool checkOptions();
protected:
PropertyName* reservedWordToPropertyName(TokenKind tt) const;
@ -583,6 +550,15 @@ class TokenStreamBase
bool hasLookahead() const { return lookahead > 0; }
public:
MOZ_MUST_USE bool compileWarning(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
unsigned flags, unsigned errorNumber, va_list args);
void reportErrorNoOffset(unsigned errorNumber, ...);
// Compute error metadata for an error at no offset.
void computeErrorMetadataNoOffset(ErrorMetadata* err);
protected:
// Options used for parsing/tokenizing.
const ReadOnlyCompileOptions& options_;
@ -646,12 +622,11 @@ class TokenStreamBase
class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
{
public:
using CharBuffer = Vector<char16_t, 32>;
using CharT = char16_t;
using CharBuffer = Vector<CharT, 32>;
TokenStream(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* base, size_t length, StrictModeGetter* smg);
MOZ_MUST_USE bool checkOptions();
const CharT* base, size_t length, StrictModeGetter* smg);
const CharBuffer& getTokenbuf() const { return tokenbuf; }
@ -667,7 +642,6 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
// TokenStream-specific error reporters.
void reportError(unsigned errorNumber, ...);
void reportErrorNoOffset(unsigned errorNumber, ...);
// Report the given error at the current offset.
void error(unsigned errorNumber, ...);
@ -685,21 +659,12 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
MOZ_MUST_USE bool computeLineOfContext(ErrorMetadata* err, uint32_t offset);
public:
// Compute error metadata for an error at no offset.
void computeErrorMetadataNoOffset(ErrorMetadata* err);
// Compute error metadata for an error at the given offset.
MOZ_MUST_USE bool computeErrorMetadata(ErrorMetadata* err, uint32_t offset);
// General-purpose error reporters. You should avoid calling these
// directly, and instead use the more succinct alternatives (error(),
// warning(), &c.) in TokenStream, Parser, and BytecodeEmitter.
void compileError(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, unsigned flags,
unsigned errorNumber, va_list args);
MOZ_MUST_USE bool compileWarning(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes,
unsigned flags, unsigned errorNumber, va_list args);
bool reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
bool strictMode, unsigned errorNumber, va_list args);
bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset,
@ -708,8 +673,8 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
JSAtom* getRawTemplateStringAtom() {
MOZ_ASSERT(currentToken().type == TOK_TEMPLATE_HEAD ||
currentToken().type == TOK_NO_SUBS_TEMPLATE);
const char16_t* cur = userbuf.rawCharPtrAt(currentToken().pos.begin + 1);
const char16_t* end;
const CharT* cur = userbuf.rawCharPtrAt(currentToken().pos.begin + 1);
const CharT* end;
if (currentToken().type == TOK_TEMPLATE_HEAD) {
// Of the form |`...${| or |}...${|
end = userbuf.rawCharPtrAt(currentToken().pos.end - 2);
@ -720,7 +685,7 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
CharBuffer charbuf(cx);
while (cur < end) {
int32_t ch = *cur;
CharT ch = *cur;
if (ch == '\r') {
ch = '\n';
if ((cur + 1 < end) && (*(cur + 1) == '\n'))
@ -759,7 +724,7 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
}
static JSAtom* atomize(JSContext* cx, CharBuffer& cb);
MOZ_MUST_USE bool putIdentInTokenbuf(const char16_t* identStart);
MOZ_MUST_USE bool putIdentInTokenbuf(const CharT* identStart);
public:
// Advance to the next token. If the token stream encountered an error,
@ -914,7 +879,7 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
private:
Position(const Position&) = delete;
friend class TokenStream;
const char16_t* buf;
const CharT* buf;
Flags flags;
unsigned lineno;
size_t linebase;
@ -929,11 +894,11 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
void seek(const Position& pos);
MOZ_MUST_USE bool seek(const Position& pos, const TokenStream& other);
const char16_t* rawCharPtrAt(size_t offset) const {
const CharT* rawCharPtrAt(size_t offset) const {
return userbuf.rawCharPtrAt(offset);
}
const char16_t* rawLimit() const {
const CharT* rawLimit() const {
return userbuf.limit();
}
@ -950,7 +915,7 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
// begins, the offset of |buf[0]|.
class TokenBuf {
public:
TokenBuf(JSContext* cx, const char16_t* buf, size_t length, size_t startOffset)
TokenBuf(JSContext* cx, const CharT* buf, size_t length, size_t startOffset)
: base_(buf),
startOffset_(startOffset),
limit_(buf + length),
@ -973,25 +938,25 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
return startOffset_ + mozilla::PointerRangeSize(base_, ptr);
}
const char16_t* rawCharPtrAt(size_t offset) const {
const CharT* rawCharPtrAt(size_t offset) const {
MOZ_ASSERT(startOffset_ <= offset);
MOZ_ASSERT(offset - startOffset_ <= mozilla::PointerRangeSize(base_, limit_));
return base_ + (offset - startOffset_);
}
const char16_t* limit() const {
const CharT* limit() const {
return limit_;
}
char16_t getRawChar() {
CharT getRawChar() {
return *ptr++; // this will nullptr-crash if poisoned
}
char16_t peekRawChar() const {
CharT peekRawChar() const {
return *ptr; // this will nullptr-crash if poisoned
}
bool matchRawChar(char16_t c) {
bool matchRawChar(CharT c) {
if (*ptr == c) { // this will nullptr-crash if poisoned
ptr++;
return true;
@ -999,7 +964,7 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
return false;
}
bool matchRawCharBackwards(char16_t c) {
bool matchRawCharBackwards(CharT c) {
MOZ_ASSERT(ptr); // make sure it hasn't been poisoned
if (*(ptr - 1) == c) {
ptr--;
@ -1013,13 +978,13 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
ptr--;
}
const char16_t* addressOfNextRawChar(bool allowPoisoned = false) const {
const CharT* addressOfNextRawChar(bool allowPoisoned = false) const {
MOZ_ASSERT_IF(!allowPoisoned, ptr); // make sure it hasn't been poisoned
return ptr;
}
// Use this with caution!
void setAddressOfNextRawChar(const char16_t* a, bool allowPoisoned = false) {
void setAddressOfNextRawChar(const CharT* a, bool allowPoisoned = false) {
MOZ_ASSERT_IF(!allowPoisoned, a);
ptr = a;
}
@ -1040,10 +1005,10 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
size_t findEOLMax(size_t start, size_t max);
private:
const char16_t* base_; // base of buffer
const CharT* base_; // base of buffer
uint32_t startOffset_; // offset of base_[0]
const char16_t* limit_; // limit for quick bounds check
const char16_t* ptr; // next char to get
const CharT* limit_; // limit for quick bounds check
const CharT* ptr; // next char to get
};
MOZ_MUST_USE bool getTokenInternal(TokenKind* ttp, Modifier modifier);
@ -1065,13 +1030,13 @@ class MOZ_STACK_CLASS TokenStream final : public TokenStreamBase
uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
bool matchUnicodeEscapeIdent(uint32_t* codePoint);
bool matchTrailForLeadSurrogate(char16_t lead, char16_t* trail, uint32_t* codePoint);
bool peekChars(int n, char16_t* cp);
bool peekChars(int n, CharT* cp);
MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated);
MOZ_MUST_USE bool getDirective(bool isMultiline, bool shouldWarnDeprecated,
const char* directive, uint8_t directiveLength,
const char* errorMsgPragma,
UniquePtr<char16_t[], JS::FreePolicy>* destination);
UniquePtr<CharT[], JS::FreePolicy>* destination);
MOZ_MUST_USE bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated);
MOZ_MUST_USE bool getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated);

View File

@ -134,13 +134,6 @@ js::Nursery::Nursery(JSRuntime* rt)
bool
js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGC& lock)
{
/* maxNurseryBytes parameter is rounded down to a multiple of chunk size. */
maxNurseryChunks_ = maxNurseryBytes >> ChunkShift;
/* If no chunks are specified then the nursery is permanently disabled. */
if (maxNurseryChunks_ == 0)
return true;
if (!mallocedBuffers.init())
return false;
@ -148,6 +141,13 @@ js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGC& lock)
if (!freeMallocedBuffersTask || !freeMallocedBuffersTask->init())
return false;
/* maxNurseryBytes parameter is rounded down to a multiple of chunk size. */
maxNurseryChunks_ = maxNurseryBytes >> ChunkShift;
/* If no chunks are specified then the nursery is permanently disabled. */
if (maxNurseryChunks_ == 0)
return true;
AutoMaybeStartBackgroundAllocation maybeBgAlloc;
updateNumChunksLocked(1, maybeBgAlloc, lock);
if (numChunks() == 0)

View File

@ -67,7 +67,7 @@ using namespace js::jit;
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
Mode mode, int registers_to_save)
: RegExpMacroAssembler(*alloc, shared, registers_to_save),
: RegExpMacroAssembler(cx, *alloc, shared, registers_to_save),
cx(cx), mode_(mode)
{
// Find physical registers for each compiler register.

View File

@ -1808,7 +1808,7 @@ irregexp::CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompile
native_assembler.emplace(cx, &alloc, shared, mode, (data->capture_count + 1) * 2);
assembler = native_assembler.ptr();
} else {
interpreted_assembler.emplace(&alloc, shared, (data->capture_count + 1) * 2);
interpreted_assembler.emplace(cx, &alloc, shared, (data->capture_count + 1) * 2);
assembler = interpreted_assembler.ptr();
}

View File

@ -97,9 +97,10 @@ irregexp::CaseInsensitiveCompareUCStrings(const char16_t* substring1,
const char16_t* substring2,
size_t byteLength);
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(LifoAlloc* alloc, RegExpShared* shared,
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc,
RegExpShared* shared,
size_t numSavedRegisters)
: RegExpMacroAssembler(*alloc, shared, numSavedRegisters),
: RegExpMacroAssembler(cx, *alloc, shared, numSavedRegisters),
pc_(0),
advance_current_start_(0),
advance_current_offset_(0),

View File

@ -41,13 +41,14 @@ namespace irregexp {
class MOZ_STACK_CLASS RegExpMacroAssembler
{
public:
RegExpMacroAssembler(LifoAlloc& alloc, RegExpShared* shared, size_t numSavedRegisters)
RegExpMacroAssembler(JSContext* cx, LifoAlloc& alloc, RegExpShared* shared,
size_t numSavedRegisters)
: slow_safe_compiler_(false),
global_mode_(NOT_GLOBAL),
alloc_(alloc),
num_registers_(numSavedRegisters),
num_saved_registers_(numSavedRegisters),
shared(shared)
shared(cx, shared)
{}
enum StackCheckFlag {
@ -215,7 +216,7 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
}
public:
RegExpShared* shared;
RootedRegExpShared shared;
};
template <typename CharT>
@ -230,7 +231,8 @@ CaseInsensitiveCompareUCStrings(const CharT* substring1, const CharT* substring2
class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler final : public RegExpMacroAssembler
{
public:
InterpretedRegExpMacroAssembler(LifoAlloc* alloc, RegExpShared* shared, size_t numSavedRegisters);
InterpretedRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
size_t numSavedRegisters);
~InterpretedRegExpMacroAssembler();
// Inherited virtual methods.

View File

@ -246,6 +246,22 @@ BaselineCacheIRCompiler::emitGuardGroup()
return true;
}
bool
BaselineCacheIRCompiler::emitGuardGroupHasUnanalyzedNewScript()
{
Address addr(stubAddress(reader.stubOffset()));
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.loadPtr(addr, scratch1);
masm.guardGroupHasUnanalyzedNewScript(scratch1, scratch2, failure->label());
return true;
}
bool
BaselineCacheIRCompiler::emitGuardProto()
{

View File

@ -1021,6 +1021,11 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
ICStubEngine::Baseline, frame->script(),
stub, &attached);
if (newStub) {
if (gen.shouldNotePreliminaryObjectStub())
newStub->toCacheIR_Updated()->notePreliminaryObject();
else if (gen.shouldUnlinkPreliminaryObjectStubs())
StripPreliminaryObjectStubs(cx, stub);
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
SetUpdateStubData(newStub->toCacheIR_Updated(), gen.typeCheckInfo());
return true;
@ -1589,6 +1594,11 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
ICStubEngine::Baseline, frame->script(),
stub, &attached);
if (newStub) {
if (gen.shouldNotePreliminaryObjectStub())
newStub->toCacheIR_Updated()->notePreliminaryObject();
else if (gen.shouldUnlinkPreliminaryObjectStubs())
StripPreliminaryObjectStubs(cx, stub);
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
SetUpdateStubData(newStub->toCacheIR_Updated(), gen.typeCheckInfo());
}

View File

@ -3143,19 +3143,24 @@ SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape
}
}
// Don't attach if we are adding a property to an object which the new
// script properties analysis hasn't been performed for yet, as there
// may be a shape change required here afterwards.
if (oldGroup->newScript() && !oldGroup->newScript()->analyzed()) {
*isTemporarilyUnoptimizable_ = true;
return false;
}
ObjOperandId objId = writer.guardIsObject(objValId);
maybeEmitIdGuard(id);
writer.guardGroup(objId, oldGroup);
// If we are adding a property to an object for which the new script
// properties analysis hasn't been performed yet, make sure the stub fails
// after we run the analysis as a group change may be required here. The
// group change is not required for correctness but improves type
// information elsewhere.
if (oldGroup->newScript() && !oldGroup->newScript()->analyzed()) {
writer.guardGroupHasUnanalyzedNewScript(oldGroup);
MOZ_ASSERT(IsPreliminaryObject(obj));
preliminaryObjectAction_ = PreliminaryObjectAction::NotePreliminary;
} else {
preliminaryObjectAction_ = PreliminaryObjectAction::Unlink;
}
// Shape guard the holder.
ObjOperandId holderId = objId;
if (!obj->isNative()) {

View File

@ -176,6 +176,7 @@ extern const char* CacheKindNames[];
_(GuardAndLoadUnboxedExpando) \
_(GuardAndGetIndexFromString) \
_(GuardHasGetterSetter) \
_(GuardGroupHasUnanalyzedNewScript) \
_(LoadObject) \
_(LoadProto) \
_(LoadEnclosingEnvironment) \
@ -544,6 +545,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::GuardHasGetterSetter, obj);
addStubField(uintptr_t(shape), StubField::Type::Shape);
}
void guardGroupHasUnanalyzedNewScript(ObjectGroup* group) {
writeOp(CacheOp::GuardGroupHasUnanalyzedNewScript);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
}
void loadFrameCalleeResult() {
writeOp(CacheOp::LoadFrameCalleeResult);

View File

@ -255,7 +255,7 @@ CacheRegisterAllocator::defineValueRegister(MacroAssembler& masm, ValOperandId v
}
void
CacheRegisterAllocator::freeDeadOperandRegisters()
CacheRegisterAllocator::freeDeadOperandLocations(MacroAssembler& masm)
{
// See if any operands are dead so we can reuse their registers. Note that
// we skip the input operands, as those are also used by failure paths, and
@ -272,9 +272,13 @@ CacheRegisterAllocator::freeDeadOperandRegisters()
case OperandLocation::ValueReg:
availableRegs_.add(loc.valueReg());
break;
case OperandLocation::Uninitialized:
case OperandLocation::PayloadStack:
masm.propagateOOM(freePayloadSlots_.append(loc.payloadStack()));
break;
case OperandLocation::ValueStack:
masm.propagateOOM(freeValueSlots_.append(loc.valueStack()));
break;
case OperandLocation::Uninitialized:
case OperandLocation::BaselineFrame:
case OperandLocation::Constant:
case OperandLocation::DoubleReg:
@ -297,13 +301,15 @@ CacheRegisterAllocator::discardStack(MacroAssembler& masm)
masm.addToStackPtr(Imm32(stackPushed_));
stackPushed_ = 0;
}
freePayloadSlots_.clear();
freeValueSlots_.clear();
}
Register
CacheRegisterAllocator::allocateRegister(MacroAssembler& masm)
{
if (availableRegs_.empty())
freeDeadOperandRegisters();
freeDeadOperandLocations(masm);
if (availableRegs_.empty()) {
// Still no registers available, try to spill unused operands to
@ -356,7 +362,7 @@ CacheRegisterAllocator::allocateFixedRegister(MacroAssembler& masm, Register reg
// still available.
MOZ_ASSERT(!currentOpRegs_.has(reg), "Register is in use");
freeDeadOperandRegisters();
freeDeadOperandLocations(masm);
if (availableRegs_.has(reg)) {
availableRegs_.take(reg);
@ -562,6 +568,14 @@ CacheRegisterAllocator::spillOperandToStack(MacroAssembler& masm, OperandLocatio
MOZ_ASSERT(loc >= operandLocations_.begin() && loc < operandLocations_.end());
if (loc->kind() == OperandLocation::ValueReg) {
if (!freeValueSlots_.empty()) {
uint32_t stackPos = freeValueSlots_.popCopy();
MOZ_ASSERT(stackPos <= stackPushed_);
masm.storeValue(loc->valueReg(), Address(masm.getStackPointer(),
stackPushed_ - stackPos));
loc->setValueStack(stackPos);
return;
}
stackPushed_ += sizeof(js::Value);
masm.pushValue(loc->valueReg());
loc->setValueStack(stackPushed_);
@ -570,6 +584,14 @@ CacheRegisterAllocator::spillOperandToStack(MacroAssembler& masm, OperandLocatio
MOZ_ASSERT(loc->kind() == OperandLocation::PayloadReg);
if (!freePayloadSlots_.empty()) {
uint32_t stackPos = freePayloadSlots_.popCopy();
MOZ_ASSERT(stackPos <= stackPushed_);
masm.storePtr(loc->payloadReg(), Address(masm.getStackPointer(),
stackPushed_ - stackPos));
loc->setPayloadStack(stackPos, loc->payloadType());
return;
}
stackPushed_ += sizeof(uintptr_t);
masm.push(loc->payloadReg());
loc->setPayloadStack(stackPushed_, loc->payloadType());
@ -617,6 +639,7 @@ CacheRegisterAllocator::popPayload(MacroAssembler& masm, OperandLocation* loc, R
} else {
MOZ_ASSERT(loc->payloadStack() < stackPushed_);
masm.loadPtr(Address(masm.getStackPointer(), stackPushed_ - loc->payloadStack()), dest);
masm.propagateOOM(freePayloadSlots_.append(loc->payloadStack()));
}
loc->setPayloadReg(dest, loc->payloadType());
@ -636,6 +659,7 @@ CacheRegisterAllocator::popValue(MacroAssembler& masm, OperandLocation* loc, Val
} else {
MOZ_ASSERT(loc->valueStack() < stackPushed_);
masm.loadValue(Address(masm.getStackPointer(), stackPushed_ - loc->valueStack()), dest);
masm.propagateOOM(freeValueSlots_.append(loc->valueStack()));
}
loc->setValueReg(dest);

View File

@ -252,6 +252,10 @@ class MOZ_RAII CacheRegisterAllocator
// The current location of each operand.
Vector<OperandLocation, 8, SystemAllocPolicy> operandLocations_;
// Free lists for value- and payload-slots on stack
Vector<uint32_t, 2, SystemAllocPolicy> freeValueSlots_;
Vector<uint32_t, 2, SystemAllocPolicy> freePayloadSlots_;
// The registers allocated while emitting the current CacheIR op.
// This prevents us from allocating a register and then immediately
// clobbering it for something else, while we're still holding on to it.
@ -280,7 +284,7 @@ class MOZ_RAII CacheRegisterAllocator
CacheRegisterAllocator(const CacheRegisterAllocator&) = delete;
CacheRegisterAllocator& operator=(const CacheRegisterAllocator&) = delete;
void freeDeadOperandRegisters();
void freeDeadOperandLocations(MacroAssembler& masm);
void spillOperandToStack(MacroAssembler& masm, OperandLocation* loc);
void spillOperandToStackOrRegister(MacroAssembler& masm, OperandLocation* loc);

View File

@ -192,7 +192,7 @@ CacheRegisterAllocator::saveIonLiveRegisters(MacroAssembler& masm, LiveRegisterS
// work. Try to keep it simple by taking one small step at a time.
// Step 1. Discard any dead operands so we can reuse their registers.
freeDeadOperandRegisters();
freeDeadOperandLocations(masm);
// Step 2. Figure out the size of our live regs.
size_t sizeOfLiveRegsInBytes =
@ -292,6 +292,8 @@ CacheRegisterAllocator::saveIonLiveRegisters(MacroAssembler& masm, LiveRegisterS
}
masm.PushRegsInMask(liveRegs);
}
freePayloadSlots_.clear();
freeValueSlots_.clear();
MOZ_ASSERT(masm.framePushed() == ionScript->frameSize() + sizeOfLiveRegsInBytes);
@ -535,6 +537,22 @@ IonCacheIRCompiler::emitGuardGroup()
return true;
}
bool
IonCacheIRCompiler::emitGuardGroupHasUnanalyzedNewScript()
{
ObjectGroup* group = groupStubField(reader.stubOffset());
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
masm.movePtr(ImmGCPtr(group), scratch1);
masm.guardGroupHasUnanalyzedNewScript(scratch1, scratch2, failure->label());
return true;
}
bool
IonCacheIRCompiler::emitGuardProto()
{

View File

@ -2272,6 +2272,22 @@ MTypeBarrier::congruentTo(const MDefinition* def) const
return congruentIfOperandsEqual(other);
}
MDefinition*
MTypeBarrier::foldsTo(TempAllocator& alloc)
{
MIRType type = resultTypeSet()->getKnownMIRType();
if (type == MIRType::Value || type == MIRType::Object)
return this;
if (!input()->isConstant())
return this;
if (input()->type() != type)
return this;
return input();
}
#ifdef DEBUG
void
MPhi::assertLoopPhi() const

View File

@ -12825,6 +12825,7 @@ class MTypeBarrier
BarrierKind barrierKind() const {
return barrierKind_;
}
MDefinition* foldsTo(TempAllocator& alloc) override;
bool alwaysBails() const {
// If mirtype of input doesn't agree with mirtype of barrier,

Some files were not shown because too many files have changed in this diff Show More