mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
commit
d0a0ae30d5
@ -197,7 +197,7 @@ def interfaces(iface):
|
||||
interfaces = []
|
||||
while iface.base:
|
||||
interfaces.append(iface)
|
||||
iface = iface.idl.getName(iface.base, iface.location)
|
||||
iface = iface.idl.getName(xpidl.TypeId(iface.base), iface.location)
|
||||
interfaces.append(iface)
|
||||
interfaces.reverse()
|
||||
return interfaces
|
||||
|
@ -46,6 +46,12 @@ let whitelist = [
|
||||
{sourceName: /(?:res|gre-resources)\/forms\.css$/i,
|
||||
errorMessage: /Unknown property.*overflow-clip-box/i,
|
||||
isFromDevTools: false},
|
||||
// The '-moz-menulist-button' value is only supported in chrome and UA sheets
|
||||
// but forms.css is loaded as a document sheet by this test.
|
||||
// Maybe bug 1261237 will fix this?
|
||||
{sourceName: /(?:res|gre-resources)\/forms\.css$/i,
|
||||
errorMessage: /Error in parsing value for \u2018-moz-appearance\u2019/iu,
|
||||
isFromDevTools: false},
|
||||
// These variables are declared somewhere else, and error when we load the
|
||||
// files directly. They're all marked intermittent because their appearance
|
||||
// in the error console seems to not be consistent.
|
||||
|
@ -66,30 +66,6 @@ function promiseNewLocationAndHistoryEntryReplaced(browser, snippet) {
|
||||
});
|
||||
}
|
||||
|
||||
function promiseHistoryEntryReplacedNonRemote(browser) {
|
||||
let {listeners} = promiseHistoryEntryReplacedNonRemote;
|
||||
|
||||
return new Promise(resolve => {
|
||||
let shistory = browser.webNavigation.sessionHistory.legacySHistory;
|
||||
|
||||
let listener = {
|
||||
OnHistoryReplaceEntry() {
|
||||
shistory.removeSHistoryListener(this);
|
||||
executeSoon(resolve);
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsISHistoryListener,
|
||||
Ci.nsISupportsWeakReference
|
||||
])
|
||||
};
|
||||
|
||||
shistory.addSHistoryListener(listener);
|
||||
listeners.set(browser, listener);
|
||||
});
|
||||
}
|
||||
promiseHistoryEntryReplacedNonRemote.listeners = new WeakMap();
|
||||
|
||||
add_task(async function dont_save_empty_tabs() {
|
||||
let {tab, r} = await createTabWithRandomValue("about:blank");
|
||||
|
||||
@ -168,8 +144,10 @@ add_task(async function save_worthy_tabs_nonremote_final() {
|
||||
await BrowserTestUtils.loadURI(browser, "about:robots");
|
||||
ok(!browser.isRemoteBrowser, "browser is not remote anymore");
|
||||
|
||||
// Wait until the new entry replaces about:blank.
|
||||
await promiseHistoryEntryReplacedNonRemote(browser);
|
||||
// Switching remoteness caused a SessionRestore to begin, moving over history
|
||||
// and initiating the load in the target process. Wait for the full restore
|
||||
// and load to complete before trying to close the tab.
|
||||
await promiseTabRestored(tab);
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTabAndSessionState(tab);
|
||||
|
@ -196,6 +196,7 @@ exports.CSS_PROPERTIES = {
|
||||
"-moz-mac-vibrancy-light",
|
||||
"-moz-mac-vibrant-titlebar-dark",
|
||||
"-moz-mac-vibrant-titlebar-light",
|
||||
"-moz-menulist-button",
|
||||
"-moz-win-borderless-glass",
|
||||
"-moz-win-browsertabbar-toolbox",
|
||||
"-moz-win-communications-toolbox",
|
||||
|
@ -60,10 +60,12 @@ function windowLoaded()
|
||||
ok(succeeded, "Waiting for error page succeeded");
|
||||
/* 3. now, while we are on the error page, navigate back */
|
||||
try {
|
||||
SpecialPowers.wrap(w).back();
|
||||
// We need the SpecialPowers bit, because this is a cross-origin window
|
||||
// and we normally can't touch .history on those.
|
||||
SpecialPowers.wrap(w).history.back();
|
||||
}
|
||||
catch(ex) {
|
||||
ok(false, "w.back() threw " + ex);
|
||||
ok(false, "w.history.back() threw " + ex);
|
||||
}
|
||||
|
||||
pollForPage(false, function(succeeded) {
|
||||
|
@ -92,7 +92,7 @@ function* test()
|
||||
// Step 5 - Go back. This should result in another onload (because the file is
|
||||
// not in bfcache) and should be the fourth time we've requested the sjs file.
|
||||
checkPopupLoadCount();
|
||||
SpecialPowers.wrap(popup).back();
|
||||
popup.history.back();
|
||||
yield undefined;
|
||||
|
||||
// This is the check which was failing before we fixed the bug.
|
||||
@ -111,7 +111,7 @@ function* test()
|
||||
popup.location = 'file_bug669671.sjs?navigated-2';
|
||||
yield undefined;
|
||||
checkPopupLoadCount();
|
||||
SpecialPowers.wrap(popup).back();
|
||||
popup.history.back();
|
||||
yield undefined;
|
||||
checkPopupLoadCount();
|
||||
popup.close();
|
||||
@ -125,7 +125,7 @@ function* test()
|
||||
popup.location = 'file_bug669671.sjs?navigated-3';
|
||||
yield undefined;
|
||||
checkPopupLoadCount();
|
||||
SpecialPowers.wrap(popup).back();
|
||||
popup.history.back();
|
||||
yield undefined;
|
||||
is(popup.document.body.innerHTML, initialCount + '',
|
||||
'Load count (should be cached)');
|
||||
|
@ -926,43 +926,33 @@ nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter *aOuterWindow)
|
||||
// Initialize the PRCList (this).
|
||||
PR_INIT_CLIST(this);
|
||||
|
||||
if (aOuterWindow) {
|
||||
// |this| is an inner window, add this inner window to the outer
|
||||
// window list of inners.
|
||||
PR_INSERT_AFTER(this, aOuterWindow);
|
||||
// add this inner window to the outer window list of inners.
|
||||
PR_INSERT_AFTER(this, aOuterWindow);
|
||||
|
||||
mTimeoutManager =
|
||||
MakeUnique<mozilla::dom::TimeoutManager>(*nsGlobalWindowInner::Cast(AsInner()));
|
||||
mTimeoutManager = MakeUnique<dom::TimeoutManager>(*this);
|
||||
|
||||
mObserver = new nsGlobalWindowObserver(this);
|
||||
if (mObserver) {
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
// Watch for online/offline status changes so we can fire events. Use
|
||||
// a strong reference.
|
||||
os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
|
||||
false);
|
||||
mObserver = new nsGlobalWindowObserver(this);
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
// Watch for online/offline status changes so we can fire events. Use
|
||||
// a strong reference.
|
||||
os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
|
||||
false);
|
||||
|
||||
os->AddObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC, false);
|
||||
os->AddObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC, false);
|
||||
|
||||
if (aOuterWindow->IsTopLevelWindow()) {
|
||||
os->AddObserver(mObserver, "clear-site-data-reload-needed", false);
|
||||
}
|
||||
}
|
||||
|
||||
Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
|
||||
|
||||
// Watch for storage notifications so we can fire storage events.
|
||||
RefPtr<StorageNotifierService> sns =
|
||||
StorageNotifierService::GetOrCreate();
|
||||
if (sns) {
|
||||
sns->Register(mObserver);
|
||||
}
|
||||
if (aOuterWindow->IsTopLevelWindow()) {
|
||||
os->AddObserver(mObserver, "clear-site-data-reload-needed", false);
|
||||
}
|
||||
} else {
|
||||
// |this| is an outer window. Outer windows start out frozen and
|
||||
// remain frozen until they get an inner window.
|
||||
MOZ_ASSERT(IsFrozen());
|
||||
}
|
||||
|
||||
Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
|
||||
|
||||
// Watch for storage notifications so we can fire storage events.
|
||||
RefPtr<StorageNotifierService> sns =
|
||||
StorageNotifierService::GetOrCreate();
|
||||
if (sns) {
|
||||
sns->Register(mObserver);
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
@ -2018,18 +2008,6 @@ nsGlobalWindowInner::DialogsAreBeingAbused()
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::DisableDialogs()
|
||||
{
|
||||
FORWARD_TO_OUTER_VOID(DisableDialogs, ());
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::EnableDialogs()
|
||||
{
|
||||
FORWARD_TO_OUTER_VOID(EnableDialogs, ());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalWindowInner::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
@ -2312,18 +2290,6 @@ nsPIDOMWindowInner::Resume()
|
||||
nsGlobalWindowInner::Cast(this)->Resume();
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::Freeze()
|
||||
{
|
||||
nsGlobalWindowInner::Cast(this)->Freeze();
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::Thaw()
|
||||
{
|
||||
nsGlobalWindowInner::Cast(this)->Thaw();
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::SyncStateFromParentWindow()
|
||||
{
|
||||
@ -2348,12 +2314,6 @@ nsPIDOMWindowInner::GetController() const
|
||||
return nsGlobalWindowInner::Cast(this)->GetController();
|
||||
}
|
||||
|
||||
RefPtr<mozilla::dom::ServiceWorker>
|
||||
nsPIDOMWindowInner::GetOrCreateServiceWorker(const mozilla::dom::ServiceWorkerDescriptor& aDescriptor)
|
||||
{
|
||||
return nsGlobalWindowInner::Cast(this)->GetOrCreateServiceWorker(aDescriptor);
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope)
|
||||
{
|
||||
@ -2752,16 +2712,6 @@ nsGlobalWindowInner::GetScriptableParent()
|
||||
FORWARD_TO_OUTER(GetScriptableParent, (), nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Behavies identically to GetScriptableParent extept that it returns null
|
||||
* if GetScriptableParent would return this window.
|
||||
*/
|
||||
nsPIDOMWindowOuter*
|
||||
nsGlobalWindowInner::GetScriptableParentOrNull()
|
||||
{
|
||||
FORWARD_TO_OUTER(GetScriptableParentOrNull, (), nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetScriptableTop is called when script reads window.top.
|
||||
*
|
||||
@ -3815,24 +3765,6 @@ nsGlobalWindowInner::Blur(ErrorResult& aError)
|
||||
FORWARD_TO_OUTER_OR_THROW(BlurOuter, (), aError, );
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::Back(ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(BackOuter, (aError), aError, );
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::Forward(ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(ForwardOuter, (aError), aError, );
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::Home(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(HomeOuter, (aSubjectPrincipal, aError), aError, );
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::Stop(ErrorResult& aError)
|
||||
{
|
||||
@ -4191,12 +4123,6 @@ nsGlobalWindowInner::Close()
|
||||
FORWARD_TO_OUTER(Close, (), NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowInner::ReallyCloseWindow()
|
||||
{
|
||||
FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
|
||||
}
|
||||
|
||||
bool
|
||||
nsGlobalWindowInner::IsInModalState()
|
||||
{
|
||||
@ -4886,26 +4812,6 @@ nsGlobalWindowInner::DispatchSyncPopState()
|
||||
return err.StealNSResult();
|
||||
}
|
||||
|
||||
// Find an nsICanvasFrame under aFrame. Only search the principal
|
||||
// child lists. aFrame must be non-null.
|
||||
static nsCanvasFrame*
|
||||
FindCanvasFrame(nsIFrame* aFrame)
|
||||
{
|
||||
nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
|
||||
if (canvasFrame) {
|
||||
return canvasFrame;
|
||||
}
|
||||
|
||||
for (nsIFrame* kid : aFrame->PrincipalChildList()) {
|
||||
canvasFrame = FindCanvasFrame(kid);
|
||||
if (canvasFrame) {
|
||||
return canvasFrame;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Tells the HTMLFrame/CanvasFrame that is now has focus
|
||||
void
|
||||
@ -4927,26 +4833,19 @@ nsGlobalWindowInner::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewConte
|
||||
|
||||
Element *rootElement = mDoc->GetRootElement();
|
||||
if (rootElement) {
|
||||
if ((mHasFocus || aFocusChanged) &&
|
||||
(mFocusedElement == rootElement || aNewContent == rootElement)) {
|
||||
nsIFrame* frame = rootElement->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
frame = frame->GetParent();
|
||||
nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
|
||||
if (canvasFrame) {
|
||||
canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
|
||||
}
|
||||
}
|
||||
if ((mHasFocus || aFocusChanged) &&
|
||||
(mFocusedElement == rootElement || aNewContent == rootElement)) {
|
||||
nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame();
|
||||
if (canvasFrame) {
|
||||
canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Look for the frame the hard way
|
||||
nsIFrame* frame = presShell->GetRootFrame();
|
||||
if (frame) {
|
||||
nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
|
||||
if (canvasFrame) {
|
||||
canvasFrame->SetHasFocus(false);
|
||||
}
|
||||
}
|
||||
// XXXbz I would expect that there is never a canvasFrame in this case...
|
||||
nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame();
|
||||
if (canvasFrame) {
|
||||
canvasFrame->SetHasFocus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8082,6 +7981,10 @@ nsPIDOMWindowInner::MaybeCreateDoc()
|
||||
void
|
||||
nsGlobalWindowInner::PropagateClearSiteDataReload(const nsACString& aOrigin)
|
||||
{
|
||||
if (!IsCurrentInnerWindow()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPrincipal* principal = GetPrincipal();
|
||||
if (!principal) {
|
||||
return;
|
||||
|
@ -275,9 +275,6 @@ public:
|
||||
static already_AddRefed<nsGlobalWindowInner>
|
||||
Create(nsGlobalWindowOuter* aOuter, bool aIsChrome);
|
||||
|
||||
// callback for close event
|
||||
void ReallyCloseWindow();
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
@ -352,6 +349,14 @@ public:
|
||||
void Suspend();
|
||||
void Resume();
|
||||
virtual bool IsSuspended() const override;
|
||||
|
||||
// Calling Freeze() on a window will automatically Suspend() it. In
|
||||
// addition, the window and its children are further treated as no longer
|
||||
// suitable for interaction with the user. For example, it may be marked
|
||||
// non-visible, cannot be focused, etc. All worker threads are also frozen
|
||||
// bringing them to a complete stop. A window can have Freeze() called
|
||||
// multiple times and will only thaw after a matching number of Thaw()
|
||||
// calls.
|
||||
void Freeze();
|
||||
void Thaw();
|
||||
virtual bool IsFrozen() const override;
|
||||
@ -449,14 +454,6 @@ public:
|
||||
// Inner windows only.
|
||||
bool DialogsAreBeingAbused();
|
||||
|
||||
// These functions are used for controlling and determining whether dialogs
|
||||
// (alert, prompt, confirm) are currently allowed in this window. If you want
|
||||
// to temporarily disable dialogs, please use TemporarilyDisableDialogs, not
|
||||
// EnableDialogs/DisableDialogs, because correctly determining whether to
|
||||
// re-enable dialogs is actually quite difficult.
|
||||
void EnableDialogs();
|
||||
void DisableDialogs();
|
||||
|
||||
nsIScriptContext *GetContextInternal();
|
||||
|
||||
nsGlobalWindowOuter *GetOuterWindowInternal() const;
|
||||
@ -676,7 +673,6 @@ public:
|
||||
void GetEvent(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
||||
already_AddRefed<nsPIDOMWindowOuter> GetParent(mozilla::ErrorResult& aError);
|
||||
nsPIDOMWindowOuter* GetScriptableParent() override;
|
||||
nsPIDOMWindowOuter* GetScriptableParentOrNull() override;
|
||||
mozilla::dom::Element*
|
||||
GetFrameElement(nsIPrincipal& aSubjectPrincipal,
|
||||
mozilla::ErrorResult& aError);
|
||||
@ -887,9 +883,6 @@ public:
|
||||
bool GetFullScreen(mozilla::ErrorResult& aError);
|
||||
bool GetFullScreen() override;
|
||||
void SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError);
|
||||
void Back(mozilla::ErrorResult& aError);
|
||||
void Forward(mozilla::ErrorResult& aError);
|
||||
void Home(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError);
|
||||
bool Find(const nsAString& aString, bool aCaseSensitive, bool aBackwards,
|
||||
bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
|
||||
bool aShowDialog, mozilla::ErrorResult& aError);
|
||||
|
@ -306,9 +306,6 @@ using mozilla::TimeStamp;
|
||||
return GetCurrentInnerWindowInternal()->method args; \
|
||||
PR_END_MACRO
|
||||
|
||||
#define DEFAULT_HOME_PAGE "www.mozilla.org"
|
||||
#define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
|
||||
|
||||
static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
|
||||
|
||||
static int32_t gOpenPopupSpamCount = 0;
|
||||
@ -854,13 +851,6 @@ nsGlobalWindowOuter::nsGlobalWindowOuter()
|
||||
// remain frozen until they get an inner window.
|
||||
MOZ_ASSERT(IsFrozen());
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
|
||||
if (docShell) {
|
||||
mTabChild = docShell->GetTabChild();
|
||||
}
|
||||
}
|
||||
|
||||
// We could have failed the first time through trying
|
||||
// to create the entropy collector, so we should
|
||||
// try to get one until we succeed.
|
||||
@ -1146,7 +1136,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowOuter)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
|
||||
|
||||
@ -1174,7 +1163,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowOuter)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
|
||||
@ -1256,12 +1244,6 @@ nsGlobalWindowOuter::GetGlobalJSObject()
|
||||
return FastGetGlobalJSObject();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::TraceGlobalJSObject(JSTracer* aTrc)
|
||||
{
|
||||
TraceWrapper(aTrc, "active window global");
|
||||
}
|
||||
|
||||
bool
|
||||
nsGlobalWindowOuter::WouldReuseInnerWindow(nsIDocument* aNewDocument)
|
||||
{
|
||||
@ -2183,7 +2165,6 @@ nsGlobalWindowOuter::DetachFromDocShell()
|
||||
// Remember the document's principal and URI.
|
||||
mDocumentPrincipal = mDoc->NodePrincipal();
|
||||
mDocumentURI = mDoc->GetDocumentURI();
|
||||
mDocBaseURI = mDoc->GetDocBaseURI();
|
||||
|
||||
// Release our document reference
|
||||
DropOuterWindowDocs();
|
||||
@ -4869,81 +4850,6 @@ nsGlobalWindowOuter::BlurOuter()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::BackOuter(ErrorResult& aError)
|
||||
{
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
|
||||
if (!webNav) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aError = webNav->GoBack();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::ForwardOuter(ErrorResult& aError)
|
||||
{
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
|
||||
if (!webNav) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aError = webNav->GoForward();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::HomeOuter(nsIPrincipal& aSubjectPrincipal, ErrorResult& aError)
|
||||
{
|
||||
if (!mDocShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString homeURL;
|
||||
Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE, homeURL);
|
||||
|
||||
if (homeURL.IsEmpty()) {
|
||||
// if all else fails, use this
|
||||
#ifdef DEBUG_seth
|
||||
printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
|
||||
#endif
|
||||
homeURL = NS_LITERAL_STRING(DEFAULT_HOME_PAGE);
|
||||
}
|
||||
|
||||
#ifdef MOZ_PHOENIX
|
||||
{
|
||||
// Firefox lets the user specify multiple home pages to open in
|
||||
// individual tabs by separating them with '|'. Since we don't
|
||||
// have the machinery in place to easily open new tabs from here,
|
||||
// simply truncate the homeURL at the first '|' character to
|
||||
// prevent any possibilities of leaking the users list of home
|
||||
// pages to the first home page.
|
||||
//
|
||||
// Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
|
||||
// fixed we can revisit this.
|
||||
int32_t firstPipe = homeURL.FindChar('|');
|
||||
|
||||
if (firstPipe > 0) {
|
||||
homeURL.Truncate(firstPipe);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
|
||||
if (!webNav) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aError = webNav->LoadURI(homeURL.get(),
|
||||
nsIWebNavigation::LOAD_FLAGS_NONE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&aSubjectPrincipal);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::StopOuter(ErrorResult& aError)
|
||||
{
|
||||
@ -6655,12 +6561,6 @@ nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground)
|
||||
mIsBackground = aIsBackground;
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::MaybeUpdateTouchState()
|
||||
{
|
||||
FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::SetChromeEventHandler(EventTarget* aChromeEventHandler)
|
||||
{
|
||||
@ -7244,13 +7144,6 @@ nsGlobalWindowOuter::SecurityCheckURL(const char *aURL, nsIURI** aURI)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGlobalWindowOuter::IsPrivateBrowsing()
|
||||
{
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
|
||||
return loadContext && loadContext->UsePrivateBrowsing();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::FlushPendingNotifications(FlushType aType)
|
||||
{
|
||||
@ -7336,29 +7229,12 @@ nsGlobalWindowOuter::RestoreWindowState(nsISupports *aState)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX(nika): Can we remove these?
|
||||
void
|
||||
nsGlobalWindowOuter::EventListenerAdded(nsAtom* aType)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::EventListenerRemoved(nsAtom* aType)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindowOuter::AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const
|
||||
{
|
||||
aWindowSizes.mDOMOtherSize += aWindowSizes.mState.mMallocSizeOf(this);
|
||||
}
|
||||
|
||||
bool
|
||||
nsGlobalWindowOuter::UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDevices)
|
||||
{
|
||||
FORWARD_TO_INNER(UpdateVRDisplays, (aDevices), false);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsGlobalWindowOuter::GetAutoActivateVRDisplayID()
|
||||
{
|
||||
@ -7738,12 +7614,6 @@ nsPIDOMWindowOuter::GetDocumentURI() const
|
||||
}
|
||||
|
||||
|
||||
nsIURI*
|
||||
nsPIDOMWindowOuter::GetDocBaseURI() const
|
||||
{
|
||||
return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get();
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowOuter::MaybeCreateDoc()
|
||||
{
|
||||
|
@ -245,8 +245,6 @@ public:
|
||||
return GetWrapperPreserveColor();
|
||||
}
|
||||
|
||||
void TraceGlobalJSObject(JSTracer* aTrc);
|
||||
|
||||
virtual nsresult EnsureScriptEnvironment() override;
|
||||
|
||||
virtual nsIScriptContext *GetScriptContext() override;
|
||||
@ -345,8 +343,6 @@ public:
|
||||
virtual bool CanClose() override;
|
||||
virtual void ForceClose() override;
|
||||
|
||||
virtual void MaybeUpdateTouchState() override;
|
||||
|
||||
// Outer windows only.
|
||||
virtual bool DispatchCustomEvent(const nsAString& aEventName) override;
|
||||
bool DispatchResizeEvent(const mozilla::CSSIntSize& aSize);
|
||||
@ -363,11 +359,6 @@ public:
|
||||
nsIWidget* aWidget, nsIScreen* aScreen);
|
||||
bool FullScreen() const;
|
||||
|
||||
using EventTarget::EventListenerAdded;
|
||||
virtual void EventListenerAdded(nsAtom* aType) override;
|
||||
using EventTarget::EventListenerRemoved;
|
||||
virtual void EventListenerRemoved(nsAtom* aType) override;
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
|
||||
@ -506,9 +497,6 @@ public:
|
||||
mAllowScriptsToClose = true;
|
||||
}
|
||||
|
||||
// Update the VR displays for this window
|
||||
bool UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDisplays);
|
||||
|
||||
// Outer windows only.
|
||||
uint32_t GetAutoActivateVRDisplayID();
|
||||
// Outer windows only.
|
||||
@ -674,9 +662,6 @@ public:
|
||||
bool GetFullScreen() override;
|
||||
void SetFullScreenOuter(bool aFullScreen, mozilla::ErrorResult& aError);
|
||||
nsresult SetFullScreen(bool aFullScreen) override;
|
||||
void BackOuter(mozilla::ErrorResult& aError);
|
||||
void ForwardOuter(mozilla::ErrorResult& aError);
|
||||
void HomeOuter(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError);
|
||||
bool FindOuter(const nsAString& aString, bool aCaseSensitive, bool aBackwards,
|
||||
bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
|
||||
bool aShowDialog, mozilla::ErrorResult& aError);
|
||||
@ -915,7 +900,6 @@ public:
|
||||
already_AddRefed<nsIBaseWindow> GetTreeOwnerWindow();
|
||||
already_AddRefed<nsIWebBrowserChrome> GetWebBrowserChrome();
|
||||
nsresult SecurityCheckURL(const char *aURL, nsIURI** aURI);
|
||||
bool IsPrivateBrowsing();
|
||||
|
||||
bool PopupWhitelisted();
|
||||
PopupControlState RevisePopupAbuseLevel(PopupControlState);
|
||||
@ -1118,8 +1102,6 @@ protected:
|
||||
RefPtr<mozilla::dom::Storage> mLocalStorage;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
// mTabChild is only ever populated in the content process.
|
||||
nsCOMPtr<nsITabChild> mTabChild;
|
||||
|
||||
uint32_t mSerial;
|
||||
|
||||
|
@ -280,16 +280,6 @@ public:
|
||||
void Suspend();
|
||||
void Resume();
|
||||
|
||||
// Calling Freeze() on a window will automatically Suspend() it. In
|
||||
// addition, the window and its children are further treated as no longer
|
||||
// suitable for interaction with the user. For example, it may be marked
|
||||
// non-visible, cannot be focused, etc. All worker threads are also frozen
|
||||
// bringing them to a complete stop. A window can have Freeze() called
|
||||
// multiple times and will only thaw after a matching number of Thaw()
|
||||
// calls.
|
||||
void Freeze();
|
||||
void Thaw();
|
||||
|
||||
// Apply the parent window's suspend, freeze, and modal state to the current
|
||||
// window.
|
||||
void SyncStateFromParentWindow();
|
||||
@ -341,9 +331,6 @@ public:
|
||||
mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
|
||||
mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
|
||||
|
||||
RefPtr<mozilla::dom::ServiceWorker>
|
||||
GetOrCreateServiceWorker(const mozilla::dom::ServiceWorkerDescriptor& aDescriptor);
|
||||
|
||||
void NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope);
|
||||
|
||||
void NoteDOMContentLoaded();
|
||||
@ -359,12 +346,6 @@ public:
|
||||
virtual nsPIDOMWindowOuter* GetScriptableParent() = 0;
|
||||
virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() = 0;
|
||||
|
||||
/**
|
||||
* Behavies identically to GetScriptableParent extept that it returns null
|
||||
* if GetScriptableParent would return this window.
|
||||
*/
|
||||
virtual nsPIDOMWindowOuter* GetScriptableParentOrNull() = 0;
|
||||
|
||||
mozilla::dom::EventTarget* GetChromeEventHandler() const
|
||||
{
|
||||
return mChromeEventHandler;
|
||||
@ -862,7 +843,7 @@ public:
|
||||
virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() = 0;
|
||||
|
||||
/**
|
||||
* Behavies identically to GetScriptableParent extept that it returns null
|
||||
* Behaves identically to GetScriptableParent except that it returns null
|
||||
* if GetScriptableParent would return this window.
|
||||
*/
|
||||
virtual nsPIDOMWindowOuter* GetScriptableParentOrNull() = 0;
|
||||
@ -891,14 +872,11 @@ public:
|
||||
return mParentTarget;
|
||||
}
|
||||
|
||||
virtual void MaybeUpdateTouchState() {}
|
||||
|
||||
nsIDocument* GetExtantDoc() const
|
||||
{
|
||||
return mDoc;
|
||||
}
|
||||
nsIURI* GetDocumentURI() const;
|
||||
nsIURI* GetDocBaseURI() const;
|
||||
|
||||
nsIDocument* GetDoc()
|
||||
{
|
||||
@ -1197,7 +1175,6 @@ protected:
|
||||
nsCOMPtr<nsIDocument> mDoc; // strong
|
||||
// Cache the URI when mDoc is cleared.
|
||||
nsCOMPtr<nsIURI> mDocumentURI; // strong
|
||||
nsCOMPtr<nsIURI> mDocBaseURI; // strong
|
||||
|
||||
nsCOMPtr<mozilla::dom::EventTarget> mParentTarget; // strong
|
||||
|
||||
|
@ -295,20 +295,22 @@ DOMEventTargetHelper::MaybeUpdateKeepAlive()
|
||||
{
|
||||
bool shouldBeKeptAlive = false;
|
||||
|
||||
if (!mKeepingAliveTypes.mAtoms.IsEmpty()) {
|
||||
for (uint32_t i = 0; i < mKeepingAliveTypes.mAtoms.Length(); ++i) {
|
||||
if (HasListenersFor(mKeepingAliveTypes.mAtoms[i])) {
|
||||
shouldBeKeptAlive = true;
|
||||
break;
|
||||
if (NS_SUCCEEDED(CheckInnerWindowCorrectness())) {
|
||||
if (!mKeepingAliveTypes.mAtoms.IsEmpty()) {
|
||||
for (uint32_t i = 0; i < mKeepingAliveTypes.mAtoms.Length(); ++i) {
|
||||
if (HasListenersFor(mKeepingAliveTypes.mAtoms[i])) {
|
||||
shouldBeKeptAlive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldBeKeptAlive && !mKeepingAliveTypes.mStrings.IsEmpty()) {
|
||||
for (uint32_t i = 0; i < mKeepingAliveTypes.mStrings.Length(); ++i) {
|
||||
if (HasListenersFor(mKeepingAliveTypes.mStrings[i])) {
|
||||
shouldBeKeptAlive = true;
|
||||
break;
|
||||
if (!shouldBeKeptAlive && !mKeepingAliveTypes.mStrings.IsEmpty()) {
|
||||
for (uint32_t i = 0; i < mKeepingAliveTypes.mStrings.Length(); ++i) {
|
||||
if (HasListenersFor(mKeepingAliveTypes.mStrings[i])) {
|
||||
shouldBeKeptAlive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +304,8 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
in nsIURI aRequestOrigin,
|
||||
in nsISupports aContext,
|
||||
in ACString aMimeTypeGuess,
|
||||
in nsIURI aOriginalURIIfRedirect);
|
||||
in nsIURI aOriginalURIIfRedirect,
|
||||
in bool aSendViolationReports);
|
||||
|
||||
%{ C++
|
||||
// nsIObserver topic to fire when the policy encounters a violation.
|
||||
|
@ -35,6 +35,7 @@ PermissionStatus::PermissionStatus(nsPIDOMWindowInner* aWindow,
|
||||
, mName(aName)
|
||||
, mState(PermissionState::Denied)
|
||||
{
|
||||
KeepAliveIfHasListenersFor(NS_LITERAL_STRING("change"));
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -125,5 +126,18 @@ PermissionStatus::PermissionChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PermissionStatus::DisconnectFromOwner()
|
||||
{
|
||||
IgnoreKeepAliveIfHasListenersFor(NS_LITERAL_STRING("change"));
|
||||
|
||||
if (mObserver) {
|
||||
mObserver->RemoveSink(this);
|
||||
mObserver = nullptr;
|
||||
}
|
||||
|
||||
DOMEventTargetHelper::DisconnectFromOwner();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -33,6 +33,9 @@ public:
|
||||
|
||||
IMPL_EVENT_HANDLER(change)
|
||||
|
||||
void
|
||||
DisconnectFromOwner() override;
|
||||
|
||||
private:
|
||||
~PermissionStatus();
|
||||
|
||||
|
@ -114,45 +114,6 @@ BlockedContentSourceToString(nsCSPContext::BlockedContentSource aSource,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a key for use in the ShouldLoad cache.
|
||||
* Looks like: <uri>!<nsIContentPolicy::LOAD_TYPE>
|
||||
*/
|
||||
nsresult
|
||||
CreateCacheKey_Internal(nsIURI* aContentLocation,
|
||||
nsContentPolicyType aContentType,
|
||||
nsACString& outCacheKey)
|
||||
{
|
||||
if (!aContentLocation) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool isDataScheme = false;
|
||||
nsresult rv = aContentLocation->SchemeIs("data", &isDataScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
outCacheKey.Truncate();
|
||||
if (aContentType != nsIContentPolicy::TYPE_SCRIPT && isDataScheme) {
|
||||
// For non-script data: URI, use ("data:", aContentType) as the cache key.
|
||||
outCacheKey.AppendLiteral("data:");
|
||||
outCacheKey.AppendInt(aContentType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = aContentLocation->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Don't cache for a URI longer than the cutoff size.
|
||||
if (spec.Length() <= CSP_CACHE_URI_CUTOFF_SIZE) {
|
||||
outCacheKey.Append(spec);
|
||||
outCacheKey.AppendLiteral("!");
|
||||
outCacheKey.AppendInt(aContentType);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* ===== nsIContentSecurityPolicy impl ====== */
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -162,6 +123,7 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
||||
nsISupports* aRequestContext,
|
||||
const nsACString& aMimeTypeGuess,
|
||||
nsIURI* aOriginalURIIfRedirect,
|
||||
bool aSendViolationReports,
|
||||
int16_t* outDecision)
|
||||
{
|
||||
if (CSPCONTEXTLOGENABLED()) {
|
||||
@ -178,8 +140,6 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
||||
// case correctly.
|
||||
aContentType = nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(aContentType);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// This ShouldLoad function is called from nsCSPService::ShouldLoad,
|
||||
// which already checked a number of things, including:
|
||||
// * aContentLocation is not null; we can consume this without further checks
|
||||
@ -188,16 +148,6 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
||||
// * Content Type is not whitelisted (CSP Reports, TYPE_DOCUMENT, etc).
|
||||
// * Fast Path for Apps
|
||||
|
||||
nsAutoCString cacheKey;
|
||||
rv = CreateCacheKey_Internal(aContentLocation, aContentType, cacheKey);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isCached = mShouldLoadCache.Get(cacheKey, outDecision);
|
||||
if (isCached && cacheKey.Length() > 0) {
|
||||
// this is cached, use the cached value.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Default decision, CSP can revise it if there's a policy to enforce
|
||||
*outDecision = nsIContentPolicy::ACCEPT;
|
||||
|
||||
@ -233,18 +183,13 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
|
||||
nonce,
|
||||
isPreload,
|
||||
false, // allow fallback to default-src
|
||||
true, // send violation reports
|
||||
aSendViolationReports,
|
||||
true, // send blocked URI in violation reports
|
||||
parserCreated);
|
||||
|
||||
*outDecision = permitted ? nsIContentPolicy::ACCEPT
|
||||
: nsIContentPolicy::REJECT_SERVER;
|
||||
|
||||
// Done looping, cache any relevant result
|
||||
if (cacheKey.Length() > 0 && !isPreload) {
|
||||
mShouldLoadCache.Put(cacheKey, *outDecision);
|
||||
}
|
||||
|
||||
if (CSPCONTEXTLOGENABLED()) {
|
||||
CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, "
|
||||
"aContentLocation: %s",
|
||||
@ -335,7 +280,6 @@ nsCSPContext::~nsCSPContext()
|
||||
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
||||
delete mPolicies[i];
|
||||
}
|
||||
mShouldLoadCache.Clear();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -430,8 +374,6 @@ nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
|
||||
}
|
||||
|
||||
mPolicies.AppendElement(policy);
|
||||
// reset cache since effective policy changes
|
||||
mShouldLoadCache.Clear();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
#include "mozilla/dom/SecurityPolicyViolationEvent.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIClassInfo.h"
|
||||
@ -172,7 +171,6 @@ class nsCSPContext : public nsIContentSecurityPolicy
|
||||
uint64_t mInnerWindowID; // used for web console logging
|
||||
nsTArray<nsCSPPolicy*> mPolicies;
|
||||
nsCOMPtr<nsIURI> mSelfURI;
|
||||
nsDataHashtable<nsCStringHashKey, int16_t> mShouldLoadCache;
|
||||
nsCOMPtr<nsILoadGroup> mCallingChannelLoadGroup;
|
||||
nsWeakPtr mLoadingContext;
|
||||
// The CSP hangs off the principal, so let's store a raw pointer of the principal
|
||||
|
@ -188,6 +188,7 @@ CSPService::ShouldLoad(nsIURI *aContentLocation,
|
||||
requestContext,
|
||||
aMimeTypeGuess,
|
||||
nullptr, // no redirect, aOriginal URL is null.
|
||||
aLoadInfo->GetSendCSPViolationEvents(),
|
||||
aDecision);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -212,6 +213,7 @@ CSPService::ShouldLoad(nsIURI *aContentLocation,
|
||||
requestContext,
|
||||
aMimeTypeGuess,
|
||||
nullptr, // no redirect, aOriginal URL is null.
|
||||
aLoadInfo->GetSendCSPViolationEvents(),
|
||||
aDecision);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
@ -324,6 +326,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
||||
requestContext, // nsISupports
|
||||
EmptyCString(), // ACString - MIME guess
|
||||
originalUri, // Original nsIURI
|
||||
true, // aSendViolationReports
|
||||
&aDecision);
|
||||
|
||||
// if the preload policy already denied the load, then there
|
||||
@ -348,6 +351,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
||||
requestContext, // nsISupports
|
||||
EmptyCString(), // ACString - MIME guess
|
||||
originalUri, // Original nsIURI
|
||||
true, // aSendViolationReports
|
||||
&aDecision);
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ function run_test() {
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
NetUtil.newURI("http://blocked.test/foo.js"),
|
||||
null, null, null, null);
|
||||
null, null, null, null, true);
|
||||
});
|
||||
|
||||
// test that inline script violations cause a report in report-only policy
|
||||
@ -202,7 +202,7 @@ function run_test() {
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||
NetUtil.newURI("data:image/png;base64," + base64data),
|
||||
null, null, null, null);
|
||||
null, null, null, null, true);
|
||||
});
|
||||
|
||||
// test that only the uri's scheme is reported for globally unique identifiers
|
||||
@ -211,7 +211,7 @@ function run_test() {
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
|
||||
NetUtil.newURI("intent://mymaps.com/maps?um=1&ie=UTF-8&fb=1&sll"),
|
||||
null, null, null, null);
|
||||
null, null, null, null, true);
|
||||
});
|
||||
|
||||
// test fragment removal
|
||||
@ -222,7 +222,7 @@ function run_test() {
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
NetUtil.newURI(selfSpec + "#bar"),
|
||||
null, null, null, null);
|
||||
null, null, null, null, true);
|
||||
});
|
||||
|
||||
// test scheme of ftp:
|
||||
@ -231,6 +231,6 @@ function run_test() {
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
NetUtil.newURI("ftp://blocked.test/profile.png"),
|
||||
null, null, null, null);
|
||||
null, null, null, null, true);
|
||||
});
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "mozilla/dom/SVGLengthBinding.h"
|
||||
#include "mozilla/dom/SVGMarkerElement.h"
|
||||
#include "mozilla/dom/SVGMarkerElementBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "SVGContentUtils.h"
|
||||
@ -69,11 +68,6 @@ nsresult
|
||||
nsSVGOrientType::SetBaseValue(uint16_t aValue,
|
||||
nsSVGElement *aSVGElement)
|
||||
{
|
||||
if (aValue == SVG_MARKER_ORIENT_AUTO_START_REVERSE &&
|
||||
!SVGMarkerElement::MarkerImprovementsPrefEnabled()) {
|
||||
return NS_ERROR_DOM_TYPE_ERR;
|
||||
}
|
||||
|
||||
if (aValue == SVG_MARKER_ORIENT_AUTO ||
|
||||
aValue == SVG_MARKER_ORIENT_ANGLE ||
|
||||
aValue == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
|
||||
@ -226,8 +220,7 @@ SVGMarkerElement::ParseAttribute(int32_t aNameSpaceID, nsAtom* aName,
|
||||
this, false);
|
||||
return true;
|
||||
}
|
||||
if (aValue.EqualsLiteral("auto-start-reverse") &&
|
||||
MarkerImprovementsPrefEnabled()) {
|
||||
if (aValue.EqualsLiteral("auto-start-reverse")) {
|
||||
mOrientType.SetBaseValue(SVG_MARKER_ORIENT_AUTO_START_REVERSE);
|
||||
aResult.SetTo(aValue);
|
||||
mAngleAttributes[ORIENT].SetBaseValue(0.f, SVG_ANGLETYPE_UNSPECIFIED,
|
||||
@ -386,11 +379,5 @@ SVGMarkerElement::GetViewBoxTransform()
|
||||
return *mViewBoxToViewportTransform;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
SVGMarkerElement::MarkerImprovementsPrefEnabled()
|
||||
{
|
||||
return Preferences::GetBool("svg.marker-improvements.enabled", false);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -127,9 +127,6 @@ public:
|
||||
|
||||
nsSVGOrientType* GetOrientType() { return &mOrientType; }
|
||||
|
||||
// Returns the value of svg.marker-improvements.enabled.
|
||||
static bool MarkerImprovementsPrefEnabled();
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<SVGAnimatedRect> ViewBox();
|
||||
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
|
||||
|
@ -371,11 +371,7 @@ function runTests()
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTestsWithPref() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [['svg.marker-improvements.enabled', true]] }, runTests);
|
||||
}
|
||||
|
||||
window.addEventListener("load", runTestsWithPref);
|
||||
window.addEventListener("load", runTests);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
@ -88,11 +88,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=892372
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTestsWithPref() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [['svg.marker-improvements.enabled', true]] }, run);
|
||||
}
|
||||
|
||||
window.addEventListener("load", runTestsWithPref);
|
||||
window.addEventListener("load", run);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -1565,7 +1565,7 @@ function doFrameHistoryTests()
|
||||
}, true);
|
||||
|
||||
// make sure that loading a new page and then going back maintains the focus
|
||||
gChildWindow.location = "data:text/html,<script>window.onload=function() {setTimeout(function () {SpecialPowers.wrap(window).back();}, 0);}</script>";
|
||||
gChildWindow.location = "data:text/html,<script>window.onload=function() {setTimeout(function () { history.back() }, 0);}</script>";
|
||||
}
|
||||
|
||||
function addFrameSwitchingListeners(frame)
|
||||
|
@ -273,10 +273,6 @@ partial interface Window {
|
||||
|
||||
[Throws] attribute boolean fullScreen;
|
||||
|
||||
[Throws, ChromeOnly] void back();
|
||||
[Throws, ChromeOnly] void forward();
|
||||
[Throws, ChromeOnly, NeedsSubjectPrincipal] void home();
|
||||
|
||||
// XXX Should this be in nsIDOMChromeWindow?
|
||||
void updateCommands(DOMString action,
|
||||
optional Selection? sel = null,
|
||||
|
@ -950,6 +950,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
|
||||
scene_builder_hooks: Some(Box::new(APZCallbacks::new(window_id))),
|
||||
sampler: Some(Box::new(SamplerCallback::new(window_id))),
|
||||
max_texture_size: Some(8192), // Moz2D doesn't like textures bigger than this
|
||||
clear_color: Some(ColorF::new(0.0, 0.0, 0.0, 0.0)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -616,7 +616,8 @@ static bool
|
||||
ShouldLoadCachedImage(imgRequest* aImgRequest,
|
||||
nsISupports* aLoadingContext,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsContentPolicyType aPolicyType)
|
||||
nsContentPolicyType aPolicyType,
|
||||
bool aSendCSPViolationReports)
|
||||
{
|
||||
/* Call content policies on cached images - Bug 1082837
|
||||
* Cached images are keyed off of the first uri in a redirect chain.
|
||||
@ -650,6 +651,8 @@ ShouldLoadCachedImage(imgRequest* aImgRequest,
|
||||
nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
|
||||
aPolicyType);
|
||||
|
||||
secCheckLoadInfo->SetSendCSPViolationEvents(aSendCSPViolationReports);
|
||||
|
||||
int16_t decision = nsIContentPolicy::REJECT_REQUEST;
|
||||
rv = NS_CheckContentLoadPolicy(contentLocation,
|
||||
secCheckLoadInfo,
|
||||
@ -746,7 +749,8 @@ ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
|
||||
}
|
||||
|
||||
// Content Policy Check on Cached Images
|
||||
return ShouldLoadCachedImage(request, aCX, triggeringPrincipal, aPolicyType);
|
||||
return ShouldLoadCachedImage(request, aCX, triggeringPrincipal, aPolicyType,
|
||||
/* aSendCSPViolationReports */ false);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
@ -1797,7 +1801,8 @@ imgLoader::ValidateRequestWithNewChannel(imgRequest* request,
|
||||
nsContentPolicyType aLoadPolicyType,
|
||||
imgRequestProxy** aProxyRequest,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
int32_t aCORSMode)
|
||||
int32_t aCORSMode,
|
||||
bool* aNewChannelCreated)
|
||||
{
|
||||
// now we need to insert a new channel request object inbetween the real
|
||||
// request and the proxy that basically delays loading the image until it
|
||||
@ -1853,6 +1858,10 @@ imgLoader::ValidateRequestWithNewChannel(imgRequest* request,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aNewChannelCreated) {
|
||||
*aNewChannelCreated = true;
|
||||
}
|
||||
|
||||
RefPtr<imgRequestProxy> req;
|
||||
rv = CreateNewProxyForRequest(request, aLoadGroup, aLoadingDocument,
|
||||
aObserver, aLoadFlags, getter_AddRefs(req));
|
||||
@ -1917,6 +1926,7 @@ imgLoader::ValidateEntry(imgCacheEntry* aEntry,
|
||||
nsLoadFlags aLoadFlags,
|
||||
nsContentPolicyType aLoadPolicyType,
|
||||
bool aCanMakeNewChannel,
|
||||
bool* aNewChannelCreated,
|
||||
imgRequestProxy** aProxyRequest,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
int32_t aCORSMode)
|
||||
@ -2036,7 +2046,7 @@ imgLoader::ValidateEntry(imgCacheEntry* aEntry,
|
||||
aCX, aLoadingDocument,
|
||||
aLoadFlags, aLoadPolicyType,
|
||||
aProxyRequest, aTriggeringPrincipal,
|
||||
aCORSMode);
|
||||
aCORSMode, aNewChannelCreated);
|
||||
}
|
||||
|
||||
return !validateRequest;
|
||||
@ -2341,10 +2351,12 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
imgCacheTable& cache = GetCache(key);
|
||||
|
||||
if (cache.Get(key, getter_AddRefs(entry)) && entry) {
|
||||
bool newChannelCreated = false;
|
||||
if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
|
||||
aReferrerPolicy, aLoadGroup, aObserver, aLoadingDocument,
|
||||
aLoadingDocument, requestFlags, aContentPolicyType, true,
|
||||
_retval, aTriggeringPrincipal, corsmode)) {
|
||||
&newChannelCreated, _retval, aTriggeringPrincipal,
|
||||
corsmode)) {
|
||||
request = entry->GetRequest();
|
||||
|
||||
// If this entry has no proxies, its request has no reference to the
|
||||
@ -2363,6 +2375,18 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
|
||||
entry->Touch();
|
||||
|
||||
if (!newChannelCreated) {
|
||||
// This is ugly but it's needed to report CSP violations. We have 3
|
||||
// scenarios:
|
||||
// - we don't have cache. We are not in this if() stmt. A new channel is
|
||||
// created and that triggers the CSP checks.
|
||||
// - We have a cache entry and this is blocked by CSP directives.
|
||||
DebugOnly<bool> shouldLoad =
|
||||
ShouldLoadCachedImage(request, aLoadingDocument, aTriggeringPrincipal,
|
||||
aContentPolicyType,
|
||||
/* aSendCSPViolationReports */ true);
|
||||
MOZ_ASSERT(shouldLoad);
|
||||
}
|
||||
} else {
|
||||
// We can't use this entry. We'll try to load it off the network, and if
|
||||
// successful, overwrite the old entry in the cache with a new one.
|
||||
@ -2613,7 +2637,7 @@ imgLoader::LoadImageWithChannel(nsIChannel* channel,
|
||||
|
||||
if (ValidateEntry(entry, uri, nullptr, nullptr, RP_Unset,
|
||||
nullptr, aObserver, aCX, doc, requestFlags,
|
||||
policyType, false, nullptr,
|
||||
policyType, false, nullptr, nullptr,
|
||||
nullptr, imgIRequest::CORS_NONE)) {
|
||||
request = entry->GetRequest();
|
||||
} else {
|
||||
|
@ -413,6 +413,7 @@ private: // methods
|
||||
nsLoadFlags aLoadFlags,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
bool aCanMakeNewChannel,
|
||||
bool* aNewChannelCreated,
|
||||
imgRequestProxy** aProxyRequest,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
int32_t aCORSMode);
|
||||
@ -429,7 +430,8 @@ private: // methods
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
imgRequestProxy** aProxyRequest,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
int32_t aCORSMode);
|
||||
int32_t aCORSMode,
|
||||
bool* aNewChannelCreated);
|
||||
|
||||
nsresult CreateNewProxyForRequest(imgRequest* aRequest,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
|
@ -431,6 +431,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
|
||||
aLoadInfo->GetInitialSecurityCheckDone(),
|
||||
aLoadInfo->GetIsInThirdPartyContext(),
|
||||
aLoadInfo->GetIsDocshellReload(),
|
||||
aLoadInfo->GetSendCSPViolationEvents(),
|
||||
aLoadInfo->GetOriginAttributes(),
|
||||
redirectChainIncludingInternalRedirects,
|
||||
redirectChain,
|
||||
@ -587,6 +588,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
|
||||
loadInfoArgs.initialSecurityCheckDone(),
|
||||
loadInfoArgs.isInThirdPartyContext(),
|
||||
loadInfoArgs.isDocshellReload(),
|
||||
loadInfoArgs.sendCSPViolationEvents(),
|
||||
loadInfoArgs.originAttributes(),
|
||||
redirectChainIncludingInternalRedirects,
|
||||
redirectChain,
|
||||
|
@ -266,6 +266,11 @@ def main(argv):
|
||||
# to be off when it starts.
|
||||
options.exclude += [os.path.join('debug', 'Script-getOffsetsCoverage-02.js')]
|
||||
|
||||
# These tests expect functions to be parsed lazily, but lazy parsing
|
||||
# is disabled on coverage build.
|
||||
options.exclude += [os.path.join('debug', 'Debugger-findScripts-uncompleted-01.js')]
|
||||
options.exclude += [os.path.join('debug', 'Debugger-findScripts-uncompleted-02.js')]
|
||||
|
||||
if options.exclude_from:
|
||||
with open(options.exclude_from) as fh:
|
||||
for line in fh:
|
||||
|
@ -776,16 +776,14 @@ MacroAssembler::nurseryAllocateObject(Register result, Register temp, gc::AllocK
|
||||
// No explicit check for nursery.isEnabled() is needed, as the comparison
|
||||
// with the nursery's end will always fail in such cases.
|
||||
CompileZone* zone = GetJitContext()->realm->zone();
|
||||
int thingSize = int(gc::Arena::thingSize(allocKind));
|
||||
int totalSize = thingSize + nDynamicSlots * sizeof(HeapSlot);
|
||||
size_t thingSize = gc::Arena::thingSize(allocKind);
|
||||
size_t totalSize = thingSize + nDynamicSlots * sizeof(HeapSlot);
|
||||
MOZ_ASSERT(totalSize < INT32_MAX);
|
||||
MOZ_ASSERT(totalSize % gc::CellAlignBytes == 0);
|
||||
void *ptrNurseryPosition = zone->addressOfNurseryPosition();
|
||||
loadPtr(AbsoluteAddress(ptrNurseryPosition), result);
|
||||
computeEffectiveAddress(Address(result, totalSize), temp);
|
||||
const void *ptrNurseryCurrentEnd = zone->addressOfNurseryCurrentEnd();
|
||||
branchPtr(Assembler::Below, AbsoluteAddress(ptrNurseryCurrentEnd), temp,
|
||||
fail);
|
||||
storePtr(temp, AbsoluteAddress(ptrNurseryPosition));
|
||||
|
||||
bumpPointerAllocate(result, temp, fail,
|
||||
zone->addressOfNurseryPosition(),
|
||||
zone->addressOfNurseryCurrentEnd(), totalSize, totalSize);
|
||||
|
||||
if (nDynamicSlots) {
|
||||
computeEffectiveAddress(Address(result, thingSize), temp);
|
||||
@ -962,23 +960,39 @@ MacroAssembler::nurseryAllocateString(Register result, Register temp, gc::AllocK
|
||||
// with the nursery's end will always fail in such cases.
|
||||
|
||||
CompileZone* zone = GetJitContext()->realm->zone();
|
||||
int thingSize = int(gc::Arena::thingSize(allocKind));
|
||||
int totalSize = js::Nursery::stringHeaderSize() + thingSize;
|
||||
size_t thingSize = gc::Arena::thingSize(allocKind);
|
||||
size_t totalSize = js::Nursery::stringHeaderSize() + thingSize;
|
||||
MOZ_ASSERT(totalSize < INT32_MAX,
|
||||
"Nursery allocation too large");
|
||||
MOZ_ASSERT(totalSize % gc::CellAlignBytes == 0);
|
||||
|
||||
// The nursery position (allocation pointer) and the nursery end are stored
|
||||
bumpPointerAllocate(result, temp, fail,
|
||||
zone->addressOfStringNurseryPosition(),
|
||||
zone->addressOfStringNurseryCurrentEnd(), totalSize, thingSize);
|
||||
storePtr(ImmPtr(zone), Address(result, -js::Nursery::stringHeaderSize()));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::bumpPointerAllocate(Register result, Register temp, Label* fail,
|
||||
void* posAddr, const void* curEndAddr, uint32_t totalSize, uint32_t size)
|
||||
{
|
||||
// The position (allocation pointer) and the end pointer are stored
|
||||
// very close to each other -- specifically, easily within a 32 bit offset.
|
||||
// Use relative offsets between them, to avoid 64-bit immediate loads.
|
||||
auto nurseryPosAddr = intptr_t(zone->addressOfStringNurseryPosition());
|
||||
auto nurseryEndAddr = intptr_t(zone->addressOfStringNurseryCurrentEnd());
|
||||
|
||||
movePtr(ImmPtr(zone->addressOfNurseryPosition()), temp);
|
||||
//
|
||||
// I tried to optimise this further by using an extra register to avoid
|
||||
// the final subtraction and hopefully get some more instruction
|
||||
// parallelism, but it made no difference.
|
||||
movePtr(ImmPtr(posAddr), temp);
|
||||
loadPtr(Address(temp, 0), result);
|
||||
addPtr(Imm32(totalSize), result);
|
||||
branchPtr(Assembler::Below, Address(temp, nurseryEndAddr - nurseryPosAddr), result, fail);
|
||||
CheckedInt<int32_t> endOffset = (CheckedInt<uintptr_t>(uintptr_t(curEndAddr)) -
|
||||
CheckedInt<uintptr_t>(uintptr_t(posAddr))).toChecked<int32_t>();
|
||||
MOZ_ASSERT(endOffset.isValid(),
|
||||
"Position and end pointers must be nearby");
|
||||
branchPtr(Assembler::Below, Address(temp, endOffset.value()), result, fail);
|
||||
storePtr(result, Address(temp, 0));
|
||||
subPtr(Imm32(thingSize), result);
|
||||
storePtr(ImmPtr(zone), Address(result, -js::Nursery::stringHeaderSize()));
|
||||
subPtr(Imm32(size), result);
|
||||
}
|
||||
|
||||
// Inlined equivalent of gc::AllocateString, jumping to fail if nursery
|
||||
|
@ -2279,6 +2279,10 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
bool shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap initialHeap);
|
||||
void nurseryAllocateObject(Register result, Register temp, gc::AllocKind allocKind,
|
||||
size_t nDynamicSlots, Label* fail);
|
||||
void bumpPointerAllocate(Register result, Register temp, Label* fail,
|
||||
void* posAddr, const void* curEddAddr,
|
||||
uint32_t totalSize, uint32_t size);
|
||||
|
||||
void freeListAllocate(Register result, Register temp, gc::AllocKind allocKind, Label* fail);
|
||||
void allocateObject(Register result, Register temp, gc::AllocKind allocKind,
|
||||
uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label* fail);
|
||||
|
@ -58,7 +58,7 @@ XPCConvert::IsMethodReflectable(const nsXPTMethodInfo& info)
|
||||
|
||||
// Reflected methods can't use native types. All native types end up
|
||||
// getting tagged as void*, so this check is easy.
|
||||
if (type.TagPart() == nsXPTType::T_VOID)
|
||||
if (type.Tag() == nsXPTType::T_VOID)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -108,7 +108,7 @@ XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
|
||||
|
||||
switch (type.TagPart()) {
|
||||
switch (type.Tag()) {
|
||||
case nsXPTType::T_I8 :
|
||||
d.setInt32(*static_cast<const int8_t*>(s));
|
||||
return true;
|
||||
@ -385,10 +385,17 @@ XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
||||
return true;
|
||||
}
|
||||
|
||||
case nsXPTType::T_ARRAY:
|
||||
return NativeArray2JS(d, static_cast<const void* const*>(s),
|
||||
case nsXPTType::T_LEGACY_ARRAY:
|
||||
return NativeArray2JS(d, *static_cast<const void* const*>(s),
|
||||
type.ArrayElementType(), iid, arrlen, pErr);
|
||||
|
||||
case nsXPTType::T_ARRAY:
|
||||
{
|
||||
auto* array = static_cast<const xpt::detail::UntypedTArray*>(s);
|
||||
return NativeArray2JS(d, array->Elements(), type.ArrayElementType(),
|
||||
iid, array->Length(), pErr);
|
||||
}
|
||||
|
||||
default:
|
||||
NS_ERROR("bad type");
|
||||
return false;
|
||||
@ -448,7 +455,7 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
bool sizeis = type.Tag() == TD_PSTRING_SIZE_IS ||
|
||||
type.Tag() == TD_PWSTRING_SIZE_IS;
|
||||
|
||||
switch (type.TagPart()) {
|
||||
switch (type.Tag()) {
|
||||
case nsXPTType::T_I8 :
|
||||
return ConvertToPrimitive(cx, s, static_cast<int8_t*>(d));
|
||||
case nsXPTType::T_I16 :
|
||||
@ -834,9 +841,70 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
||||
return ok;
|
||||
}
|
||||
|
||||
case nsXPTType::T_LEGACY_ARRAY:
|
||||
{
|
||||
void** dest = (void**)d;
|
||||
const nsXPTType& elty = type.ArrayElementType();
|
||||
|
||||
*dest = nullptr;
|
||||
|
||||
// FIXME: XPConnect historically has shortcut the JSArray2Native codepath in
|
||||
// its caller if arrlen is 0, allowing arbitrary values to be passed as
|
||||
// arrays and interpreted as the empty array (bug 1458987).
|
||||
//
|
||||
// NOTE: Once this is fixed, null/undefined should be allowed for arrays if
|
||||
// arrlen is 0.
|
||||
if (arrlen == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ok = JSArray2Native(s, elty, iid, pErr, [&] (uint32_t* aLength) -> void* {
|
||||
// Check that we have enough elements in our array.
|
||||
if (*aLength < arrlen) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
return nullptr;
|
||||
}
|
||||
*aLength = arrlen;
|
||||
|
||||
// Allocate the backing buffer & return it.
|
||||
*dest = moz_xmalloc(*aLength * elty.Stride());
|
||||
if (!*dest) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return nullptr;
|
||||
}
|
||||
return *dest;
|
||||
});
|
||||
|
||||
if (!ok && *dest) {
|
||||
// An error occurred, free any allocated backing buffer.
|
||||
free(*dest);
|
||||
*dest = nullptr;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
case nsXPTType::T_ARRAY:
|
||||
return JSArray2Native((void**)d, s, arrlen,
|
||||
type.ArrayElementType(), iid, pErr);
|
||||
{
|
||||
auto* dest = (xpt::detail::UntypedTArray*)d;
|
||||
const nsXPTType& elty = type.ArrayElementType();
|
||||
|
||||
bool ok = JSArray2Native(s, elty, iid, pErr, [&] (uint32_t* aLength) -> void* {
|
||||
if (!dest->SetLength(elty, *aLength)) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return nullptr;
|
||||
}
|
||||
return dest->Elements();
|
||||
});
|
||||
|
||||
if (!ok) {
|
||||
// An error occurred, free any allocated backing buffer.
|
||||
dest->Clear();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
default:
|
||||
NS_ERROR("bad type");
|
||||
@ -1332,39 +1400,16 @@ XPCConvert::JSValToXPCException(MutableHandleValue s,
|
||||
|
||||
// array fun...
|
||||
|
||||
static bool
|
||||
ValidArrayType(const nsXPTType& type)
|
||||
{
|
||||
switch (type.Tag()) {
|
||||
// These types aren't allowed to be in arrays.
|
||||
case nsXPTType::T_VOID:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
case nsXPTType::T_CSTRING:
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_PSTRING_SIZE_IS:
|
||||
case nsXPTType::T_PWSTRING_SIZE_IS:
|
||||
case nsXPTType::T_ARRAY:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCConvert::NativeArray2JS(MutableHandleValue d, const void* const* s,
|
||||
XPCConvert::NativeArray2JS(MutableHandleValue d, const void* buf,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
uint32_t count, nsresult* pErr)
|
||||
{
|
||||
MOZ_ASSERT(s, "bad param");
|
||||
MOZ_ASSERT(buf || count == 0, "Must have buf or 0 elements");
|
||||
|
||||
AutoJSContext cx;
|
||||
|
||||
// XXX add support for putting chars in a string rather than an array
|
||||
|
||||
// XXX add support to indicate *which* array element was not convertable
|
||||
|
||||
RootedObject array(cx, JS_NewArrayObject(cx, count));
|
||||
if (!array)
|
||||
return false;
|
||||
@ -1372,12 +1417,9 @@ XPCConvert::NativeArray2JS(MutableHandleValue d, const void* const* s,
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
|
||||
|
||||
if (!ValidArrayType(type))
|
||||
return false;
|
||||
|
||||
RootedValue current(cx, JS::NullValue());
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (!NativeData2JS(¤t, type.ElementPtr(*s, i), type, iid, 0, pErr) ||
|
||||
if (!NativeData2JS(¤t, type.ElementPtr(buf, i), type, iid, 0, pErr) ||
|
||||
!JS_DefineElement(cx, array, i, current, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
@ -1388,223 +1430,125 @@ XPCConvert::NativeArray2JS(MutableHandleValue d, const void* const* s,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Fast conversion of typed arrays to native using memcpy.
|
||||
// No float or double canonicalization is done. Called by
|
||||
// JSarray2Native whenever a TypedArray is met. ArrayBuffers
|
||||
// are not accepted; create a properly typed array view on them
|
||||
// first. The element type of array must match the XPCOM
|
||||
// type in size, type and signedness exactly. As an exception,
|
||||
// Uint8ClampedArray is allowed for arrays of uint8_t. DataViews
|
||||
// are not supported.
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCConvert::JSTypedArray2Native(void** d,
|
||||
JSObject* jsArray,
|
||||
uint32_t count,
|
||||
const nsXPTType& type,
|
||||
nsresult* pErr)
|
||||
XPCConvert::JSArray2Native(JS::HandleValue aJSVal,
|
||||
const nsXPTType& aEltType,
|
||||
const nsIID* aIID,
|
||||
nsresult* pErr,
|
||||
const ArrayAllocFixupLen& aAllocFixupLen)
|
||||
{
|
||||
MOZ_ASSERT(jsArray, "bad param");
|
||||
MOZ_ASSERT(d, "bad param");
|
||||
MOZ_ASSERT(JS_IsTypedArrayObject(jsArray), "not a typed array");
|
||||
// Wrap aAllocFixupLen to check length is within bounds & initialize the
|
||||
// allocated memory if needed.
|
||||
auto allocFixupLen = [&] (uint32_t* aLength) -> void* {
|
||||
if (*aLength > (UINT32_MAX / aEltType.Stride())) {
|
||||
return nullptr; // Byte length doesn't fit in uint32_t
|
||||
}
|
||||
|
||||
// Check the actual length of the input array against the
|
||||
// given size_is.
|
||||
uint32_t len = JS_GetTypedArrayLength(jsArray);
|
||||
if (len < count) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
void* buf = aAllocFixupLen(aLength);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t expected;
|
||||
switch (JS_GetArrayBufferViewType(jsArray)) {
|
||||
case js::Scalar::Int8:
|
||||
expected = nsXPTType::T_I8;
|
||||
break;
|
||||
|
||||
case js::Scalar::Uint8:
|
||||
case js::Scalar::Uint8Clamped:
|
||||
expected = nsXPTType::T_U8;
|
||||
break;
|
||||
|
||||
case js::Scalar::Int16:
|
||||
expected = nsXPTType::T_I16;
|
||||
break;
|
||||
|
||||
case js::Scalar::Uint16:
|
||||
expected = nsXPTType::T_U16;
|
||||
break;
|
||||
|
||||
case js::Scalar::Int32:
|
||||
expected = nsXPTType::T_I32;
|
||||
break;
|
||||
|
||||
case js::Scalar::Uint32:
|
||||
expected = nsXPTType::T_U32;
|
||||
break;
|
||||
|
||||
case js::Scalar::Float32:
|
||||
expected = nsXPTType::T_FLOAT;
|
||||
break;
|
||||
|
||||
case js::Scalar::Float64:
|
||||
expected = nsXPTType::T_DOUBLE;
|
||||
break;
|
||||
|
||||
// Yet another array type was defined? It is not supported yet...
|
||||
default:
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the type we got is the type we expected.
|
||||
if (expected != type.Tag()) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the size would overflow uint32_t.
|
||||
if (count > (UINT32_MAX / type.Stride())) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the backing memory buffer to copy out of.
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
bool isShared;
|
||||
void* buf = JS_GetArrayBufferViewData(jsArray, &isShared, nogc);
|
||||
|
||||
// Require opting in to shared memory - a future project.
|
||||
if (isShared) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the buffer, and copy.
|
||||
*d = moz_xmalloc(count * type.Stride());
|
||||
if (!*d) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(*d, buf, count * type.Stride());
|
||||
|
||||
if (pErr)
|
||||
*pErr = NS_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCConvert::JSArray2Native(void** d, HandleValue s,
|
||||
uint32_t count, const nsXPTType& type,
|
||||
const nsID* iid, nsresult* pErr)
|
||||
{
|
||||
MOZ_ASSERT(d, "bad param");
|
||||
// Ensure the buffer has valid values for each element. We can skip this
|
||||
// for arithmetic types, as they do not require initialization.
|
||||
if (buf && !aEltType.IsArithmetic()) {
|
||||
for (uint32_t i = 0; i < *aLength; ++i) {
|
||||
InitializeValue(aEltType, aEltType.ElementPtr(buf, i));
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
};
|
||||
|
||||
AutoJSContext cx;
|
||||
|
||||
// FIXME: XPConnect historically has shortcut the JSArray2Native codepath in
|
||||
// its caller if count is 0, allowing arbitrary values to be passed as
|
||||
// arrays and interpreted as the empty array (bug 1458987).
|
||||
//
|
||||
// NOTE: Once this is fixed, null/undefined should be allowed for arrays if
|
||||
// count is 0.
|
||||
if (count == 0) {
|
||||
*d = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// XXX add support for getting chars from strings
|
||||
|
||||
// XXX add support to indicate *which* array element was not convertable
|
||||
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
if (!ValidArrayType(type))
|
||||
return false;
|
||||
|
||||
if (s.isNullOrUndefined()) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!s.isObject()) {
|
||||
// JSArray2Native only accepts objects (Array and TypedArray).
|
||||
if (!aJSVal.isObject()) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
|
||||
return false;
|
||||
}
|
||||
RootedObject jsarray(cx, &aJSVal.toObject());
|
||||
|
||||
RootedObject jsarray(cx, &s.toObject());
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
// If this is a typed array, then try a fast conversion with memcpy.
|
||||
if (JS_IsTypedArrayObject(jsarray)) {
|
||||
return JSTypedArray2Native(d, jsarray, count, type, pErr);
|
||||
// Fast conversion of typed arrays to native using memcpy. No float or
|
||||
// double canonicalization is done. ArrayBuffers are not accepted;
|
||||
// create a properly typed array view on them first. The element type of
|
||||
// array must match the XPCOM type in size, type and signedness exactly.
|
||||
// As an exception, Uint8ClampedArray is allowed for arrays of uint8_t.
|
||||
// DataViews are not supported.
|
||||
|
||||
nsXPTTypeTag tag;
|
||||
switch (JS_GetArrayBufferViewType(jsarray)) {
|
||||
case js::Scalar::Int8: tag = TD_INT8; break;
|
||||
case js::Scalar::Uint8: tag = TD_UINT8; break;
|
||||
case js::Scalar::Uint8Clamped: tag = TD_UINT8; break;
|
||||
case js::Scalar::Int16: tag = TD_INT16; break;
|
||||
case js::Scalar::Uint16: tag = TD_UINT16; break;
|
||||
case js::Scalar::Int32: tag = TD_INT32; break;
|
||||
case js::Scalar::Uint32: tag = TD_UINT32; break;
|
||||
case js::Scalar::Float32: tag = TD_FLOAT; break;
|
||||
case js::Scalar::Float64: tag = TD_DOUBLE; break;
|
||||
default: return false;
|
||||
}
|
||||
if (aEltType.Tag() != tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the backing buffer before getting the view data in case
|
||||
// allocFixupLen can cause GCs.
|
||||
uint32_t length = JS_GetTypedArrayLength(jsarray);
|
||||
void* buf = allocFixupLen(&length);
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the backing memory buffer to copy out of.
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
bool isShared = false;
|
||||
const void* data = JS_GetArrayBufferViewData(jsarray, &isShared, nogc);
|
||||
|
||||
// Require opting in to shared memory - a future project.
|
||||
if (isShared) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Directly copy data into the allocated target buffer.
|
||||
memcpy(buf, data, length * aEltType.Stride());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isArray;
|
||||
if (!JS_IsArrayObject(cx, jsarray, &isArray) || !isArray) {
|
||||
// If jsarray is not a TypedArrayObject, check for an Array object.
|
||||
uint32_t length = 0;
|
||||
bool isArray = false;
|
||||
if (!JS_IsArrayObject(cx, jsarray, &isArray) || !isArray ||
|
||||
!JS_GetArrayLength(cx, jsarray, &length)) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t len;
|
||||
if (!JS_GetArrayLength(cx, jsarray, &len) || len < count) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count > (UINT32_MAX / type.Stride())) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the destination array, and begin converting elements.
|
||||
*d = moz_xmalloc(count * type.Stride());
|
||||
if (!*d) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
void* buf = allocFixupLen(&length);
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Translate each array element separately.
|
||||
RootedValue current(cx);
|
||||
uint32_t initedCount;
|
||||
for (initedCount = 0; initedCount < count; ++initedCount) {
|
||||
if (!JS_GetElement(cx, jsarray, initedCount, ¤t) ||
|
||||
!JSData2Native(type.ElementPtr(*d, initedCount),
|
||||
current, type, iid, 0, pErr))
|
||||
break;
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
if (!JS_GetElement(cx, jsarray, i, ¤t) ||
|
||||
!JSData2Native(aEltType.ElementPtr(buf, i), current,
|
||||
aEltType, aIID, 0, pErr)) {
|
||||
// Array element conversion failed. Clean up all elements converted
|
||||
// before the error. Caller handles freeing 'buf'.
|
||||
for (uint32_t j = 0; j < i; ++j) {
|
||||
CleanupValue(aEltType, aEltType.ElementPtr(buf, j));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we handled every array element.
|
||||
if (initedCount == count) {
|
||||
if (pErr)
|
||||
*pErr = NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Something failed! Clean up after ourselves.
|
||||
for (uint32_t i = 0; i < initedCount; ++i) {
|
||||
CleanupValue(type, type.ElementPtr(*d, i));
|
||||
}
|
||||
free(*d);
|
||||
*d = nullptr;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
@ -1619,7 +1563,7 @@ xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
|
||||
MOZ_ASSERT(aArrayLen == 0 ||
|
||||
aType.Tag() == nsXPTType::T_PSTRING_SIZE_IS ||
|
||||
aType.Tag() == nsXPTType::T_PWSTRING_SIZE_IS ||
|
||||
aType.Tag() == nsXPTType::T_ARRAY,
|
||||
aType.Tag() == nsXPTType::T_LEGACY_ARRAY,
|
||||
"Array lengths may only appear for certain types!");
|
||||
|
||||
switch (aType.Tag()) {
|
||||
@ -1656,8 +1600,8 @@ xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
|
||||
free(*(void**)aValue);
|
||||
break;
|
||||
|
||||
// Array Types
|
||||
case nsXPTType::T_ARRAY:
|
||||
// Legacy Array Type
|
||||
case nsXPTType::T_LEGACY_ARRAY:
|
||||
{
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
void* elements = *(void**)aValue;
|
||||
@ -1668,10 +1612,69 @@ xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
|
||||
free(elements);
|
||||
break;
|
||||
}
|
||||
|
||||
// Array Type
|
||||
case nsXPTType::T_ARRAY:
|
||||
{
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
auto* array = (xpt::detail::UntypedTArray*)aValue;
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); ++i) {
|
||||
CleanupValue(elty, elty.ElementPtr(array->Elements(), i));
|
||||
}
|
||||
array->Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear the JS::Value to `undefined`
|
||||
case nsXPTType::T_JSVAL:
|
||||
((JS::Value*)aValue)->setUndefined();
|
||||
break;
|
||||
|
||||
// Non-arithmetic types requiring no cleanup
|
||||
case nsXPTType::T_VOID:
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown Type!");
|
||||
}
|
||||
|
||||
// Null out the pointer if we have it.
|
||||
if (aType.HasPointerRepr()) {
|
||||
*(void**)aValue = nullptr;
|
||||
// Clear any non-complex values to the valid '0' state.
|
||||
if (!aType.IsComplex()) {
|
||||
aType.ZeroValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// Implementation of xpc::InitializeValue.
|
||||
|
||||
void
|
||||
xpc::InitializeValue(const nsXPTType& aType, void* aValue)
|
||||
{
|
||||
switch (aType.Tag()) {
|
||||
// Types which require custom, specific initialization.
|
||||
case nsXPTType::T_JSVAL:
|
||||
new (aValue) JS::Value();
|
||||
MOZ_ASSERT(reinterpret_cast<JS::Value*>(aValue)->isUndefined());
|
||||
break;
|
||||
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
new (aValue) nsString();
|
||||
break;
|
||||
case nsXPTType::T_CSTRING:
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
new (aValue) nsCString();
|
||||
break;
|
||||
|
||||
case nsXPTType::T_ARRAY:
|
||||
new (aValue) xpt::detail::UntypedTArray();
|
||||
break;
|
||||
|
||||
// The remaining types all have valid states where all bytes are '0'.
|
||||
default:
|
||||
aType.ZeroValue(aValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +530,10 @@ xpc::CleanupValue(const nsXPTType& aType,
|
||||
// Check if we can do a cheap early return, and only perform the inner call
|
||||
// if we can't. We never have to clean up null pointer types or arithmetic
|
||||
// types.
|
||||
if (aType.IsArithmetic() || (aType.HasPointerRepr() && !*(void**)aValue)) {
|
||||
//
|
||||
// NOTE: We can skip zeroing arithmetic types in CleanupValue, as they are
|
||||
// already in a valid state.
|
||||
if (aType.IsArithmetic() || (aType.IsPointer() && !*(void**)aValue)) {
|
||||
return;
|
||||
}
|
||||
xpc::InnerCleanupValue(aType, aValue, aArrayLen);
|
||||
|
@ -672,7 +672,7 @@ nsXPCWrappedJSClass::GetArraySizeFromParam(const nsXPTMethodInfo* method,
|
||||
nsXPTCMiniVariant* nativeParams,
|
||||
uint32_t* result) const
|
||||
{
|
||||
if (type.Tag() != nsXPTType::T_ARRAY &&
|
||||
if (type.Tag() != nsXPTType::T_LEGACY_ARRAY &&
|
||||
type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
|
||||
type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
|
||||
*result = 0;
|
||||
@ -749,25 +749,27 @@ nsXPCWrappedJSClass::CleanupOutparams(const nsXPTMethodInfo* info,
|
||||
if (!param.IsOut())
|
||||
continue;
|
||||
|
||||
// Extract the array length so we can use it in CleanupValue.
|
||||
uint32_t arrayLen = 0;
|
||||
if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
|
||||
continue;
|
||||
|
||||
MOZ_ASSERT(param.IsIndirect(), "Outparams are always indirect");
|
||||
|
||||
// The inOutOnly flag is necessary because full outparams may contain
|
||||
// uninitialized junk before the call is made, and we don't want to try
|
||||
// to clean up uninitialized junk.
|
||||
if (!inOutOnly || param.IsIn()) {
|
||||
// Call 'CleanupValue' on parameters which we know to be initialized:
|
||||
// 1. Complex parameters (initialized by caller)
|
||||
// 2. 'inout' parameters (initialized by caller)
|
||||
// 3. 'out' parameters when 'inOutOnly' is 'false' (initialized by us)
|
||||
//
|
||||
// We skip non-complex 'out' parameters before the call, as they may
|
||||
// contain random junk.
|
||||
if (param.Type().IsComplex() || param.IsIn() || !inOutOnly) {
|
||||
uint32_t arrayLen = 0;
|
||||
if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
|
||||
continue;
|
||||
|
||||
xpc::CleanupValue(param.Type(), nativeParams[i].val.p, arrayLen);
|
||||
}
|
||||
|
||||
// Even if we didn't call CleanupValue, null out any pointers. This is
|
||||
// just to protect C++ callers which may read garbage if they forget to
|
||||
// check the error value.
|
||||
if (param.Type().HasPointerRepr()) {
|
||||
*(void**)nativeParams[i].val.p = nullptr;
|
||||
// Ensure our parameters are in a clean state. Complex values are always
|
||||
// handled by CleanupValue, and others have a valid null representation.
|
||||
if (!param.Type().IsComplex()) {
|
||||
param.Type().ZeroValue(nativeParams[i].val.p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1245,10 +1245,6 @@ CallMethodHelper::Call()
|
||||
CallMethodHelper::~CallMethodHelper()
|
||||
{
|
||||
for (nsXPTCVariant& param : mDispatchParams) {
|
||||
// Only clean up values which need cleanup.
|
||||
if (!param.DoesValNeedCleanup())
|
||||
continue;
|
||||
|
||||
uint32_t arraylen = 0;
|
||||
if (!GetArraySizeFromParam(param.type, UndefinedHandleValue, &arraylen))
|
||||
continue;
|
||||
@ -1262,7 +1258,7 @@ CallMethodHelper::GetArraySizeFromParam(const nsXPTType& type,
|
||||
HandleValue maybeArray,
|
||||
uint32_t* result)
|
||||
{
|
||||
if (type.Tag() != nsXPTType::T_ARRAY &&
|
||||
if (type.Tag() != nsXPTType::T_LEGACY_ARRAY &&
|
||||
type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
|
||||
type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
|
||||
*result = 0;
|
||||
@ -1477,25 +1473,39 @@ CallMethodHelper::InitializeDispatchParams()
|
||||
|
||||
mJSContextIndex = mMethodInfo->IndexOfJSContext();
|
||||
|
||||
// iterate through the params to clear flags (for safe cleanup later)
|
||||
for (uint8_t i = 0; i < paramCount + wantsJSContext + wantsOptArgc; i++) {
|
||||
nsXPTCVariant* dp = mDispatchParams.AppendElement();
|
||||
dp->ClearFlags();
|
||||
dp->val.p = nullptr;
|
||||
// Allocate enough space in mDispatchParams up-front.
|
||||
if (!mDispatchParams.AppendElements(paramCount + wantsJSContext + wantsOptArgc)) {
|
||||
Throw(NS_ERROR_OUT_OF_MEMORY, mCallContext);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill in the JSContext argument
|
||||
if (wantsJSContext) {
|
||||
nsXPTCVariant* dp = &mDispatchParams[mJSContextIndex];
|
||||
dp->type = nsXPTType::T_VOID;
|
||||
dp->val.p = mCallContext;
|
||||
}
|
||||
// Initialize each parameter to a valid state (for safe cleanup later).
|
||||
for (uint8_t i = 0, paramIdx = 0; i < mDispatchParams.Length(); i++) {
|
||||
nsXPTCVariant& dp = mDispatchParams[i];
|
||||
|
||||
// Fill in the optional_argc argument
|
||||
if (wantsOptArgc) {
|
||||
nsXPTCVariant* dp = &mDispatchParams[mOptArgcIndex];
|
||||
dp->type = nsXPTType::T_U8;
|
||||
dp->val.u8 = std::min<uint32_t>(mArgc, paramCount) - requiredArgs;
|
||||
if (i == mJSContextIndex) {
|
||||
// Fill in the JSContext argument
|
||||
dp.type = nsXPTType::T_VOID;
|
||||
dp.val.p = mCallContext;
|
||||
} else if (i == mOptArgcIndex) {
|
||||
// Fill in the optional_argc argument
|
||||
dp.type = nsXPTType::T_U8;
|
||||
dp.val.u8 = std::min<uint32_t>(mArgc, paramCount) - requiredArgs;
|
||||
} else {
|
||||
// Initialize normal arguments.
|
||||
const nsXPTParamInfo& param = mMethodInfo->Param(paramIdx);
|
||||
dp.type = param.Type();
|
||||
xpc::InitializeValue(dp.type, &dp.val);
|
||||
|
||||
// Specify the correct storage/calling semantics. This will also set
|
||||
// the `ptr` field to be self-referential.
|
||||
if (param.IsIndirect()) {
|
||||
dp.SetIndirect();
|
||||
}
|
||||
|
||||
// Advance to the next normal parameter.
|
||||
paramIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1522,40 +1532,8 @@ bool
|
||||
CallMethodHelper::ConvertIndependentParam(uint8_t i)
|
||||
{
|
||||
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
|
||||
const nsXPTType& type = paramInfo.GetType();
|
||||
const nsXPTType& type = paramInfo.Type();
|
||||
nsXPTCVariant* dp = GetDispatchParam(i);
|
||||
dp->type = type;
|
||||
MOZ_ASSERT(!paramInfo.IsShared(), "[shared] implies [noscript]!");
|
||||
|
||||
// Specify the correct storage/calling semantics.
|
||||
if (paramInfo.IsIndirect())
|
||||
dp->SetIndirect();
|
||||
|
||||
// Some types are always stored within the nsXPTCVariant, and passed
|
||||
// indirectly, regardless of in/out-ness. These types are stored in the
|
||||
// nsXPTCVariant's extended value.
|
||||
switch (type.Tag()) {
|
||||
// Ensure that the jsval has a valid value.
|
||||
case nsXPTType::T_JSVAL:
|
||||
new (&dp->ext.jsval) JS::Value();
|
||||
MOZ_ASSERT(dp->ext.jsval.isUndefined());
|
||||
break;
|
||||
|
||||
// Initialize our temporary string class values so they can be assigned
|
||||
// to by the XPCConvert logic.
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
new (&dp->ext.nsstr) nsString();
|
||||
break;
|
||||
case nsXPTType::T_CSTRING:
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
new (&dp->ext.nscstr) nsCString();
|
||||
break;
|
||||
}
|
||||
|
||||
// Flag cleanup for anything that isn't self-contained.
|
||||
if (!type.IsArithmetic())
|
||||
dp->SetValNeedsCleanup();
|
||||
|
||||
// Even if there's nothing to convert, we still need to examine the
|
||||
// JSObject container for out-params. If it's null or otherwise invalid,
|
||||
@ -1641,18 +1619,8 @@ bool
|
||||
CallMethodHelper::ConvertDependentParam(uint8_t i)
|
||||
{
|
||||
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
|
||||
const nsXPTType& type = paramInfo.GetType();
|
||||
|
||||
const nsXPTType& type = paramInfo.Type();
|
||||
nsXPTCVariant* dp = GetDispatchParam(i);
|
||||
dp->type = type;
|
||||
|
||||
// Specify the correct storage/calling semantics.
|
||||
if (paramInfo.IsIndirect())
|
||||
dp->SetIndirect();
|
||||
|
||||
// Make sure we clean up all of our dependent types. All of them require
|
||||
// allocations of some kind.
|
||||
dp->SetValNeedsCleanup();
|
||||
|
||||
// Even if there's nothing to convert, we still need to examine the
|
||||
// JSObject container for out-params. If it's null or otherwise invalid,
|
||||
@ -1712,14 +1680,18 @@ TraceParam(JSTracer* aTrc, void* aVal, const nsXPTType& aType,
|
||||
if (aType.Tag() == nsXPTType::T_JSVAL) {
|
||||
JS::UnsafeTraceRoot(aTrc, (JS::Value*)aVal,
|
||||
"XPCWrappedNative::CallMethod param");
|
||||
} else if (aType.Tag() == nsXPTType::T_ARRAY && *(void**)aVal) {
|
||||
} else if (aType.Tag() == nsXPTType::T_ARRAY) {
|
||||
auto* array = (xpt::detail::UntypedTArray*)aVal;
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
if (elty.Tag() != nsXPTType::T_JSVAL) {
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); ++i) {
|
||||
TraceParam(aTrc, elty.ElementPtr(array->Elements(), i), elty);
|
||||
}
|
||||
} else if (aType.Tag() == nsXPTType::T_LEGACY_ARRAY && *(void**)aVal) {
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
|
||||
for (uint32_t i = 0; i < aArrayLen; ++i) {
|
||||
TraceParam(aTrc, elty.ElementPtr(aVal, i), elty);
|
||||
TraceParam(aTrc, elty.ElementPtr(*(void**)aVal, i), elty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1729,9 +1701,8 @@ CallMethodHelper::trace(JSTracer* aTrc)
|
||||
{
|
||||
// We need to note each of our initialized parameters which contain jsvals.
|
||||
for (nsXPTCVariant& param : mDispatchParams) {
|
||||
if (!param.DoesValNeedCleanup()) {
|
||||
MOZ_ASSERT(param.type.Tag() != nsXPTType::T_JSVAL,
|
||||
"JSVals are marked as needing cleanup (even though they don't)");
|
||||
// We only need to trace parameters which have an innermost JSVAL.
|
||||
if (param.type.InnermostType().Tag() != nsXPTType::T_JSVAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1963,31 +1963,6 @@ public:
|
||||
// for the WN case. You probably want UnwrapReflectorToISupports.
|
||||
static bool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface);
|
||||
|
||||
/**
|
||||
* Convert a native array into a JS::Value.
|
||||
*
|
||||
* @param d [out] the resulting JS::Value
|
||||
* @param s the native array we're working with
|
||||
* @param type the type of objects in the array
|
||||
* @param iid the interface of each object in the array that we want
|
||||
* @param count the number of items in the array
|
||||
* @param scope the default scope to put on the new JSObjects' parent chain
|
||||
* @param pErr [out] relevant error code, if any.
|
||||
*/
|
||||
static bool NativeArray2JS(JS::MutableHandleValue d, const void* const* s,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
uint32_t count, nsresult* pErr);
|
||||
|
||||
static bool JSArray2Native(void** d, JS::HandleValue s,
|
||||
uint32_t count, const nsXPTType& type,
|
||||
const nsID* iid, nsresult* pErr);
|
||||
|
||||
static bool JSTypedArray2Native(void** d,
|
||||
JSObject* jsarray,
|
||||
uint32_t count,
|
||||
const nsXPTType& type,
|
||||
nsresult* pErr);
|
||||
|
||||
static nsresult JSValToXPCException(JS::MutableHandleValue s,
|
||||
const char* ifaceName,
|
||||
const char* methodName,
|
||||
@ -2002,6 +1977,40 @@ public:
|
||||
JS::Value* jsExceptionPtr);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Convert a native array into a JS::Value.
|
||||
*
|
||||
* @param d [out] the resulting JS::Value
|
||||
* @param buf the native buffer containing input values
|
||||
* @param type the type of objects in the array
|
||||
* @param iid the interface of each object in the array that we want
|
||||
* @param count the number of items in the array
|
||||
* @param scope the default scope to put on the new JSObjects' parent chain
|
||||
* @param pErr [out] relevant error code, if any.
|
||||
*/
|
||||
static bool NativeArray2JS(JS::MutableHandleValue d, const void* buf,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
uint32_t count, nsresult* pErr);
|
||||
|
||||
typedef std::function<void* (uint32_t*)> ArrayAllocFixupLen;
|
||||
|
||||
/**
|
||||
* Convert a JS::Value into a native array.
|
||||
*
|
||||
* @param aJSVal the JS::Value to convert
|
||||
* @param aEltType the type of objects in the array
|
||||
* @param aIID the interface of each object in the array
|
||||
* @param pErr [out] relevant error code, if any
|
||||
* @param aAllocFixupLen function called with the JS Array's length to
|
||||
* allocate the backing buffer. This function may
|
||||
* modify the length of array to be converted.
|
||||
*/
|
||||
static bool JSArray2Native(JS::HandleValue aJSVal,
|
||||
const nsXPTType& aEltType,
|
||||
const nsIID* aIID,
|
||||
nsresult* pErr,
|
||||
const ArrayAllocFixupLen& aAllocFixupLen);
|
||||
|
||||
XPCConvert() = delete;
|
||||
|
||||
};
|
||||
@ -3039,7 +3048,7 @@ nsIPrincipal* GetObjectPrincipal(JSObject* obj);
|
||||
// value : char[16_t]** (free)
|
||||
// TD_INTERFACE_TYPE, TD_INTERFACE_IS_TYPE
|
||||
// value : nsISupports** (release)
|
||||
// TD_ARRAY (NOTE: aArrayLen should be passed)
|
||||
// TD_LEGACY_ARRAY (NOTE: aArrayLen should be passed)
|
||||
// value : void** (cleanup elements & free)
|
||||
// TD_DOMOBJECT
|
||||
// value : T** (cleanup)
|
||||
@ -3060,6 +3069,17 @@ void InnerCleanupValue(const nsXPTType& aType,
|
||||
void* aValue,
|
||||
uint32_t aArrayLen);
|
||||
|
||||
// In order to be able to safely call CleanupValue on a generated value, the
|
||||
// data behind it needs to be initialized to a safe value. This method handles
|
||||
// initializing the backing data to a safe value to use as an argument to
|
||||
// XPCConvert methods, or xpc::CleanupValue.
|
||||
//
|
||||
// The pointer `aValue` must point to a block of memory at least aType.Stride()
|
||||
// bytes large, and correctly aligned.
|
||||
//
|
||||
// This method accepts the same types as xpc::CleanupValue.
|
||||
void InitializeValue(const nsXPTType& aType, void* aValue);
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -64,11 +64,19 @@ TestParams.prototype = {
|
||||
testAUTF8String: f,
|
||||
testACString: f,
|
||||
testJsval: f,
|
||||
testShortSequence: f,
|
||||
testDoubleSequence: f,
|
||||
testAStringSequence: f,
|
||||
testACStringSequence: f,
|
||||
testInterfaceSequence: f,
|
||||
testJsvalSequence: f,
|
||||
testInterfaceIsSequence: f_is,
|
||||
testShortArray: f_is,
|
||||
testDoubleArray: f_is,
|
||||
testStringArray: f_is,
|
||||
testWstringArray: f_is,
|
||||
testInterfaceArray: f_is,
|
||||
testJsvalArray: f_is,
|
||||
testSizedString: f_is,
|
||||
testSizedWstring: f_is,
|
||||
testInterfaceIs: f_is,
|
||||
|
@ -28,6 +28,14 @@ nsXPCTestParams::~nsXPCTestParams()
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
#define SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP) { \
|
||||
_retval.SwapElements(b); \
|
||||
b = a; \
|
||||
for (uint32_t i = 0; i < b.Length(); ++i) \
|
||||
TAKE_OWNERSHIP(b[i]); \
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
#define TAKE_OWNERSHIP_NOOP(val) {}
|
||||
#define TAKE_OWNERSHIP_INTERFACE(val) {static_cast<nsISupports*>(val)->AddRef();}
|
||||
#define TAKE_OWNERSHIP_STRING(val) { \
|
||||
@ -223,6 +231,13 @@ NS_IMETHODIMP nsXPCTestParams::TestInterfaceArray(uint32_t aLength, nsIXPCTestIn
|
||||
BUFFER_METHOD_IMPL(nsIXPCTestInterfaceA*, 0, TAKE_OWNERSHIP_INTERFACE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXPCTestParams::TestJsvalArray(uint32_t aLength, JS::Value *a,
|
||||
uint32_t* bLength, JS::Value **b,
|
||||
uint32_t* rvLength, JS::Value **rv)
|
||||
{
|
||||
BUFFER_METHOD_IMPL(JS::Value, 0, TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXPCTestParams::TestSizedString(uint32_t aLength, const char * a,
|
||||
uint32_t* bLength, char * *b,
|
||||
uint32_t* rvLength, char * *rv)
|
||||
@ -306,3 +321,68 @@ NS_IMETHODIMP nsXPCTestParams::TestStringArrayOptionalSize(const char * *a, uint
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestShortSequence(const nsTArray<short>& a, nsTArray<short>& b, nsTArray<short>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestDoubleSequence(const nsTArray<double>& a, nsTArray<double>& b, nsTArray<double>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestInterfaceSequence(const nsTArray<RefPtr<nsIXPCTestInterfaceA>>& a,
|
||||
nsTArray<RefPtr<nsIXPCTestInterfaceA>>& b,
|
||||
nsTArray<RefPtr<nsIXPCTestInterfaceA>>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestAStringSequence(const nsTArray<nsString>& a,
|
||||
nsTArray<nsString>& b,
|
||||
nsTArray<nsString>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestACStringSequence(const nsTArray<nsCString>& a,
|
||||
nsTArray<nsCString>& b,
|
||||
nsTArray<nsCString>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestJsvalSequence(const nsTArray<JS::Value>& a,
|
||||
nsTArray<JS::Value>& b,
|
||||
nsTArray<JS::Value>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestSequenceSequence(const nsTArray<nsTArray<short>>& a,
|
||||
nsTArray<nsTArray<short>>& b,
|
||||
nsTArray<nsTArray<short>>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestInterfaceIsSequence(const nsIID* aIID, const nsTArray<void*>& a,
|
||||
nsIID** bIID, nsTArray<void*>& b,
|
||||
nsIID** rvIID, nsTArray<void*>& _retval)
|
||||
{
|
||||
// Shuffle around our nsIIDs
|
||||
*rvIID = (*bIID)->Clone();
|
||||
*bIID = aIID->Clone();
|
||||
|
||||
// Perform the generic sequence shuffle.
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_INTERFACE);
|
||||
}
|
||||
|
@ -39,6 +39,19 @@ interface nsIXPCTestParams : nsISupports {
|
||||
ACString testACString(in ACString a, inout ACString b);
|
||||
jsval testJsval(in jsval a, inout jsval b);
|
||||
|
||||
// Test various forms of the Array<T> type.
|
||||
Array<short> testShortSequence(in Array<short> a, inout Array<short> b);
|
||||
Array<double> testDoubleSequence(in Array<double> a, inout Array<double> b);
|
||||
Array<nsIXPCTestInterfaceA> testInterfaceSequence(in Array<nsIXPCTestInterfaceA> a, inout Array<nsIXPCTestInterfaceA> b);
|
||||
Array<AString> testAStringSequence(in Array<AString> a, inout Array<AString> b);
|
||||
Array<ACString> testACStringSequence(in Array<ACString> a, inout Array<ACString> b);
|
||||
Array<jsval> testJsvalSequence(in Array<jsval> a, inout Array<jsval> b);
|
||||
Array<Array<short> > testSequenceSequence(in Array<Array<short> > a, inout Array<Array<short> > b);
|
||||
|
||||
void testInterfaceIsSequence(in nsIIDPtr aIID, [iid_is(aIID)] in Array<nsQIResult> a,
|
||||
inout nsIIDPtr bIID, [iid_is(bIID)] inout Array<nsQIResult> b,
|
||||
out nsIIDPtr rvIID, [retval, iid_is(rvIID)] out Array<nsQIResult> rv);
|
||||
|
||||
//
|
||||
// Dependent parameters use the same types as above, but are handled much differently.
|
||||
//
|
||||
@ -82,6 +95,12 @@ interface nsIXPCTestParams : nsISupports {
|
||||
out unsigned long rvLength, out nsIIDPtr rvIID,
|
||||
[retval, array, size_is(rvLength), iid_is(rvIID)] out nsQIResult rv);
|
||||
|
||||
// Test arrays of jsvals
|
||||
void testJsvalArray(in unsigned long aLength, [array, size_is(aLength)] in jsval a,
|
||||
inout unsigned long bLength, [array, size_is(bLength)] inout jsval b,
|
||||
out unsigned long rvLength, [retval, array, size_is(rvLength)] out jsval rv);
|
||||
|
||||
|
||||
// Test for out dipper parameters
|
||||
void testOutAString(out AString o);
|
||||
|
||||
|
@ -163,6 +163,8 @@ function test_component(contractid) {
|
||||
["we", "are", "being", "sooo", "international", "right", "now"], 7, arrayComparator(standardComparator));
|
||||
doIsTest("testInterfaceArray", [makeA(), makeA()], 2,
|
||||
[makeA(), makeA(), makeA(), makeA(), makeA(), makeA()], 6, arrayComparator(interfaceComparator));
|
||||
doIsTest("testJsvalArray", [{ cheese: 'whiz', apple: 8 }, [1, 5, '3'], /regex/], 3,
|
||||
['apple', 2.2e10, 3.3e30, { only: "wheedle", except: {} }], 4, arrayComparator(standardComparator));
|
||||
|
||||
// Test typed arrays and ArrayBuffer aliasing.
|
||||
var arrayBuffer = new ArrayBuffer(16);
|
||||
@ -195,4 +197,24 @@ function test_component(contractid) {
|
||||
// Test type mismatch (int16 <-> uint16); this should throw BAD_CONVERT_JS.
|
||||
doTypedArrayMismatchTest("testShortArray", new Uint16Array([0, 7, 4, 3]), 4,
|
||||
new Uint16Array([1, 5, 6]), 3);
|
||||
|
||||
// Test Sequence<T> types.
|
||||
doTest("testShortSequence", [2, 4, 6], [1, 3, 5, 7], arrayComparator(standardComparator));
|
||||
doTest("testDoubleSequence", [-10, -0.5], [1, 3, 1e11, -8e-5 ], arrayComparator(fuzzComparator));
|
||||
doTest("testACStringSequence", ["mary", "hat", "hey", "lid", "tell", "lam"],
|
||||
["ids", "fleas", "woes", "wide", "has", "know", "!"],
|
||||
arrayComparator(standardComparator));
|
||||
doTest("testAStringSequence", ["沒有語言", "的偉大嗎?]"],
|
||||
["we", "are", "being", "sooo", "international", "right", "now"],
|
||||
arrayComparator(standardComparator));
|
||||
|
||||
doTest("testInterfaceSequence", [makeA(), makeA()],
|
||||
[makeA(), makeA(), makeA(), makeA(), makeA(), makeA()], arrayComparator(interfaceComparator));
|
||||
|
||||
doTest("testJsvalSequence", [{ cheese: 'whiz', apple: 8 }, [1, 5, '3'], /regex/],
|
||||
['apple', 2.2e10, 3.3e30, { only: "wheedle", except: {} }], arrayComparator(standardComparator));
|
||||
|
||||
doIsTest("testInterfaceIsSequence", [makeA(), makeA(), makeA(), makeA(), makeA()], Ci['nsIXPCTestInterfaceA'],
|
||||
[makeB(), makeB(), makeB()], Ci['nsIXPCTestInterfaceB'],
|
||||
arrayComparator(interfaceComparator), dotEqualsComparator);
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||skiaContent,1,800000) == ma
|
||||
== marker-effects-01.svg marker-effects-01-ref.svg
|
||||
fuzzy-if(skiaContent,1,100) == marker-viewBox-01.svg marker-viewBox-01-ref.svg
|
||||
fuzzy-if(skiaContent,1,100) == marker-orientation-01.svg marker-orientation-01-ref.svg
|
||||
fuzzy-if(skiaContent,1,5) pref(svg.marker-improvements.enabled,true) == marker-orientation-02.svg marker-orientation-02-ref.svg
|
||||
fuzzy-if(skiaContent,1,5) == marker-orientation-02.svg marker-orientation-02-ref.svg
|
||||
== marker-orientation-03.svg pass.svg
|
||||
== marker-orientation-04.svg pass.svg
|
||||
|
||||
@ -551,4 +551,4 @@ fuzzy-if(skiaContent,1,100) == tspan-xy-anchor-end-01.svg tspan-xy-anchor-end-re
|
||||
# currentColor override by color attribute
|
||||
== currentColor-override-flood.svg pass.svg
|
||||
== currentColor-override-lighting.svg currentColor-override-lighting-ref.svg
|
||||
== currentColor-override-stop.svg pass.svg
|
||||
== currentColor-override-stop.svg pass.svg
|
||||
|
@ -78,6 +78,8 @@ enum class StyleAppearance : uint8_t {
|
||||
Meterbar,
|
||||
// The meter bar's meter indicator.
|
||||
Meterchunk,
|
||||
// The dropdown button(s) that open up a dropdown list.
|
||||
MozMenulistButton,
|
||||
// For HTML's <input type=number>
|
||||
NumberInput,
|
||||
// A horizontal progress bar.
|
||||
|
@ -284,7 +284,7 @@ select > button {
|
||||
background-image: url("arrow.gif") !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-position: center !important;
|
||||
-moz-appearance: menulist-button;
|
||||
-moz-appearance: -moz-menulist-button;
|
||||
|
||||
/* Make sure to size correctly if the combobox has a non-auto height. */
|
||||
block-size: 100% ! important;
|
||||
|
@ -16,6 +16,9 @@ const NON_CONTENT_ACCESSIBLE_VALUES = {
|
||||
"-moz-popup",
|
||||
"-moz-groupbox",
|
||||
],
|
||||
"-moz-appearance": [
|
||||
"-moz-menulist-button",
|
||||
],
|
||||
};
|
||||
|
||||
if (!SpecialPowers.getBoolPref("layout.css.xul-box-display-values.content.enabled")) {
|
||||
|
@ -30,18 +30,17 @@
|
||||
#endif
|
||||
|
||||
#include "nscore.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/FastBernoulliTrial.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/HashTable.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/JSONWriter.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
// CodeAddressService is defined entirely in the header, so this does not make
|
||||
// DMD depend on XPCOM's object file.
|
||||
@ -96,8 +95,8 @@ static malloc_table_t gMallocTable;
|
||||
//
|
||||
// - Direct allocations (the easy case).
|
||||
//
|
||||
// - Indirect allocations in js::{Vector,HashSet,HashMap} -- this class serves
|
||||
// as their AllocPolicy.
|
||||
// - Indirect allocations in mozilla::{Vector,HashSet,HashMap} -- this class
|
||||
// serves as their AllocPolicy.
|
||||
//
|
||||
// - Other indirect allocations (e.g. MozStackWalk) -- see the comments on
|
||||
// Thread::mBlockIntercepts and in replace_malloc for how these work.
|
||||
@ -162,7 +161,6 @@ public:
|
||||
return p;
|
||||
}
|
||||
|
||||
// This realloc_ is the one we use for direct reallocs within DMD.
|
||||
static void* realloc_(void* aPtr, size_t aNewSize)
|
||||
{
|
||||
void* p = gMallocTable.realloc(aPtr, aNewSize);
|
||||
@ -170,7 +168,6 @@ public:
|
||||
return p;
|
||||
}
|
||||
|
||||
// This realloc_ is required for this to be a JS container AllocPolicy.
|
||||
template <typename T>
|
||||
static T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
|
||||
{
|
||||
@ -621,7 +618,7 @@ private:
|
||||
{
|
||||
typedef const char* Lookup;
|
||||
|
||||
static uint32_t hash(const char* const& aS)
|
||||
static mozilla::HashNumber hash(const char* const& aS)
|
||||
{
|
||||
return HashString(aS);
|
||||
}
|
||||
@ -632,7 +629,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
typedef js::HashSet<const char*, StringHasher, InfallibleAllocPolicy> StringHashSet;
|
||||
typedef mozilla::HashSet<const char*, StringHasher, InfallibleAllocPolicy>
|
||||
StringHashSet;
|
||||
|
||||
StringHashSet mSet;
|
||||
};
|
||||
@ -693,7 +691,7 @@ public:
|
||||
|
||||
typedef StackTrace* Lookup;
|
||||
|
||||
static uint32_t hash(const StackTrace* const& aSt)
|
||||
static mozilla::HashNumber hash(const StackTrace* const& aSt)
|
||||
{
|
||||
return mozilla::HashBytes(aSt->mPcs, aSt->Size());
|
||||
}
|
||||
@ -717,19 +715,21 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
typedef js::HashSet<StackTrace*, StackTrace, InfallibleAllocPolicy>
|
||||
typedef mozilla::HashSet<StackTrace*, StackTrace, InfallibleAllocPolicy>
|
||||
StackTraceTable;
|
||||
static StackTraceTable* gStackTraceTable = nullptr;
|
||||
|
||||
typedef js::HashSet<const StackTrace*, js::DefaultHasher<const StackTrace*>,
|
||||
InfallibleAllocPolicy>
|
||||
typedef mozilla::HashSet<const StackTrace*,
|
||||
mozilla::DefaultHasher<const StackTrace*>,
|
||||
InfallibleAllocPolicy>
|
||||
StackTraceSet;
|
||||
|
||||
typedef js::HashSet<const void*, js::DefaultHasher<const void*>,
|
||||
InfallibleAllocPolicy>
|
||||
typedef mozilla::HashSet<const void*, mozilla::DefaultHasher<const void*>,
|
||||
InfallibleAllocPolicy>
|
||||
PointerSet;
|
||||
typedef js::HashMap<const void*, uint32_t, js::DefaultHasher<const void*>,
|
||||
InfallibleAllocPolicy>
|
||||
typedef mozilla::HashMap<const void*, uint32_t,
|
||||
mozilla::DefaultHasher<const void*>,
|
||||
InfallibleAllocPolicy>
|
||||
PointerIdMap;
|
||||
|
||||
// We won't GC the stack trace table until it this many elements.
|
||||
@ -992,7 +992,7 @@ public:
|
||||
|
||||
typedef const void* Lookup;
|
||||
|
||||
static uint32_t hash(const void* const& aPtr)
|
||||
static mozilla::HashNumber hash(const void* const& aPtr)
|
||||
{
|
||||
return mozilla::HashGeneric(aPtr);
|
||||
}
|
||||
@ -1004,7 +1004,8 @@ public:
|
||||
};
|
||||
|
||||
// A table of live blocks where the lookup key is the block address.
|
||||
typedef js::HashSet<LiveBlock, LiveBlock, InfallibleAllocPolicy> LiveBlockTable;
|
||||
typedef mozilla::HashSet<LiveBlock, LiveBlock, InfallibleAllocPolicy>
|
||||
LiveBlockTable;
|
||||
static LiveBlockTable* gLiveBlockTable = nullptr;
|
||||
|
||||
class AggregatedLiveBlockHashPolicy
|
||||
@ -1012,7 +1013,7 @@ class AggregatedLiveBlockHashPolicy
|
||||
public:
|
||||
typedef const LiveBlock* const Lookup;
|
||||
|
||||
static uint32_t hash(const LiveBlock* const& aB)
|
||||
static mozilla::HashNumber hash(const LiveBlock* const& aB)
|
||||
{
|
||||
return gOptions->IsDarkMatterMode()
|
||||
? mozilla::HashGeneric(aB->ReqSize(),
|
||||
@ -1041,8 +1042,8 @@ public:
|
||||
|
||||
// A table of live blocks where the lookup key is everything but the block
|
||||
// address. For aggregating similar live blocks at output time.
|
||||
typedef js::HashMap<const LiveBlock*, size_t, AggregatedLiveBlockHashPolicy,
|
||||
InfallibleAllocPolicy>
|
||||
typedef mozilla::HashMap<const LiveBlock*, size_t,
|
||||
AggregatedLiveBlockHashPolicy, InfallibleAllocPolicy>
|
||||
AggregatedLiveBlockTable;
|
||||
|
||||
// A freed heap block.
|
||||
@ -1088,7 +1089,7 @@ public:
|
||||
|
||||
typedef DeadBlock Lookup;
|
||||
|
||||
static uint32_t hash(const DeadBlock& aB)
|
||||
static mozilla::HashNumber hash(const DeadBlock& aB)
|
||||
{
|
||||
return mozilla::HashGeneric(aB.ReqSize(),
|
||||
aB.SlopSize(),
|
||||
@ -1105,7 +1106,7 @@ public:
|
||||
|
||||
// For each unique DeadBlock value we store a count of how many actual dead
|
||||
// blocks have that value.
|
||||
typedef js::HashMap<DeadBlock, size_t, DeadBlock, InfallibleAllocPolicy>
|
||||
typedef mozilla::HashMap<DeadBlock, size_t, DeadBlock, InfallibleAllocPolicy>
|
||||
DeadBlockTable;
|
||||
static DeadBlockTable* gDeadBlockTable = nullptr;
|
||||
|
||||
|
3499
mfbt/HashTable.h
3499
mfbt/HashTable.h
File diff suppressed because it is too large
Load Diff
@ -3279,9 +3279,6 @@ pref("browser.tabs.remote.separatePrivilegedContentProcess", false);
|
||||
pref("svg.display-lists.hit-testing.enabled", true);
|
||||
pref("svg.display-lists.painting.enabled", true);
|
||||
|
||||
// Is support for the <marker orient="auto-start-reverse"> feature enabled?
|
||||
pref("svg.marker-improvements.enabled", true);
|
||||
|
||||
// Is support for the new getBBox method from SVG 2 enabled?
|
||||
// See https://svgwg.org/svg2-draft/single-page.html#types-SVGBoundingBoxOptions
|
||||
pref("svg.new-getBBox.enabled", false);
|
||||
|
@ -122,6 +122,14 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(_M_IX86)
|
||||
bool WriteAtomic(void* aDestPtr, const uint16_t aValue) const
|
||||
{
|
||||
*static_cast<uint16_t*>(aDestPtr) = aValue;
|
||||
return true;
|
||||
}
|
||||
#endif // defined(_M_IX86)
|
||||
|
||||
bool Protect(void* aVAddress, size_t aSize, uint32_t aProtFlags,
|
||||
uint32_t* aPrevProtFlags) const
|
||||
{
|
||||
|
@ -51,8 +51,7 @@ public:
|
||||
}
|
||||
|
||||
// mov edi, edi
|
||||
fn.WriteShort(0xff8b);
|
||||
fn.Commit();
|
||||
fn.CommitAndWriteShort(0xff8b);
|
||||
}
|
||||
|
||||
mPatchedFns.clear();
|
||||
@ -206,8 +205,7 @@ public:
|
||||
sizeof(uint16_t));
|
||||
|
||||
// Short jump up into our long jump.
|
||||
writableFn.WriteShort(0xF9EB); // jmp $-5
|
||||
return writableFn.Commit();
|
||||
return writableFn.CommitAndWriteShort(0xF9EB); // jmp $-5
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -177,6 +177,9 @@ public:
|
||||
}
|
||||
|
||||
mMMPolicy.FlushInstructionCache();
|
||||
|
||||
mStartWriteOffset += mLocalBytes.length();
|
||||
|
||||
mLocalBytes.clear();
|
||||
return true;
|
||||
}
|
||||
@ -228,6 +231,53 @@ public:
|
||||
mOffset += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
#if defined(_M_IX86)
|
||||
private:
|
||||
template <typename T>
|
||||
bool CommitAndWriteShortInternal(const T& aMMPolicy, void* aDest, uint16_t aValue);
|
||||
|
||||
template <>
|
||||
bool CommitAndWriteShortInternal<MMPolicyInProcess>(const MMPolicyInProcess& aMMPolicy,
|
||||
void* aDest, uint16_t aValue)
|
||||
{
|
||||
return aMMPolicy.WriteAtomic(aDest, aValue);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool CommitAndWriteShortInternal<MMPolicyOutOfProcess>(const MMPolicyOutOfProcess& aMMPolicy,
|
||||
void* aDest, uint16_t aValue)
|
||||
{
|
||||
return aMMPolicy.Write(aDest, &aValue, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Commits any dirty writes, and then writes a short, atomically if possible.
|
||||
* This call may succeed in both inproc and outproc cases, but atomicity
|
||||
* is only guaranteed in the inproc case.
|
||||
*/
|
||||
bool CommitAndWriteShort(const uint16_t aValue)
|
||||
{
|
||||
// First, commit everything that has been written until now
|
||||
if (!Commit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now immediately write the short, atomically if inproc
|
||||
bool ok = CommitAndWriteShortInternal(mMMPolicy,
|
||||
reinterpret_cast<void*>(mFunc +
|
||||
mStartWriteOffset),
|
||||
aValue);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mMMPolicy.FlushInstructionCache();
|
||||
mStartWriteOffset += sizeof(uint16_t);
|
||||
return true;
|
||||
}
|
||||
#endif // defined(_M_IX86)
|
||||
|
||||
void WriteDisp32(const uintptr_t aAbsTarget)
|
||||
{
|
||||
intptr_t diff = static_cast<intptr_t>(aAbsTarget) -
|
||||
|
@ -82,6 +82,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
, mInitialSecurityCheckDone(false)
|
||||
, mIsThirdPartyContext(false)
|
||||
, mIsDocshellReload(false)
|
||||
, mSendCSPViolationEvents(true)
|
||||
, mForcePreflight(false)
|
||||
, mIsPreflight(false)
|
||||
, mLoadTriggeredFromExternal(false)
|
||||
@ -315,6 +316,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
|
||||
, mInitialSecurityCheckDone(false)
|
||||
, mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party.
|
||||
, mIsDocshellReload(false)
|
||||
, mSendCSPViolationEvents(true)
|
||||
, mForcePreflight(false)
|
||||
, mIsPreflight(false)
|
||||
, mLoadTriggeredFromExternal(false)
|
||||
@ -401,6 +403,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
|
||||
, mInitialSecurityCheckDone(rhs.mInitialSecurityCheckDone)
|
||||
, mIsThirdPartyContext(rhs.mIsThirdPartyContext)
|
||||
, mIsDocshellReload(rhs.mIsDocshellReload)
|
||||
, mSendCSPViolationEvents(rhs.mSendCSPViolationEvents)
|
||||
, mOriginAttributes(rhs.mOriginAttributes)
|
||||
, mRedirectChainIncludingInternalRedirects(
|
||||
rhs.mRedirectChainIncludingInternalRedirects)
|
||||
@ -447,6 +450,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
bool aInitialSecurityCheckDone,
|
||||
bool aIsThirdPartyContext,
|
||||
bool aIsDocshellReload,
|
||||
bool aSendCSPViolationEvents,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
RedirectHistoryArray& aRedirectChainIncludingInternalRedirects,
|
||||
RedirectHistoryArray& aRedirectChain,
|
||||
@ -488,6 +492,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
, mInitialSecurityCheckDone(aInitialSecurityCheckDone)
|
||||
, mIsThirdPartyContext(aIsThirdPartyContext)
|
||||
, mIsDocshellReload(aIsDocshellReload)
|
||||
, mSendCSPViolationEvents(aSendCSPViolationEvents)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
, mAncestorPrincipals(std::move(aAncestorPrincipals))
|
||||
, mAncestorOuterWindowIDs(aAncestorOuterWindowIDs)
|
||||
@ -839,6 +844,20 @@ LoadInfo::SetIsDocshellReload(bool aValue)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetSendCSPViolationEvents(bool* aResult)
|
||||
{
|
||||
*aResult = mSendCSPViolationEvents;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetSendCSPViolationEvents(bool aValue)
|
||||
{
|
||||
mSendCSPViolationEvents = aValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetExternalContentPolicyType(nsContentPolicyType* aResult)
|
||||
{
|
||||
|
@ -124,6 +124,7 @@ private:
|
||||
bool aInitialSecurityCheckDone,
|
||||
bool aIsThirdPartyRequest,
|
||||
bool aIsDocshellReload,
|
||||
bool aSendCSPViolationEvents,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
RedirectHistoryArray& aRedirectChainIncludingInternalRedirects,
|
||||
RedirectHistoryArray& aRedirectChain,
|
||||
@ -194,6 +195,7 @@ private:
|
||||
bool mInitialSecurityCheckDone;
|
||||
bool mIsThirdPartyContext;
|
||||
bool mIsDocshellReload;
|
||||
bool mSendCSPViolationEvents;
|
||||
OriginAttributes mOriginAttributes;
|
||||
RedirectHistoryArray mRedirectChainIncludingInternalRedirects;
|
||||
RedirectHistoryArray mRedirectChain;
|
||||
|
@ -502,6 +502,12 @@ interface nsILoadInfo : nsISupports
|
||||
*/
|
||||
readonly attribute nsContentPolicyType externalContentPolicyType;
|
||||
|
||||
/**
|
||||
* CSP uses this parameter to send or not CSP violation events.
|
||||
* Default value: true.
|
||||
*/
|
||||
[infallible] attribute boolean sendCSPViolationEvents;
|
||||
|
||||
%{ C++
|
||||
inline nsContentPolicyType GetExternalContentPolicyType()
|
||||
{
|
||||
|
@ -65,6 +65,7 @@ struct LoadInfoArgs
|
||||
bool initialSecurityCheckDone;
|
||||
bool isInThirdPartyContext;
|
||||
bool isDocshellReload;
|
||||
bool sendCSPViolationEvents;
|
||||
OriginAttributes originAttributes;
|
||||
RedirectHistoryEntryInfo[] redirectChainIncludingInternalRedirects;
|
||||
RedirectHistoryEntryInfo[] redirectChain;
|
||||
|
@ -515,7 +515,6 @@ ${helpers.predefined_type(
|
||||
products="gecko",
|
||||
alias="-webkit-appearance:layout.css.webkit-appearance.enabled",
|
||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)",
|
||||
needs_context=False,
|
||||
animation_value_type="discrete",
|
||||
)}
|
||||
|
||||
|
@ -20,11 +20,16 @@ use values::specified::{AllowQuirks, Number};
|
||||
use values::specified::length::{LengthOrPercentage, NonNegativeLength};
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn moz_display_values_enabled(context: &ParserContext) -> bool {
|
||||
use gecko_bindings::structs;
|
||||
fn in_ua_or_chrome_sheet(context: &ParserContext) -> bool {
|
||||
use stylesheets::Origin;
|
||||
context.stylesheet_origin == Origin::UserAgent ||
|
||||
context.chrome_rules_enabled() ||
|
||||
context.chrome_rules_enabled()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn moz_display_values_enabled(context: &ParserContext) -> bool {
|
||||
use gecko_bindings::structs;
|
||||
in_ua_or_chrome_sheet(context) ||
|
||||
unsafe {
|
||||
structs::StaticPrefs_sVarCache_layout_css_xul_display_values_content_enabled
|
||||
}
|
||||
@ -33,9 +38,7 @@ fn moz_display_values_enabled(context: &ParserContext) -> bool {
|
||||
#[cfg(feature = "gecko")]
|
||||
fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
|
||||
use gecko_bindings::structs;
|
||||
use stylesheets::Origin;
|
||||
context.stylesheet_origin == Origin::UserAgent ||
|
||||
context.chrome_rules_enabled() ||
|
||||
in_ua_or_chrome_sheet(context) ||
|
||||
unsafe {
|
||||
structs::StaticPrefs_sVarCache_layout_css_xul_box_display_values_content_enabled
|
||||
}
|
||||
@ -948,6 +951,9 @@ pub enum Appearance {
|
||||
Meterbar,
|
||||
/// The meter bar's meter indicator.
|
||||
Meterchunk,
|
||||
/// The "arrowed" part of the dropdown button that open up a dropdown list.
|
||||
#[parse(condition = "in_ua_or_chrome_sheet")]
|
||||
MozMenulistButton,
|
||||
/// For HTML's <input type=number>
|
||||
NumberInput,
|
||||
/// A horizontal progress bar.
|
||||
|
@ -42,6 +42,10 @@ jobs:
|
||||
- releases/bouncer_firefox_beta.py
|
||||
mozilla-release:
|
||||
- releases/bouncer_firefox_release.py
|
||||
mozilla-esr60:
|
||||
- releases/bouncer_firefox_esr.py
|
||||
jamun:
|
||||
- releases/dev_bouncer_firefox_esr.py
|
||||
default:
|
||||
- releases/dev_bouncer_firefox_beta.py
|
||||
product-field:
|
||||
|
@ -30,8 +30,10 @@ jobs:
|
||||
by-project:
|
||||
maple: [32]
|
||||
birch: [145]
|
||||
jamun: [724]
|
||||
mozilla-beta: [32]
|
||||
mozilla-release: [145]
|
||||
mozilla-esr60: [806]
|
||||
default: []
|
||||
treeherder:
|
||||
platform: firefox-release/opt
|
||||
|
@ -28,32 +28,40 @@ jobs:
|
||||
by-project:
|
||||
mozilla-beta: archive.mozilla.org
|
||||
mozilla-release: archive.mozilla.org
|
||||
mozilla-esr60: archive.mozilla.org
|
||||
default: ftp.stage.mozaws.net
|
||||
download-domain:
|
||||
by-project:
|
||||
mozilla-beta: download.mozilla.org
|
||||
mozilla-release: download.mozilla.org
|
||||
mozilla-esr60: download.mozilla.org
|
||||
default: download.mozilla.org
|
||||
channel-names:
|
||||
by-project:
|
||||
maple: ["beta", "beta-localtest", "beta-cdntest"]
|
||||
birch: ["release", "release-localtest", "release-cdntest"]
|
||||
jamun: ["esr", "esr-localtest", "esr-cdntest"]
|
||||
mozilla-beta: ["beta", "beta-localtest", "beta-cdntest"]
|
||||
mozilla-release: ["release", "release-localtest", "release-cdntest"]
|
||||
mozilla-esr60: ["esr", "esr-localtest", "esr-cdntest"]
|
||||
default: []
|
||||
publish-rules:
|
||||
by-project:
|
||||
maple: [32]
|
||||
birch: [145]
|
||||
jamun: [724]
|
||||
mozilla-beta: [32]
|
||||
mozilla-release: [145]
|
||||
mozilla-esr60: [806]
|
||||
default: []
|
||||
rules-to-update:
|
||||
by-project:
|
||||
maple: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
||||
birch: ["firefox-release-cdntest", "firefox-release-localtest"]
|
||||
jamun: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
||||
mozilla-beta: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
||||
mozilla-release: ["firefox-release-cdntest", "firefox-release-localtest"]
|
||||
mozilla-esr60: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
||||
default: []
|
||||
platforms: ["linux", "linux64", "macosx64", "win32", "win64"]
|
||||
treeherder:
|
||||
|
@ -14,6 +14,7 @@ job-defaults:
|
||||
by-project:
|
||||
mozilla-beta: scriptworker-prov-v1/bouncer-v1
|
||||
mozilla-release: scriptworker-prov-v1/bouncer-v1
|
||||
mozilla-esr60: scriptworker-prov-v1/bouncer-v1
|
||||
default: scriptworker-prov-v1/bouncer-dev
|
||||
worker:
|
||||
implementation: bouncer-submission
|
||||
|
@ -59,7 +59,7 @@ jobs:
|
||||
run:
|
||||
extra-config:
|
||||
by-project:
|
||||
mozilla-(release|beta):
|
||||
mozilla-(release|beta|esr.*):
|
||||
stage_product: "firefox"
|
||||
bucket_name: "net-mozaws-prod-delivery-firefox"
|
||||
default:
|
||||
|
@ -32,7 +32,9 @@ jobs:
|
||||
channel-names:
|
||||
by-project:
|
||||
birch: ["beta", "beta-localtest", "beta-cdntest"]
|
||||
jamun: ["esr", "esr-localtest", "esr-cdntest"]
|
||||
mozilla-release: ["beta", "beta-localtest", "beta-cdntest"]
|
||||
mozilla-esr60: ["esr", "esr-localtest", "esr-cdntest"]
|
||||
default: []
|
||||
publish-rules:
|
||||
by-project:
|
||||
@ -42,7 +44,9 @@ jobs:
|
||||
rules-to-update:
|
||||
by-project:
|
||||
birch: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
||||
jamun: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
||||
mozilla-release: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
||||
mozilla-esr60: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
||||
default: []
|
||||
treeherder:
|
||||
platform: linux64/opt
|
||||
|
@ -28,25 +28,33 @@ jobs:
|
||||
archive-domain:
|
||||
by-project:
|
||||
mozilla-release: archive.mozilla.org
|
||||
mozilla-esr60: archive.mozilla.org
|
||||
default: ftp.stage.mozaws.net
|
||||
download-domain:
|
||||
by-project:
|
||||
mozilla-release: download.mozilla.org
|
||||
mozilla-esr60: download.mozilla.org
|
||||
default: download.mozilla.org
|
||||
channel-names:
|
||||
by-project:
|
||||
birch: ["beta", "beta-localtest", "beta-cdntest"]
|
||||
jamun: ["esr", "esr-localtest", "esr-cdntest"]
|
||||
mozilla-release: ["beta", "beta-localtest", "beta-cdntest"]
|
||||
mozilla-esr60: ["esr", "esr-localtest", "esr-cdntest"]
|
||||
default: []
|
||||
publish-rules:
|
||||
by-project:
|
||||
birch: [32]
|
||||
jamun: [724]
|
||||
mozilla-release: [32]
|
||||
mozilla-esr60: []
|
||||
default: []
|
||||
rules-to-update:
|
||||
by-project:
|
||||
birch: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
||||
jamun: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
||||
mozilla-release: ["firefox-beta-cdntest", "firefox-beta-localtest"]
|
||||
mozilla-esr60: ["firefox-esr60-cdntest", "firefox-esr60-localtest"]
|
||||
default: []
|
||||
treeherder:
|
||||
platform: linux64/opt
|
||||
|
@ -54,7 +54,7 @@ job-defaults:
|
||||
include-version:
|
||||
by-project:
|
||||
birch: nonbeta
|
||||
jamun: beta
|
||||
jamun: esr
|
||||
maple: beta
|
||||
mozilla-beta: beta
|
||||
mozilla-release: nonbeta
|
||||
|
@ -42,6 +42,10 @@ job-defaults:
|
||||
- "browser/config/version.txt"
|
||||
- "browser/config/version_display.txt"
|
||||
- "config/milestone.txt"
|
||||
jamun:
|
||||
- "browser/config/version.txt"
|
||||
- "browser/config/version_display.txt"
|
||||
- "config/milestone.txt"
|
||||
push:
|
||||
by-project:
|
||||
mozilla-beta: true
|
||||
@ -50,6 +54,7 @@ job-defaults:
|
||||
mozilla-esr60: true
|
||||
maple: true
|
||||
birch: true
|
||||
jamun: true
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
|
@ -87,7 +87,7 @@ PER_PROJECT_PARAMETERS = {
|
||||
},
|
||||
|
||||
'comm-esr60': {
|
||||
'target_tasks_method': 'mozilla_beta_tasks',
|
||||
'target_tasks_method': 'mozilla_esr60_tasks',
|
||||
'optimize_target_tasks': True,
|
||||
'include_nightly': True,
|
||||
},
|
||||
|
@ -21,6 +21,7 @@ RELEASE_PROJECTS = {
|
||||
'mozilla-esr60',
|
||||
'comm-central',
|
||||
'comm-beta',
|
||||
'comm-esr60',
|
||||
}
|
||||
|
||||
RELEASE_PROMOTION_PROJECTS = {
|
||||
|
@ -46,7 +46,9 @@ SIGNING_SCOPE_ALIAS_TO_PROJECT = [[
|
||||
'all-release-branches', set([
|
||||
'mozilla-beta',
|
||||
'mozilla-release',
|
||||
'mozilla-esr60',
|
||||
'comm-beta',
|
||||
'comm-esr60',
|
||||
])
|
||||
]]
|
||||
|
||||
@ -76,12 +78,16 @@ BEETMOVER_SCOPE_ALIAS_TO_PROJECT = [[
|
||||
'mozilla-central',
|
||||
'mozilla-beta',
|
||||
'mozilla-release',
|
||||
'mozilla-esr60',
|
||||
'comm-central',
|
||||
])
|
||||
], [
|
||||
'all-release-branches', set([
|
||||
'mozilla-beta',
|
||||
'mozilla-release',
|
||||
'mozilla-esr60',
|
||||
'comm-beta',
|
||||
'comm-esr60',
|
||||
])
|
||||
]]
|
||||
|
||||
@ -170,11 +176,17 @@ BALROG_SCOPE_ALIAS_TO_PROJECT = [[
|
||||
], [
|
||||
'beta', set([
|
||||
'mozilla-beta',
|
||||
'comm-beta',
|
||||
])
|
||||
], [
|
||||
'release', set([
|
||||
'mozilla-release',
|
||||
])
|
||||
], [
|
||||
'esr60', set([
|
||||
'mozilla-esr60',
|
||||
'comm-esr60',
|
||||
])
|
||||
], [
|
||||
'esr', set([
|
||||
'mozilla-esr52',
|
||||
@ -189,6 +201,7 @@ BALROG_SERVER_SCOPES = {
|
||||
'beta': 'balrog:server:beta',
|
||||
'release': 'balrog:server:release',
|
||||
'esr': 'balrog:server:esr',
|
||||
'esr60': 'balrog:server:esr',
|
||||
'default': 'balrog:server:dep',
|
||||
}
|
||||
|
||||
@ -442,7 +455,7 @@ def get_release_config(config):
|
||||
def get_signing_cert_scope_per_platform(build_platform, is_nightly, config):
|
||||
if 'devedition' in build_platform:
|
||||
return get_devedition_signing_cert_scope(config)
|
||||
elif is_nightly or build_platform in ('firefox-source', 'fennec-source'):
|
||||
elif is_nightly or build_platform in ('firefox-source', 'fennec-source', 'thunderbird-source'):
|
||||
return get_signing_cert_scope(config)
|
||||
else:
|
||||
return add_scope_prefix(config, 'signing:cert:dep-signing')
|
||||
|
@ -6,7 +6,8 @@ config = {
|
||||
"installer": {
|
||||
"product-name": "Firefox-%(version)s",
|
||||
"check_uptake": True,
|
||||
"alias": "firefox-esr-latest",
|
||||
# convert to firefox-esr-latest when ESR52 stops
|
||||
"alias": "firefox-esr-next-latest",
|
||||
"ssl-only": True,
|
||||
"add-locales": True,
|
||||
"paths": {
|
||||
@ -35,7 +36,8 @@ config = {
|
||||
"installer-ssl": {
|
||||
"product-name": "Firefox-%(version)s-SSL",
|
||||
"check_uptake": True,
|
||||
"alias": "firefox-esr-latest-ssl",
|
||||
# convert to firefox-esr-latest-ssl when ESR52 stops
|
||||
"alias": "firefox-esr-next-latest-ssl",
|
||||
"ssl-only": True,
|
||||
"add-locales": True,
|
||||
"paths": {
|
||||
|
31
testing/mozharness/configs/single_locale/mozilla-esr60.py
Normal file
31
testing/mozharness/configs/single_locale/mozilla-esr60.py
Normal file
@ -0,0 +1,31 @@
|
||||
import os
|
||||
|
||||
config = {
|
||||
"nightly_build": True,
|
||||
"branch": "mozilla-esr60",
|
||||
"en_us_binary_url": "http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-mozilla-esr60/",
|
||||
"update_channel": "esr",
|
||||
|
||||
# l10n
|
||||
"hg_l10n_base": "https://hg.mozilla.org/l10n-central",
|
||||
|
||||
# mar
|
||||
"mar_tools_url": os.environ["MAR_TOOLS_URL"],
|
||||
|
||||
# repositories
|
||||
"repos": [{
|
||||
"vcs": "hg",
|
||||
"repo": "https://hg.mozilla.org/build/tools",
|
||||
"branch": "default",
|
||||
"dest": "tools",
|
||||
}, {
|
||||
"vcs": "hg",
|
||||
"repo": "https://hg.mozilla.org/releases/mozilla-esr60",
|
||||
"revision": "%(revision)s",
|
||||
"dest": "mozilla-esr60",
|
||||
"clone_upstream_url": "https://hg.mozilla.org/mozilla-unified",
|
||||
}],
|
||||
# purge options
|
||||
'purge_minsize': 12,
|
||||
'is_automation': True,
|
||||
}
|
@ -194424,6 +194424,11 @@
|
||||
{}
|
||||
]
|
||||
],
|
||||
"clear-site-data/support/iframe_executionContexts.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"clear-site-data/support/page_with_resource.sub.html": [
|
||||
[
|
||||
{}
|
||||
@ -321466,6 +321471,12 @@
|
||||
{}
|
||||
]
|
||||
],
|
||||
"clear-site-data/executionContexts.sub.html": [
|
||||
[
|
||||
"/clear-site-data/executionContexts.sub.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"clear-site-data/navigation-insecure.html": [
|
||||
[
|
||||
"/clear-site-data/navigation-insecure.html",
|
||||
@ -429477,6 +429488,10 @@
|
||||
"65ca96dbb9d774e97cc3a60f6b6dde952104893b",
|
||||
"support"
|
||||
],
|
||||
"clear-site-data/executionContexts.sub.html": [
|
||||
"f09a3f73b59994ae82532a4412116815012e4371",
|
||||
"testharness"
|
||||
],
|
||||
"clear-site-data/navigation-insecure.html": [
|
||||
"9ccd712a222085ae7ef75a52e7f542e996a8eb29",
|
||||
"testharness"
|
||||
@ -429497,6 +429512,10 @@
|
||||
"f7c48bb39579c991af9945d2ac6e98b604b7113b",
|
||||
"support"
|
||||
],
|
||||
"clear-site-data/support/iframe_executionContexts.html": [
|
||||
"9c20c9e0db5861970e1f72245b47f128be4a4b3d",
|
||||
"support"
|
||||
],
|
||||
"clear-site-data/support/page_with_resource.sub.html": [
|
||||
"703519a2f6f0e5d11a4fb4fb0e40e5fc3d8624fe",
|
||||
"support"
|
||||
|
@ -1,5 +0,0 @@
|
||||
[media-src-7_1_2.sub.html]
|
||||
expected: TIMEOUT
|
||||
[Test that securitypolicyviolation events are fired]
|
||||
expected: TIMEOUT
|
||||
|
@ -1,5 +0,0 @@
|
||||
[media-src-7_2_2.sub.html]
|
||||
expected: TIMEOUT
|
||||
[Test that securitypolicyviolation events are fired]
|
||||
expected: TIMEOUT
|
||||
|
@ -1,5 +0,0 @@
|
||||
[media-src-blocked.sub.html]
|
||||
expected: TIMEOUT
|
||||
[Test that securitypolicyviolation events are fired]
|
||||
expected: TIMEOUT
|
||||
|
@ -0,0 +1,3 @@
|
||||
[fetch-csp.https.html]
|
||||
[Verify CSP control of fetch() in a Service Worker]
|
||||
expected: FAIL
|
@ -2,6 +2,3 @@
|
||||
[Script: Ed25519-with-CSP, passes, valid key, valid signature.]
|
||||
expected: FAIL
|
||||
|
||||
[Script: Ed25519-with-CSP, fails, valid key, valid signature, key not in CSP.]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
function createAndLoadIframe() {
|
||||
return new Promise(resolve => {
|
||||
addEventListener("message", function() {
|
||||
assert_true(true, "Iframe loaded");
|
||||
resolve();
|
||||
}, { once: true });
|
||||
|
||||
let ifr = document.createElement('iframe');
|
||||
document.body.appendChild(ifr);
|
||||
ifr.src = "https://{{domains[www2]}}:{{ports[https][0]}}/clear-site-data/support/iframe_executionContexts.html";
|
||||
});
|
||||
}
|
||||
|
||||
function loadClearSiteDataResource(what) {
|
||||
return new Promise(resolve => {
|
||||
addEventListener("message", function() {
|
||||
assert_true(true, "Iframe re-loaded");
|
||||
resolve();
|
||||
}, { once: true });
|
||||
|
||||
let image = new Image();
|
||||
image.src = "https://{{domains[www2]}}:{{ports[https][0]}}/clear-site-data/support/echo-clear-site-data.py?" + what;
|
||||
});
|
||||
}
|
||||
|
||||
promise_test(function(test) {
|
||||
return createAndLoadIframe()
|
||||
.then(() => loadClearSiteDataResource("executionContexts"))
|
||||
}, "executionContexts triggers the reload of contexts");
|
||||
|
||||
promise_test(function(test) {
|
||||
return createAndLoadIframe()
|
||||
.then(() => loadClearSiteDataResource("*"));
|
||||
}, "* triggers the reload of contexts");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
parent.postMessage("Hello world!", "*");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -3,5 +3,5 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
dropmarker {
|
||||
-moz-appearance: menulist-button;
|
||||
-moz-appearance: -moz-menulist-button;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ menulist[editable="true"] {
|
||||
|
||||
menulist[editable="true"] > .menulist-dropmarker {
|
||||
display: -moz-box;
|
||||
-moz-appearance: menulist-button;
|
||||
-moz-appearance: -moz-menulist-button;
|
||||
}
|
||||
|
||||
html|*.menulist-editable-input {
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
dropmarker {
|
||||
-moz-appearance: menulist-button;
|
||||
-moz-appearance: -moz-menulist-button;
|
||||
width: 16px;
|
||||
-moz-box-align: center;
|
||||
-moz-box-pack: center;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
dropmarker {
|
||||
-moz-appearance: menulist-button;
|
||||
-moz-appearance: -moz-menulist-button;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
-moz-box-align: center;
|
||||
|
@ -3327,6 +3327,7 @@ nsNativeThemeCocoa::ComputeWidgetInfo(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
return Some(WidgetInfo::Button(
|
||||
ButtonParams{ComputeControlParams(aFrame, eventState),
|
||||
ButtonType::eArrowButton}));
|
||||
@ -3868,6 +3869,7 @@ nsNativeThemeCocoa::CreateWebRenderCommandsForWidget(mozilla::wr::DisplayListBui
|
||||
case StyleAppearance::Menulist:
|
||||
case StyleAppearance::MenulistTextfield:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::Groupbox:
|
||||
case StyleAppearance::Textfield:
|
||||
case StyleAppearance::NumberInput:
|
||||
@ -4033,6 +4035,7 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext,
|
||||
|
||||
case StyleAppearance::Menulist:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
result = DirectionAwareMargin(kAquaDropdownBorder, aFrame);
|
||||
break;
|
||||
|
||||
@ -4160,6 +4163,7 @@ nsNativeThemeCocoa::GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFram
|
||||
case StyleAppearance::Listbox:
|
||||
case StyleAppearance::Menulist:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::MenulistTextfield:
|
||||
case StyleAppearance::Checkbox:
|
||||
case StyleAppearance::Radio:
|
||||
@ -4290,6 +4294,7 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
|
||||
case StyleAppearance::Menulist:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
{
|
||||
SInt32 popupHeight = 0;
|
||||
::GetThemeMetric(kThemeMetricPopupButtonHeight, &popupHeight);
|
||||
@ -4616,7 +4621,8 @@ nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* a
|
||||
WidgetType aWidgetType)
|
||||
{
|
||||
// if this is a dropdown button in a combobox the answer is always no
|
||||
if (aWidgetType == StyleAppearance::MenulistButton) {
|
||||
if (aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton) {
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
if (parentFrame && parentFrame->IsComboboxControlFrame())
|
||||
return false;
|
||||
@ -4626,6 +4632,7 @@ nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* a
|
||||
// Combobox dropdowns don't support native theming in vertical mode.
|
||||
case StyleAppearance::Menulist:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::MenulistText:
|
||||
case StyleAppearance::MenulistTextfield:
|
||||
if (aFrame && aFrame->GetWritingMode().IsVertical()) {
|
||||
@ -4755,6 +4762,7 @@ nsNativeThemeCocoa::WidgetIsContainer(WidgetType aWidgetType)
|
||||
// flesh this out at some point
|
||||
switch (aWidgetType) {
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::Radio:
|
||||
case StyleAppearance::Checkbox:
|
||||
case StyleAppearance::Progressbar:
|
||||
|
@ -304,7 +304,8 @@ nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aWidgetType, nsIFrame* aF
|
||||
aWidgetType == StyleAppearance::Dualbutton ||
|
||||
aWidgetType == StyleAppearance::ToolbarbuttonDropdown ||
|
||||
aWidgetType == StyleAppearance::Menulist ||
|
||||
aWidgetType == StyleAppearance::MenulistButton) {
|
||||
aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton) {
|
||||
aState->active &= aState->inHover;
|
||||
} else if (aWidgetType == StyleAppearance::Treetwisty ||
|
||||
aWidgetType == StyleAppearance::Treetwistyopen) {
|
||||
@ -421,7 +422,8 @@ nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aWidgetType, nsIFrame* aF
|
||||
aWidgetType == StyleAppearance::Dualbutton ||
|
||||
aWidgetType == StyleAppearance::ToolbarbuttonDropdown ||
|
||||
aWidgetType == StyleAppearance::Menulist ||
|
||||
aWidgetType == StyleAppearance::MenulistButton) {
|
||||
aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton) {
|
||||
bool menuOpen = IsOpenButton(aFrame);
|
||||
aState->depressed = IsCheckedButton(aFrame) || menuOpen;
|
||||
// we must not highlight buttons with open drop down menus on hover.
|
||||
@ -430,7 +432,9 @@ nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aWidgetType, nsIFrame* aF
|
||||
|
||||
// When the input field of the drop down button has focus, some themes
|
||||
// should draw focus for the drop down button as well.
|
||||
if (aWidgetType == StyleAppearance::MenulistButton && aWidgetFlags) {
|
||||
if ((aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton) &&
|
||||
aWidgetFlags) {
|
||||
*aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused);
|
||||
}
|
||||
}
|
||||
@ -623,6 +627,7 @@ nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aWidgetType, nsIFrame* aF
|
||||
aGtkWidgetType = MOZ_GTK_DROPDOWN_ENTRY;
|
||||
break;
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
aGtkWidgetType = MOZ_GTK_DROPDOWN_ARROW;
|
||||
break;
|
||||
case StyleAppearance::ToolbarbuttonDropdown:
|
||||
@ -1398,6 +1403,7 @@ nsNativeThemeGTK::GetWidgetPadding(nsDeviceContext* aContext,
|
||||
case StyleAppearance::TabScrollArrowBack:
|
||||
case StyleAppearance::TabScrollArrowForward:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::ToolbarbuttonDropdown:
|
||||
case StyleAppearance::ButtonArrowUp:
|
||||
case StyleAppearance::ButtonArrowDown:
|
||||
@ -1600,6 +1606,7 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
}
|
||||
break;
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
{
|
||||
moz_gtk_get_combo_box_entry_button_size(&aResult->width,
|
||||
&aResult->height);
|
||||
@ -1952,6 +1959,7 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
|
||||
!IsWidgetStyled(aPresContext, aFrame, aWidgetType);
|
||||
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
if (aFrame && aFrame->GetWritingMode().IsVertical()) {
|
||||
return false;
|
||||
}
|
||||
@ -1974,6 +1982,7 @@ nsNativeThemeGTK::WidgetIsContainer(StyleAppearance aWidgetType)
|
||||
{
|
||||
// XXXdwh At some point flesh all of this out.
|
||||
if (aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton ||
|
||||
aWidgetType == StyleAppearance::Radio ||
|
||||
aWidgetType == StyleAppearance::RangeThumb ||
|
||||
aWidgetType == StyleAppearance::Checkbox ||
|
||||
|
@ -88,6 +88,7 @@ HeadlessThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
|
||||
result.left = 7;
|
||||
break;
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
result.top = 1;
|
||||
result.right = 1;
|
||||
result.bottom = 1;
|
||||
@ -135,6 +136,7 @@ HeadlessThemeGTK::GetWidgetPadding(nsDeviceContext* aContext,
|
||||
case StyleAppearance::TabScrollArrowBack:
|
||||
case StyleAppearance::TabScrollArrowForward:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::RangeThumb:
|
||||
case StyleAppearance::ButtonFocus:
|
||||
aResult->top = 0;
|
||||
@ -272,6 +274,7 @@ HeadlessThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
|
||||
aResult->height = 27;
|
||||
break;
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
aResult->width = 29;
|
||||
aResult->height = 28;
|
||||
*aIsOverridable = false;
|
||||
@ -409,6 +412,7 @@ HeadlessThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
|
||||
case StyleAppearance::MozGtkInfoBar:
|
||||
return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
return (!aFrame || IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) &&
|
||||
!IsWidgetStyled(aPresContext, aFrame, aWidgetType);
|
||||
default:
|
||||
@ -421,6 +425,7 @@ NS_IMETHODIMP_(bool)
|
||||
HeadlessThemeGTK::WidgetIsContainer(WidgetType aWidgetType)
|
||||
{
|
||||
if (aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton ||
|
||||
aWidgetType == StyleAppearance::Radio ||
|
||||
aWidgetType == StyleAppearance::RangeThumb ||
|
||||
aWidgetType == StyleAppearance::Checkbox ||
|
||||
|
@ -785,6 +785,7 @@ mozilla::Maybe<nsUXThemeClass> nsNativeThemeWin::GetThemeClass(WidgetType aWidge
|
||||
return Some(eUXStatus);
|
||||
case StyleAppearance::Menulist:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
return Some(eUXCombobox);
|
||||
case StyleAppearance::Treeheadercell:
|
||||
case StyleAppearance::Treeheadersortarrow:
|
||||
@ -1297,7 +1298,8 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, WidgetType aWidgetType,
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case StyleAppearance::MenulistButton: {
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton: {
|
||||
bool isHTML = IsHTMLContent(aFrame);
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
bool isMenulist = !isHTML && parentFrame->IsMenuFrame();
|
||||
@ -1828,7 +1830,8 @@ RENDER_AGAIN:
|
||||
}
|
||||
// The following widgets need to be RTL-aware
|
||||
else if (aWidgetType == StyleAppearance::Resizer ||
|
||||
aWidgetType == StyleAppearance::MenulistButton)
|
||||
aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton)
|
||||
{
|
||||
DrawThemeBGRTLAware(theme, hdc, part, state,
|
||||
&widgetRect, &clipRect, IsFrameRTL(aFrame));
|
||||
@ -2258,6 +2261,8 @@ nsNativeThemeWin::GetWidgetOverflow(nsDeviceContext* aContext,
|
||||
* where, if invalidated, the dropdown control probably won't be repainted.
|
||||
* This is fairly minor, as by default there is nothing in that area, and
|
||||
* a border only shows up if the widget is being hovered.
|
||||
*
|
||||
* TODO(jwatt): Figure out what do to about StyleAppearance::MozMenulistButton too.
|
||||
*/
|
||||
#if 0
|
||||
/* We explicitly draw dropdown buttons in HTML content 1px bigger up, right,
|
||||
@ -2351,7 +2356,8 @@ nsNativeThemeWin::GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aF
|
||||
case StyleAppearance::ScrollbarbuttonRight:
|
||||
case StyleAppearance::ScrollbarHorizontal:
|
||||
case StyleAppearance::ScrollbarVertical:
|
||||
case StyleAppearance::MenulistButton: {
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton: {
|
||||
rv = ClassicGetMinimumWidgetSize(aFrame, aWidgetType, aResult, aIsOverridable);
|
||||
ScaleForFrameDPI(aResult, aFrame);
|
||||
return rv;
|
||||
@ -2566,7 +2572,9 @@ nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, WidgetType aWidgetType,
|
||||
|
||||
// We need to repaint the dropdown arrow in vista HTML combobox controls when
|
||||
// the control is closed to get rid of the hover effect.
|
||||
if ((aWidgetType == StyleAppearance::Menulist || aWidgetType == StyleAppearance::MenulistButton) &&
|
||||
if ((aWidgetType == StyleAppearance::Menulist ||
|
||||
aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton) &&
|
||||
IsHTMLContent(aFrame))
|
||||
{
|
||||
*aShouldRepaint = true;
|
||||
@ -2643,6 +2651,7 @@ nsNativeThemeWin::WidgetIsContainer(WidgetType aWidgetType)
|
||||
{
|
||||
// XXXdwh At some point flesh all of this out.
|
||||
if (aWidgetType == StyleAppearance::MenulistButton ||
|
||||
aWidgetType == StyleAppearance::MozMenulistButton ||
|
||||
aWidgetType == StyleAppearance::Radio ||
|
||||
aWidgetType == StyleAppearance::Checkbox)
|
||||
return false;
|
||||
@ -2788,6 +2797,7 @@ nsNativeThemeWin::ClassicThemeSupportsWidget(nsIFrame* aFrame,
|
||||
case StyleAppearance::ScalethumbHorizontal:
|
||||
case StyleAppearance::ScalethumbVertical:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::InnerSpinButton:
|
||||
case StyleAppearance::SpinnerUpbutton:
|
||||
case StyleAppearance::SpinnerDownbutton:
|
||||
@ -2998,6 +3008,7 @@ nsNativeThemeWin::ClassicGetMinimumWidgetSize(nsIFrame* aFrame,
|
||||
*aIsOverridable = false;
|
||||
break;
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
(*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL);
|
||||
break;
|
||||
case StyleAppearance::Menulist:
|
||||
@ -3277,7 +3288,8 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, WidgetT
|
||||
case StyleAppearance::Groupbox:
|
||||
// these don't use DrawFrameControl
|
||||
return NS_OK;
|
||||
case StyleAppearance::MenulistButton: {
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton: {
|
||||
|
||||
aPart = DFC_SCROLL;
|
||||
aState = DFCS_SCROLLCOMBOBOX;
|
||||
@ -3662,6 +3674,7 @@ RENDER_AGAIN:
|
||||
case StyleAppearance::SpinnerUpbutton:
|
||||
case StyleAppearance::SpinnerDownbutton:
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
case StyleAppearance::Resizer: {
|
||||
int32_t oldTA;
|
||||
// setup DC to make DrawFrameControl draw correctly
|
||||
@ -4093,6 +4106,7 @@ nsNativeThemeWin::GetWidgetNativeDrawingFlags(WidgetType aWidgetType)
|
||||
// except that the graphic in the dropdown button (the downward arrow)
|
||||
// doesn't get scaled up.
|
||||
case StyleAppearance::MenulistButton:
|
||||
case StyleAppearance::MozMenulistButton:
|
||||
// these are definitely no; they're all graphics that don't get scaled up
|
||||
case StyleAppearance::Checkbox:
|
||||
case StyleAppearance::Radio:
|
||||
|
@ -4,6 +4,9 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// See the comment at the top of mfbt/HashTable.h for a comparison between
|
||||
// PLDHashTable and mozilla::HashTable.
|
||||
|
||||
#ifndef PLDHashTable_h
|
||||
#define PLDHashTable_h
|
||||
|
||||
|
@ -39,7 +39,7 @@ struct nsIDataType
|
||||
VTYPE_WCHAR_STR = TD_PWSTRING ,
|
||||
VTYPE_INTERFACE = TD_INTERFACE_TYPE ,
|
||||
VTYPE_INTERFACE_IS = TD_INTERFACE_IS_TYPE,
|
||||
VTYPE_ARRAY = TD_ARRAY ,
|
||||
VTYPE_ARRAY = TD_LEGACY_ARRAY ,
|
||||
VTYPE_STRING_SIZE_IS = TD_PSTRING_SIZE_IS ,
|
||||
VTYPE_WSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS ,
|
||||
VTYPE_UTF8STRING = TD_UTF8STRING ,
|
||||
|
@ -2550,6 +2550,13 @@ public:
|
||||
this->AppendElements(aOther);
|
||||
}
|
||||
|
||||
AutoTArray(self_type&& aOther)
|
||||
: nsTArray<E>()
|
||||
{
|
||||
Init();
|
||||
this->SwapElements(aOther);
|
||||
}
|
||||
|
||||
explicit AutoTArray(const base_type& aOther)
|
||||
: mAlign()
|
||||
{
|
||||
@ -2584,6 +2591,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type& operator=(self_type&& aOther)
|
||||
{
|
||||
base_type::operator=(std::move(aOther));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& aOther)
|
||||
{
|
||||
|
@ -4,6 +4,9 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// See the comment at the top of mfbt/HashTable.h for a comparison between
|
||||
// PLDHashTable and mozilla::HashTable.
|
||||
|
||||
#ifndef nsTHashtable_h__
|
||||
#define nsTHashtable_h__
|
||||
|
||||
|
@ -63,10 +63,18 @@ def get_type(type, calltype, iid_is=None, size_is=None):
|
||||
return ret
|
||||
|
||||
if isinstance(type, xpidl.Array):
|
||||
# NB: For an Array<T> we pass down the iid_is to get the type of T.
|
||||
# NB: For a Array<T> we pass down the iid_is to get the type of T.
|
||||
# This allows Arrays of InterfaceIs types to work.
|
||||
return {
|
||||
'tag': 'TD_ARRAY',
|
||||
'element': get_type(type.type, calltype, iid_is),
|
||||
}
|
||||
|
||||
if isinstance(type, xpidl.LegacyArray):
|
||||
# NB: For a Legacy [array] T we pass down iid_is to get the type of T.
|
||||
# This allows [array] of InterfaceIs types to work.
|
||||
return {
|
||||
'tag': 'TD_LEGACY_ARRAY',
|
||||
'size_is': size_is,
|
||||
'element': get_type(type.type, calltype, iid_is),
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ void bar();
|
||||
m = iface.members[0]
|
||||
self.assertTrue(isinstance(m, xpidl.Method))
|
||||
self.assertEqual("bar", m.name)
|
||||
self.assertEqual("void", m.type)
|
||||
self.assertEqual(xpidl.TypeId("void"), m.type)
|
||||
|
||||
def testMethodParams(self):
|
||||
i = self.p.parse("""[uuid(abc)] interface foo {
|
||||
@ -73,15 +73,15 @@ long bar(in long a, in float b, [array] in long c);
|
||||
m = iface.members[0]
|
||||
self.assertTrue(isinstance(m, xpidl.Method))
|
||||
self.assertEqual("bar", m.name)
|
||||
self.assertEqual("long", m.type)
|
||||
self.assertEqual(xpidl.TypeId("long"), m.type)
|
||||
self.assertEqual(3, len(m.params))
|
||||
self.assertEqual("long", m.params[0].type)
|
||||
self.assertEqual(xpidl.TypeId("long"), m.params[0].type)
|
||||
self.assertEqual("in", m.params[0].paramtype)
|
||||
self.assertEqual("float", m.params[1].type)
|
||||
self.assertEqual(xpidl.TypeId("float"), m.params[1].type)
|
||||
self.assertEqual("in", m.params[1].paramtype)
|
||||
self.assertEqual("long", m.params[2].type)
|
||||
self.assertEqual(xpidl.TypeId("long"), m.params[2].type)
|
||||
self.assertEqual("in", m.params[2].paramtype)
|
||||
self.assertTrue(isinstance(m.params[2].realtype, xpidl.Array))
|
||||
self.assertTrue(isinstance(m.params[2].realtype, xpidl.LegacyArray))
|
||||
self.assertEqual("long", m.params[2].realtype.type.name)
|
||||
|
||||
def testAttribute(self):
|
||||
@ -94,7 +94,7 @@ attribute long bar;
|
||||
a = iface.members[0]
|
||||
self.assertTrue(isinstance(a, xpidl.Attribute))
|
||||
self.assertEqual("bar", a.name)
|
||||
self.assertEqual("long", a.type)
|
||||
self.assertEqual(xpidl.TypeId("long"), a.type)
|
||||
|
||||
def testOverloadedVirtual(self):
|
||||
i = self.p.parse("""[uuid(abc)] interface foo {
|
||||
|
@ -12,6 +12,7 @@ import os.path
|
||||
import re
|
||||
from ply import lex
|
||||
from ply import yacc
|
||||
from collections import namedtuple
|
||||
|
||||
"""A type conforms to the following pattern:
|
||||
|
||||
@ -20,7 +21,7 @@ from ply import yacc
|
||||
|
||||
def nativeType(self, calltype):
|
||||
'returns a string representation of the native type
|
||||
calltype must be 'in', 'out', or 'inout'
|
||||
calltype must be 'in', 'out', 'inout', or 'element'
|
||||
|
||||
Interface members const/method/attribute conform to the following pattern:
|
||||
|
||||
@ -131,6 +132,9 @@ class Builtin(object):
|
||||
return self.nativename.endswith('*')
|
||||
|
||||
def nativeType(self, calltype, shared=False, const=False):
|
||||
if self.name in ["string", "wstring"] and calltype == 'element':
|
||||
raise IDLError("Use string class types for string Array elements", self.location)
|
||||
|
||||
if const:
|
||||
print >>sys.stderr, IDLError(
|
||||
"[const] doesn't make sense on builtin types.", self.location, warning=True)
|
||||
@ -144,7 +148,7 @@ class Builtin(object):
|
||||
else:
|
||||
const = ''
|
||||
return "%s%s %s" % (const, self.nativename,
|
||||
calltype != 'in' and '*' or '')
|
||||
'*' if 'out' in calltype else '')
|
||||
|
||||
def rustType(self, calltype, shared=False, const=False):
|
||||
# We want to rewrite any *mut pointers to *const pointers if constness
|
||||
@ -321,6 +325,7 @@ class Include(object):
|
||||
|
||||
class IDL(object):
|
||||
def __init__(self, productions):
|
||||
self.hasSequence = False
|
||||
self.productions = productions
|
||||
self.deps = []
|
||||
|
||||
@ -328,10 +333,19 @@ class IDL(object):
|
||||
self.namemap.set(object)
|
||||
|
||||
def getName(self, id, location):
|
||||
if id.name == 'Array':
|
||||
if id.params is None or len(id.params) != 1:
|
||||
raise IDLError("Array takes exactly 1 parameter", location)
|
||||
self.hasSequence = True
|
||||
return Array(self.getName(id.params[0], location), location)
|
||||
|
||||
if id.params is not None:
|
||||
raise IDLError("Generic type '%s' unrecognized" % id.name, location)
|
||||
|
||||
try:
|
||||
return self.namemap[id]
|
||||
return self.namemap[id.name]
|
||||
except KeyError:
|
||||
raise IDLError("type '%s' not found" % id, location)
|
||||
raise IDLError("type '%s' not found" % id.name, location)
|
||||
|
||||
def hasName(self, id):
|
||||
return id in self.namemap
|
||||
@ -354,6 +368,8 @@ class IDL(object):
|
||||
for p in self.productions:
|
||||
if p.kind == 'include':
|
||||
yield p
|
||||
if self.hasSequence:
|
||||
yield Include("nsTArray.h", BuiltinLocation)
|
||||
|
||||
def needsJSTypes(self):
|
||||
for p in self.productions:
|
||||
@ -396,12 +412,14 @@ class Typedef(object):
|
||||
parent.setName(self)
|
||||
self.realtype = parent.getName(self.type, self.location)
|
||||
|
||||
if not isinstance(self.realtype, (Builtin, Native, Typedef)):
|
||||
raise IDLError("Unsupported typedef target type", self.location)
|
||||
|
||||
def isScriptable(self):
|
||||
return self.realtype.isScriptable()
|
||||
|
||||
def nativeType(self, calltype):
|
||||
return "%s %s" % (self.name,
|
||||
calltype != 'in' and '*' or '')
|
||||
return "%s %s" % (self.name, '*' if 'out' in calltype else '')
|
||||
|
||||
def rustType(self, calltype):
|
||||
return "%s%s" % (calltype != 'in' and '*mut ' or '',
|
||||
@ -440,8 +458,9 @@ class Forward(object):
|
||||
return True
|
||||
|
||||
def nativeType(self, calltype):
|
||||
return "%s %s" % (self.name,
|
||||
calltype != 'in' and '* *' or '*')
|
||||
if calltype == 'element':
|
||||
return 'RefPtr<%s>' % self.name
|
||||
return "%s *%s" % (self.name, '*' if 'out' in calltype else '')
|
||||
|
||||
def rustType(self, calltype):
|
||||
if rustBlacklistedForward(self.name):
|
||||
@ -459,29 +478,19 @@ class Native(object):
|
||||
modifier = None
|
||||
specialtype = None
|
||||
|
||||
# A tuple type here means that a custom value is used for each calltype:
|
||||
# (in, out/inout, array element) respectively.
|
||||
# A `None` here means that the written type should be used as-is.
|
||||
specialtypes = {
|
||||
'nsid': None,
|
||||
'domstring': 'nsAString',
|
||||
'utf8string': 'nsACString',
|
||||
'cstring': 'nsACString',
|
||||
'astring': 'nsAString',
|
||||
'jsval': 'JS::Value',
|
||||
'domstring': ('const nsAString&', 'nsAString&', 'nsString'),
|
||||
'utf8string': ('const nsACString&', 'nsACString&', 'nsCString'),
|
||||
'cstring': ('const nsACString&', 'nsACString&', 'nsCString'),
|
||||
'astring': ('const nsAString&', 'nsAString&', 'nsString'),
|
||||
'jsval': ('JS::HandleValue', 'JS::MutableHandleValue', 'JS::Value'),
|
||||
'promise': '::mozilla::dom::Promise',
|
||||
}
|
||||
|
||||
# Mappings from C++ native name types to rust native names. Types which
|
||||
# aren't listed here are incompatible with rust code.
|
||||
rust_nativenames = {
|
||||
'void': "libc::c_void",
|
||||
'char': "u8",
|
||||
'char16_t': "u16",
|
||||
'nsID': "nsID",
|
||||
'nsIID': "nsIID",
|
||||
'nsCID': "nsCID",
|
||||
'nsAString': "::nsstring::nsAString",
|
||||
'nsACString': "::nsstring::nsACString",
|
||||
}
|
||||
|
||||
def __init__(self, name, nativename, attlist, location):
|
||||
self.name = name
|
||||
self.nativename = nativename
|
||||
@ -533,47 +542,75 @@ class Native(object):
|
||||
def nativeType(self, calltype, const=False, shared=False):
|
||||
if shared:
|
||||
if calltype != 'out':
|
||||
raise IDLError("[shared] only applies to out parameters.")
|
||||
raise IDLError("[shared] only applies to out parameters.", self.location)
|
||||
const = True
|
||||
|
||||
if self.specialtype not in [None, 'promise'] and calltype == 'in':
|
||||
if isinstance(self.nativename, tuple):
|
||||
if calltype == 'in':
|
||||
return self.nativename[0] + ' '
|
||||
elif 'out' in calltype:
|
||||
return self.nativename[1] + ' '
|
||||
else:
|
||||
return self.nativename[2] + ' '
|
||||
|
||||
# 'in' nsid parameters should be made 'const'
|
||||
if self.specialtype == 'nsid' and calltype == 'in':
|
||||
const = True
|
||||
|
||||
if self.specialtype == 'jsval':
|
||||
if calltype == 'out' or calltype == 'inout':
|
||||
return "JS::MutableHandleValue "
|
||||
return "JS::HandleValue "
|
||||
if calltype == 'element':
|
||||
if self.isRef(calltype):
|
||||
raise IDLError("[ref] qualified type unsupported in Array<T>", self.location)
|
||||
|
||||
# Promises should be held in RefPtr<T> in Array<T>s
|
||||
if self.specialtype == 'promise':
|
||||
return 'RefPtr<mozilla::dom::Promise>'
|
||||
|
||||
# We don't support nsIDPtr, in Array<T> currently, although
|
||||
# this or support for Array<nsID> will be needed to replace
|
||||
# [array] completely.
|
||||
if self.specialtype == 'nsid':
|
||||
raise IDLError("Array<nsIDPtr> not yet supported. "
|
||||
"File an XPConnect bug if you need it.", self.location)
|
||||
|
||||
if self.isRef(calltype):
|
||||
m = '& '
|
||||
elif self.isPtr(calltype):
|
||||
m = '*' + ((self.modifier == 'ptr' and calltype != 'in') and '*' or '')
|
||||
m = '& ' # [ref] is always passed with a single indirection
|
||||
else:
|
||||
m = calltype != 'in' and '*' or ''
|
||||
m = '* ' if 'out' in calltype else ''
|
||||
if self.isPtr(calltype):
|
||||
m += '* '
|
||||
return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
|
||||
|
||||
def rustType(self, calltype, const=False, shared=False):
|
||||
if shared:
|
||||
if calltype != 'out':
|
||||
raise IDLError("[shared] only applies to out parameters.")
|
||||
const = True
|
||||
# For the most part, 'native' types don't make sense in rust, as they
|
||||
# are native C++ types. However, we can support a few types here, as
|
||||
# they're important.
|
||||
#
|
||||
# NOTE: This code doesn't try to perfectly match C++ constness, as
|
||||
# constness doesn't affect ABI, and raw pointers are already unsafe.
|
||||
|
||||
if self.specialtype is not None and calltype == 'in':
|
||||
const = True
|
||||
if self.modifier not in ['ptr', 'ref']:
|
||||
raise RustNoncompat('Rust only supports [ref] / [ptr] native types')
|
||||
|
||||
if self.nativename not in self.rust_nativenames:
|
||||
raise RustNoncompat("native type %s is unsupported" % self.nativename)
|
||||
name = self.rust_nativenames[self.nativename]
|
||||
prefix = '*mut ' if 'out' in calltype else '*const '
|
||||
if 'out' in calltype and self.modifier == 'ptr':
|
||||
prefix += '*mut '
|
||||
|
||||
if self.isRef(calltype):
|
||||
m = const and '&' or '&mut '
|
||||
elif self.isPtr(calltype):
|
||||
m = (const and '*const ' or '*mut ')
|
||||
if self.modifier == 'ptr' and calltype != 'in':
|
||||
m += '*mut '
|
||||
else:
|
||||
m = calltype != 'in' and '*mut ' or ''
|
||||
return "%s%s" % (m, name)
|
||||
if self.specialtype == 'nsid':
|
||||
return prefix + self.nativename
|
||||
if self.specialtype in ['cstring', 'utf8string']:
|
||||
if 'element' in calltype:
|
||||
return '::nsstring::nsCString'
|
||||
return prefix + '::nsstring::nsACString'
|
||||
if self.specialtype in ['astring', 'domstring']:
|
||||
if 'element' in calltype:
|
||||
return '::nsstring::nsString'
|
||||
return prefix + '::nsstring::nsAString'
|
||||
if self.nativename == 'void':
|
||||
return prefix + 'libc::c_void'
|
||||
|
||||
if self.specialtype:
|
||||
raise RustNoncompat("specialtype %s unsupported" % self.specialtype)
|
||||
raise RustNoncompat("native type %s unsupported" % self.nativename)
|
||||
|
||||
def __str__(self):
|
||||
return "native %s(%s)\n" % (self.name, self.nativename)
|
||||
@ -613,11 +650,13 @@ class WebIDL(object):
|
||||
return True # All DOM objects are script exposed.
|
||||
|
||||
def nativeType(self, calltype):
|
||||
return "%s %s" % (self.native, calltype != 'in' and '* *' or '*')
|
||||
if calltype == 'element':
|
||||
return 'RefPtr<%s>' % self.native
|
||||
return "%s *%s" % (self.native, '*' if 'out' in calltype else '')
|
||||
|
||||
def rustType(self, calltype):
|
||||
# Just expose the type as a void* - we can't do any better.
|
||||
return "%s*const libc::c_void" % (calltype != 'in' and '*mut ' or '')
|
||||
return "%s*const libc::c_void" % ('*mut ' if 'out' in calltype else '')
|
||||
|
||||
def __str__(self):
|
||||
return "webidl %s\n" % self.name
|
||||
@ -662,7 +701,7 @@ class Interface(object):
|
||||
if hasattr(member, 'doccomments'):
|
||||
member.doccomments[0:0] = self.doccomments
|
||||
break
|
||||
self.doccomments = parent.getName(self.name, None).doccomments
|
||||
self.doccomments = parent.getName(TypeId(self.name), None).doccomments
|
||||
|
||||
if self.attributes.function:
|
||||
has_method = False
|
||||
@ -677,7 +716,7 @@ class Interface(object):
|
||||
|
||||
parent.setName(self)
|
||||
if self.base is not None:
|
||||
realbase = parent.getName(self.base, self.location)
|
||||
realbase = parent.getName(TypeId(self.base), self.location)
|
||||
if realbase.kind != 'interface':
|
||||
raise IDLError("interface '%s' inherits from non-interface type '%s'" %
|
||||
(self.name, self.base), self.location)
|
||||
@ -713,12 +752,13 @@ class Interface(object):
|
||||
return True
|
||||
|
||||
def nativeType(self, calltype, const=False):
|
||||
return "%s%s %s" % (const and 'const ' or '',
|
||||
self.name,
|
||||
calltype != 'in' and '* *' or '*')
|
||||
if calltype == 'element':
|
||||
return 'RefPtr<%s>' % self.name
|
||||
return "%s%s *%s" % ('const ' if const else '', self.name,
|
||||
'*' if 'out' in calltype else '')
|
||||
|
||||
def rustType(self, calltype):
|
||||
return "%s*const %s" % (calltype != 'in' and '*mut ' or '',
|
||||
def rustType(self, calltype, const=False):
|
||||
return "%s*const %s" % ('*mut ' if 'out' in calltype else '',
|
||||
self.name)
|
||||
|
||||
def __str__(self):
|
||||
@ -737,9 +777,9 @@ class Interface(object):
|
||||
# The constant may be in a base class
|
||||
iface = self
|
||||
while name not in iface.namemap and iface is not None:
|
||||
iface = self.idl.getName(self.base, self.location)
|
||||
iface = self.idl.getName(TypeId(self.base), self.location)
|
||||
if iface is None:
|
||||
raise IDLError("cannot find symbol '%s'" % name)
|
||||
raise IDLError("cannot find symbol '%s'" % name, self.location)
|
||||
c = iface.namemap.get(name, location)
|
||||
if c.kind != 'const':
|
||||
raise IDLError("symbol '%s' is not a constant", c.location)
|
||||
@ -748,7 +788,7 @@ class Interface(object):
|
||||
|
||||
def needsJSTypes(self):
|
||||
for m in self.members:
|
||||
if m.kind == "attribute" and m.type == "jsval":
|
||||
if m.kind == "attribute" and m.type == TypeId("jsval"):
|
||||
return True
|
||||
if m.kind == "method" and m.needsJSTypes():
|
||||
return True
|
||||
@ -758,7 +798,7 @@ class Interface(object):
|
||||
''' Returns the number of entries in the vtable for this interface. '''
|
||||
total = sum(member.count() for member in self.members)
|
||||
if self.base is not None:
|
||||
realbase = self.idl.getName(self.base, self.location)
|
||||
realbase = self.idl.getName(TypeId(self.base), self.location)
|
||||
total += realbase.countEntries()
|
||||
return total
|
||||
|
||||
@ -1084,7 +1124,7 @@ class Method(object):
|
||||
def needsJSTypes(self):
|
||||
if self.implicit_jscontext:
|
||||
return True
|
||||
if self.type == "jsval":
|
||||
if self.type == TypeId("jsval"):
|
||||
return True
|
||||
for p in self.params:
|
||||
t = p.realtype
|
||||
@ -1166,7 +1206,7 @@ class Param(object):
|
||||
def resolve(self, method):
|
||||
self.realtype = method.iface.idl.getName(self.type, self.location)
|
||||
if self.array:
|
||||
self.realtype = Array(self.realtype)
|
||||
self.realtype = LegacyArray(self.realtype)
|
||||
if (self.null is not None and
|
||||
getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
|
||||
raise IDLError("'Null' attribute can only be used on DOMString",
|
||||
@ -1211,20 +1251,80 @@ class Param(object):
|
||||
self.name)
|
||||
|
||||
|
||||
class Array(object):
|
||||
class LegacyArray(object):
|
||||
def __init__(self, basetype):
|
||||
self.type = basetype
|
||||
self.location = self.type.location
|
||||
|
||||
def isScriptable(self):
|
||||
return self.type.isScriptable()
|
||||
|
||||
def nativeType(self, calltype, const=False):
|
||||
return "%s%s*" % (const and 'const ' or '',
|
||||
self.type.nativeType(calltype))
|
||||
if 'element' in calltype:
|
||||
raise IDLError("nested [array] unsupported", self.location)
|
||||
|
||||
# For legacy reasons, we have to add a 'const ' to builtin pointer array
|
||||
# types. (`[array] in string` and `[array] in wstring` parameters)
|
||||
if calltype == 'in' and isinstance(self.type, Builtin) and self.type.isPointer():
|
||||
const = True
|
||||
|
||||
return "%s%s*%s" % ('const ' if const else '',
|
||||
self.type.nativeType('legacyelement'),
|
||||
'*' if 'out' in calltype else '')
|
||||
|
||||
def rustType(self, calltype, const=False):
|
||||
return "%s %s" % (const and '*const' or '*mut',
|
||||
self.type.rustType(calltype))
|
||||
return "%s%s%s" % ('*mut ' if 'out' in calltype else '',
|
||||
'*const ' if const else '*mut ',
|
||||
self.type.rustType('legacyelement'))
|
||||
|
||||
|
||||
class Array(object):
|
||||
kind = 'array'
|
||||
|
||||
def __init__(self, type, location):
|
||||
self.type = type
|
||||
self.location = location
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return "Array<%s>" % self.type.name
|
||||
|
||||
def resolve(self, idl):
|
||||
idl.getName(self.type, self.location)
|
||||
|
||||
def isScriptable(self):
|
||||
return self.type.isScriptable()
|
||||
|
||||
def nativeType(self, calltype):
|
||||
if calltype == 'legacyelement':
|
||||
raise IDLError("[array] Array<T> is unsupported", self.location)
|
||||
|
||||
base = 'nsTArray<%s>' % self.type.nativeType('element')
|
||||
if 'out' in calltype:
|
||||
return '%s& ' % base
|
||||
elif 'in' == calltype:
|
||||
return 'const %s& ' % base
|
||||
else:
|
||||
return base
|
||||
|
||||
def rustType(self, calltype):
|
||||
# NOTE: To add Rust support, ensure 'element' is handled correctly in
|
||||
# all rustType callees.
|
||||
raise RustNoncompat("Array<...> types")
|
||||
|
||||
|
||||
TypeId = namedtuple('TypeId', 'name params')
|
||||
|
||||
|
||||
# Make str(TypeId) produce a nicer value
|
||||
TypeId.__str__ = lambda self: \
|
||||
"%s<%s>" % (self.name, ', '.join(str(p) for p in self.params)) \
|
||||
if self.params is not None \
|
||||
else self.name
|
||||
|
||||
|
||||
# Allow skipping 'params' in TypeId(..)
|
||||
TypeId.__new__.__defaults__ = (None,)
|
||||
|
||||
|
||||
class IDLParser(object):
|
||||
@ -1267,7 +1367,7 @@ class IDLParser(object):
|
||||
t_LSHIFT = r'<<'
|
||||
t_RSHIFT = r'>>'
|
||||
|
||||
literals = '"(){}[],;:=|+-*'
|
||||
literals = '"(){}[]<>,;:=|+-*'
|
||||
|
||||
t_ignore = ' \t'
|
||||
|
||||
@ -1360,7 +1460,7 @@ class IDLParser(object):
|
||||
p[0].insert(0, p[1])
|
||||
|
||||
def p_typedef(self, p):
|
||||
"""typedef : TYPEDEF IDENTIFIER IDENTIFIER ';'"""
|
||||
"""typedef : TYPEDEF type IDENTIFIER ';'"""
|
||||
p[0] = Typedef(type=p[2],
|
||||
name=p[3],
|
||||
location=self.getLocation(p, 1),
|
||||
@ -1473,7 +1573,7 @@ class IDLParser(object):
|
||||
p[0] = CDATA(p[1], self.getLocation(p, 1))
|
||||
|
||||
def p_member_const(self, p):
|
||||
"""member : CONST IDENTIFIER IDENTIFIER '=' number ';' """
|
||||
"""member : CONST type IDENTIFIER '=' number ';' """
|
||||
p[0] = ConstMember(type=p[2], name=p[3],
|
||||
value=p[5], location=self.getLocation(p, 1),
|
||||
doccomments=p.slice[1].doccomments)
|
||||
@ -1535,7 +1635,7 @@ class IDLParser(object):
|
||||
p[0] = lambda i: n1(i) | n2(i)
|
||||
|
||||
def p_member_att(self, p):
|
||||
"""member : attributes optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
|
||||
"""member : attributes optreadonly ATTRIBUTE type IDENTIFIER ';'"""
|
||||
if 'doccomments' in p[1]:
|
||||
doccomments = p[1]['doccomments']
|
||||
elif p[2] is not None:
|
||||
@ -1551,7 +1651,7 @@ class IDLParser(object):
|
||||
doccomments=doccomments)
|
||||
|
||||
def p_member_method(self, p):
|
||||
"""member : attributes IDENTIFIER IDENTIFIER '(' paramlist ')' raises ';'"""
|
||||
"""member : attributes type IDENTIFIER '(' paramlist ')' raises ';'"""
|
||||
if 'doccomments' in p[1]:
|
||||
doccomments = p[1]['doccomments']
|
||||
else:
|
||||
@ -1584,7 +1684,7 @@ class IDLParser(object):
|
||||
p[0].insert(0, p[2])
|
||||
|
||||
def p_param(self, p):
|
||||
"""param : attributes paramtype IDENTIFIER IDENTIFIER"""
|
||||
"""param : attributes paramtype type IDENTIFIER"""
|
||||
p[0] = Param(paramtype=p[2],
|
||||
type=p[3],
|
||||
name=p[4],
|
||||
@ -1622,6 +1722,25 @@ class IDLParser(object):
|
||||
p[0] = list(p[3])
|
||||
p[0].insert(0, p[1])
|
||||
|
||||
def p_type_id(self, p):
|
||||
"""type : IDENTIFIER"""
|
||||
p[0] = TypeId(name=p[1])
|
||||
p.slice[0].doccomments = p.slice[1].doccomments
|
||||
|
||||
def p_type_generic(self, p):
|
||||
"""type : IDENTIFIER '<' typelist '>'"""
|
||||
p[0] = TypeId(name=p[1], params=p[3])
|
||||
p.slice[0].doccomments = p.slice[1].doccomments
|
||||
|
||||
def p_typelist(self, p):
|
||||
"""typelist : type"""
|
||||
p[0] = [p[1]]
|
||||
|
||||
def p_typelist_continue(self, p):
|
||||
"""typelist : type ',' typelist"""
|
||||
p[0] = list(p[3])
|
||||
p[0].insert(0, p[1])
|
||||
|
||||
def p_error(self, t):
|
||||
if not t:
|
||||
raise IDLError(
|
||||
|
@ -31,6 +31,8 @@ invoke_count_words(uint32_t paramCount, nsXPTCVariant* s)
|
||||
case nsXPTType::T_DOUBLE :
|
||||
result++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -60,6 +62,7 @@ invoke_copy_to_stack(uint32_t paramCount, nsXPTCVariant* s, uint32_t* d)
|
||||
case nsXPTType::T_I64 : *((int64_t*) d) = s->val.i64; d++; break;
|
||||
case nsXPTType::T_U64 : *((uint64_t*)d) = s->val.u64; d++; break;
|
||||
case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break;
|
||||
default : break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ PrepareAndDispatch(uint32_t methodIndex, nsXPTCStubBase* self, uint32_t* args)
|
||||
case nsXPTType::T_I64 : dp->val.i64 = *((int64_t*) ap); ap++; break;
|
||||
case nsXPTType::T_U64 : dp->val.u64 = *((uint64_t*)ap); ap++; break;
|
||||
case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break;
|
||||
default : break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
|
||||
case nsXPTType::T_I64 : dp->val.i64 = *((int64_t*) ap); ap++; break;
|
||||
case nsXPTType::T_U64 : dp->val.u64 = *((uint64_t*)ap); ap++; break;
|
||||
case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break;
|
||||
default : break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,6 @@ static_assert(offsetof(nsXPTCMiniVariant, val) == 0,
|
||||
|
||||
struct nsXPTCVariant
|
||||
{
|
||||
// No ctors or dtors so that we can use arrays of these on the stack with no
|
||||
// penalty.
|
||||
union ExtendedVal
|
||||
{
|
||||
// ExtendedVal is an extension on nsXPTCMiniVariant. It contains types
|
||||
@ -60,6 +58,7 @@ struct nsXPTCVariant
|
||||
nsCString nscstr;
|
||||
nsString nsstr;
|
||||
JS::Value jsval;
|
||||
xpt::detail::UntypedTArray array;
|
||||
|
||||
// This type contains non-standard-layout types, so needs an explicit
|
||||
// Ctor/Dtor - we'll just delete them.
|
||||
@ -79,6 +78,12 @@ struct nsXPTCVariant
|
||||
nsXPTType type;
|
||||
uint8_t flags;
|
||||
|
||||
// Clear to a valid, null state.
|
||||
nsXPTCVariant() {
|
||||
memset(this, 0, sizeof(nsXPTCVariant));
|
||||
type = nsXPTType::T_VOID;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
//
|
||||
@ -88,22 +93,12 @@ struct nsXPTCVariant
|
||||
// Indicates that we &val.p should be passed n the stack, i.e. that
|
||||
// val should be passed by reference.
|
||||
IS_INDIRECT = 0x1,
|
||||
|
||||
// Indicates that the value we hold requires some sort of cleanup (memory
|
||||
// deallocation, interface release, JS::Value unrooting, etc). The precise
|
||||
// cleanup that is performed depends on the 'type' field above.
|
||||
// If the value is an array, this flag specifies whether the elements
|
||||
// within the array require cleanup (we always clean up the array itself,
|
||||
// so this flag would be redundant for that purpose).
|
||||
VAL_NEEDS_CLEANUP = 0x2
|
||||
};
|
||||
|
||||
void ClearFlags() {flags = 0;}
|
||||
void SetIndirect() {flags |= IS_INDIRECT;}
|
||||
void SetValNeedsCleanup() {flags |= VAL_NEEDS_CLEANUP;}
|
||||
|
||||
bool IsIndirect() const {return 0 != (flags & IS_INDIRECT);}
|
||||
bool DoesValNeedCleanup() const {return 0 != (flags & VAL_NEEDS_CLEANUP);}
|
||||
|
||||
// Implicitly convert to nsXPTCMiniVariant.
|
||||
operator nsXPTCMiniVariant&() {
|
||||
@ -113,9 +108,8 @@ struct nsXPTCVariant
|
||||
return *(const nsXPTCMiniVariant*) &val;
|
||||
}
|
||||
|
||||
// As this type contains an anonymous union, we need to provide explicit
|
||||
// constructors & destructors.
|
||||
nsXPTCVariant() { }
|
||||
// As this type contains an anonymous union, we need to provide an explicit
|
||||
// destructor.
|
||||
~nsXPTCVariant() { }
|
||||
};
|
||||
|
||||
|
@ -265,7 +265,7 @@ def link_to_cpp(interfaces, fd):
|
||||
|
||||
def describe_type(type): # Create the type's documentation comment.
|
||||
tag = type['tag'][3:].lower()
|
||||
if tag == 'array':
|
||||
if tag == 'legacy_array':
|
||||
return '%s[size_is=%d]' % (
|
||||
describe_type(type['element']), type['size_is'])
|
||||
elif tag == 'interface_type' or tag == 'domobject':
|
||||
@ -280,10 +280,15 @@ def link_to_cpp(interfaces, fd):
|
||||
tag = type['tag']
|
||||
d1 = d2 = 0
|
||||
|
||||
if tag == 'TD_ARRAY':
|
||||
if tag == 'TD_LEGACY_ARRAY':
|
||||
d1 = type['size_is']
|
||||
d2 = lower_extra_type(type['element'])
|
||||
|
||||
elif tag == 'TD_ARRAY':
|
||||
# NOTE: TD_ARRAY can hold 16 bits of type index, while
|
||||
# TD_LEGACY_ARRAY can only hold 8.
|
||||
d1, d2 = splitint(lower_extra_type(type['element']))
|
||||
|
||||
elif tag == 'TD_INTERFACE_TYPE':
|
||||
d1, d2 = splitint(interface_idx(type['name']))
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "js/Value.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
// Forward Declarations
|
||||
namespace mozilla {
|
||||
@ -152,6 +153,14 @@ static_assert(sizeof(nsXPTInterfaceInfo) == 28, "wrong size?");
|
||||
*/
|
||||
enum nsXPTTypeTag : uint8_t
|
||||
{
|
||||
// Arithmetic (POD) Types
|
||||
// - Do not require cleanup,
|
||||
// - All bit patterns are valid,
|
||||
// - Outparams may be uninitialized by caller,
|
||||
// - Directly supported in xptcall.
|
||||
//
|
||||
// NOTE: The name 'Arithmetic' comes from Harbison/Steele. Despite being a tad
|
||||
// unclear, it is used frequently in xptcall, so is unlikely to be changed.
|
||||
TD_INT8 = 0,
|
||||
TD_INT16 = 1,
|
||||
TD_INT32 = 2,
|
||||
@ -165,24 +174,42 @@ enum nsXPTTypeTag : uint8_t
|
||||
TD_BOOL = 10,
|
||||
TD_CHAR = 11,
|
||||
TD_WCHAR = 12,
|
||||
_TD_LAST_ARITHMETIC = TD_WCHAR,
|
||||
|
||||
// Pointer Types
|
||||
// - Require cleanup unless NULL,
|
||||
// - All-zeros (NULL) bit pattern is valid,
|
||||
// - Outparams may be uninitialized by caller,
|
||||
// - Supported in xptcall as raw pointer.
|
||||
TD_VOID = 13,
|
||||
TD_PNSIID = 14,
|
||||
TD_DOMSTRING = 15,
|
||||
TD_PSTRING = 16,
|
||||
TD_PWSTRING = 17,
|
||||
TD_INTERFACE_TYPE = 18,
|
||||
TD_INTERFACE_IS_TYPE = 19,
|
||||
TD_ARRAY = 20,
|
||||
TD_PSTRING_SIZE_IS = 21,
|
||||
TD_PWSTRING_SIZE_IS = 22,
|
||||
TD_UTF8STRING = 23,
|
||||
TD_CSTRING = 24,
|
||||
TD_ASTRING = 25,
|
||||
TD_JSVAL = 26,
|
||||
TD_DOMOBJECT = 27,
|
||||
TD_PROMISE = 28
|
||||
TD_PSTRING = 15,
|
||||
TD_PWSTRING = 16,
|
||||
TD_INTERFACE_TYPE = 17,
|
||||
TD_INTERFACE_IS_TYPE = 18,
|
||||
TD_LEGACY_ARRAY = 19,
|
||||
TD_PSTRING_SIZE_IS = 20,
|
||||
TD_PWSTRING_SIZE_IS = 21,
|
||||
TD_DOMOBJECT = 22,
|
||||
TD_PROMISE = 23,
|
||||
_TD_LAST_POINTER = TD_PROMISE,
|
||||
|
||||
// Complex Types
|
||||
// - Require cleanup,
|
||||
// - Always passed indirectly,
|
||||
// - Outparams must be initialized by caller,
|
||||
// - Supported in xptcall due to indirection.
|
||||
TD_DOMSTRING = 24,
|
||||
TD_UTF8STRING = 25,
|
||||
TD_CSTRING = 26,
|
||||
TD_ASTRING = 27,
|
||||
TD_JSVAL = 28,
|
||||
TD_ARRAY = 29,
|
||||
_TD_LAST_COMPLEX = TD_ARRAY
|
||||
};
|
||||
|
||||
static_assert(_TD_LAST_COMPLEX < 32, "nsXPTTypeTag must fit in 5 bits");
|
||||
|
||||
|
||||
/*
|
||||
* A nsXPTType is a union used to identify the type of a method argument or
|
||||
@ -193,27 +220,34 @@ enum nsXPTTypeTag : uint8_t
|
||||
*/
|
||||
struct nsXPTType
|
||||
{
|
||||
// NOTE: This is uint8_t instead of nsXPTTypeTag so that it can be compared
|
||||
// with the nsXPTType::* re-exports.
|
||||
uint8_t Tag() const { return mTag; }
|
||||
nsXPTTypeTag Tag() const { return static_cast<nsXPTTypeTag>(mTag); }
|
||||
|
||||
// The index in the function argument list which should be used when
|
||||
// determining the iid_is or size_is properties of this dependent type.
|
||||
uint8_t ArgNum() const {
|
||||
MOZ_ASSERT(Tag() == TD_INTERFACE_IS_TYPE ||
|
||||
Tag() == TD_PSTRING_SIZE_IS ||
|
||||
Tag() == TD_PWSTRING_SIZE_IS ||
|
||||
Tag() == TD_ARRAY);
|
||||
Tag() == TD_LEGACY_ARRAY);
|
||||
return mData1;
|
||||
}
|
||||
|
||||
const nsXPTType& ArrayElementType() const {
|
||||
MOZ_ASSERT(Tag() == TD_ARRAY);
|
||||
return xpt::detail::GetType(mData2);
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper for reading 16-bit data values split between mData1 and mData2.
|
||||
uint16_t Data16() const { return ((uint16_t)mData1 << 8) | mData2; }
|
||||
|
||||
public:
|
||||
// Get the type of the element in the current array or sequence. Arrays only
|
||||
// fit 8 bits of type data, while sequences support up to 16 bits of type data
|
||||
// due to not needing to store an ArgNum.
|
||||
const nsXPTType& ArrayElementType() const {
|
||||
if (Tag() == TD_LEGACY_ARRAY) {
|
||||
return xpt::detail::GetType(mData2);
|
||||
}
|
||||
MOZ_ASSERT(Tag() == TD_ARRAY);
|
||||
return xpt::detail::GetType(Data16());
|
||||
}
|
||||
|
||||
// We store the 16-bit iface value as two 8-bit values in order to
|
||||
// avoid 16-bit alignment requirements for XPTTypeDescriptor, which
|
||||
// reduces its size and also the size of XPTParamDescriptor.
|
||||
@ -227,43 +261,44 @@ public:
|
||||
return xpt::detail::GetDOMObjectInfo(Data16());
|
||||
}
|
||||
|
||||
// 'Arithmetic' here roughly means that the value is self-contained and
|
||||
// doesn't depend on anything else in memory (ie: not a pointer, not an
|
||||
// XPCOM object, not a jsval, etc).
|
||||
//
|
||||
// Supposedly this terminology comes from Harbison/Steele, but it's still
|
||||
// a rather crappy name. We'd change it if it wasn't used all over the
|
||||
// place in xptcall. :-(
|
||||
bool IsArithmetic() const { return Tag() <= TD_WCHAR; }
|
||||
// See the comments in nsXPTTypeTag for an explanation as to what each of
|
||||
// these categories mean.
|
||||
bool IsArithmetic() const { return Tag() <= _TD_LAST_ARITHMETIC; }
|
||||
bool IsPointer() const { return !IsArithmetic() && Tag() <= _TD_LAST_POINTER; }
|
||||
bool IsComplex() const { return Tag() > _TD_LAST_POINTER; }
|
||||
|
||||
bool IsInterfacePointer() const {
|
||||
return Tag() == TD_INTERFACE_TYPE || Tag() == TD_INTERFACE_IS_TYPE;
|
||||
}
|
||||
|
||||
bool IsArray() const { return Tag() == TD_ARRAY; }
|
||||
|
||||
bool IsDependent() const {
|
||||
return Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_ARRAY ||
|
||||
return (Tag() == TD_ARRAY && InnermostType().IsDependent()) ||
|
||||
Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_LEGACY_ARRAY ||
|
||||
Tag() == TD_PSTRING_SIZE_IS || Tag() == TD_PWSTRING_SIZE_IS;
|
||||
}
|
||||
|
||||
// Unwrap a nested type to its innermost value (e.g. through arrays).
|
||||
const nsXPTType& InnermostType() const {
|
||||
if (Tag() == TD_ARRAY) {
|
||||
if (Tag() == TD_LEGACY_ARRAY || Tag() == TD_ARRAY) {
|
||||
return ArrayElementType().InnermostType();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Helper methods for working with the type's native representation.
|
||||
// In-memory size of native type in bytes.
|
||||
inline size_t Stride() const;
|
||||
inline bool HasPointerRepr() const;
|
||||
|
||||
// Offset the given base pointer to reference the element at the given index.
|
||||
void* ElementPtr(const void* aBase, uint32_t aIndex) const {
|
||||
return (char*)aBase + (aIndex * Stride());
|
||||
}
|
||||
|
||||
// Zero out a native value of the given type. The type must not be 'complex'.
|
||||
void ZeroValue(void* aValue) const {
|
||||
MOZ_RELEASE_ASSERT(!IsComplex(), "Cannot zero a complex value");
|
||||
memset(aValue, 0, Stride());
|
||||
}
|
||||
|
||||
// Indexes into the extra types array of a small set of known types.
|
||||
enum class Idx : uint8_t
|
||||
{
|
||||
@ -289,7 +324,7 @@ public:
|
||||
// Helper methods for fabricating nsXPTType values used by xpconnect.
|
||||
static nsXPTType MkArrayType(Idx aInner) {
|
||||
MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
|
||||
return { TD_ARRAY, false, false, false, 0, (uint8_t)aInner };
|
||||
return { TD_LEGACY_ARRAY, false, false, false, 0, (uint8_t)aInner };
|
||||
}
|
||||
static const nsXPTType& Get(Idx aInner) {
|
||||
MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
|
||||
@ -300,42 +335,41 @@ public:
|
||||
// nsXPTType backwards compatibility //
|
||||
///////////////////////////////////////
|
||||
|
||||
nsXPTType& operator=(uint8_t aPrefix) { mTag = aPrefix; return *this; }
|
||||
operator uint8_t() const { return TagPart(); };
|
||||
uint8_t TagPart() const { return mTag; };
|
||||
nsXPTType& operator=(nsXPTTypeTag aPrefix) { mTag = aPrefix; return *this; }
|
||||
operator nsXPTTypeTag() const { return Tag(); }
|
||||
|
||||
enum // Re-export TD_ interfaces from nsXPTType
|
||||
{
|
||||
T_I8 = TD_INT8 ,
|
||||
T_I16 = TD_INT16 ,
|
||||
T_I32 = TD_INT32 ,
|
||||
T_I64 = TD_INT64 ,
|
||||
T_U8 = TD_UINT8 ,
|
||||
T_U16 = TD_UINT16 ,
|
||||
T_U32 = TD_UINT32 ,
|
||||
T_U64 = TD_UINT64 ,
|
||||
T_FLOAT = TD_FLOAT ,
|
||||
T_DOUBLE = TD_DOUBLE ,
|
||||
T_BOOL = TD_BOOL ,
|
||||
T_CHAR = TD_CHAR ,
|
||||
T_WCHAR = TD_WCHAR ,
|
||||
T_VOID = TD_VOID ,
|
||||
T_IID = TD_PNSIID ,
|
||||
T_DOMSTRING = TD_DOMSTRING ,
|
||||
T_CHAR_STR = TD_PSTRING ,
|
||||
T_WCHAR_STR = TD_PWSTRING ,
|
||||
T_INTERFACE = TD_INTERFACE_TYPE ,
|
||||
T_INTERFACE_IS = TD_INTERFACE_IS_TYPE,
|
||||
T_ARRAY = TD_ARRAY ,
|
||||
T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS ,
|
||||
T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS ,
|
||||
T_UTF8STRING = TD_UTF8STRING ,
|
||||
T_CSTRING = TD_CSTRING ,
|
||||
T_ASTRING = TD_ASTRING ,
|
||||
T_JSVAL = TD_JSVAL ,
|
||||
T_DOMOBJECT = TD_DOMOBJECT ,
|
||||
T_PROMISE = TD_PROMISE
|
||||
};
|
||||
#define TD_ALIAS_(name_, value_) static constexpr nsXPTTypeTag name_ = value_
|
||||
TD_ALIAS_(T_I8 , TD_INT8 );
|
||||
TD_ALIAS_(T_I16 , TD_INT16 );
|
||||
TD_ALIAS_(T_I32 , TD_INT32 );
|
||||
TD_ALIAS_(T_I64 , TD_INT64 );
|
||||
TD_ALIAS_(T_U8 , TD_UINT8 );
|
||||
TD_ALIAS_(T_U16 , TD_UINT16 );
|
||||
TD_ALIAS_(T_U32 , TD_UINT32 );
|
||||
TD_ALIAS_(T_U64 , TD_UINT64 );
|
||||
TD_ALIAS_(T_FLOAT , TD_FLOAT );
|
||||
TD_ALIAS_(T_DOUBLE , TD_DOUBLE );
|
||||
TD_ALIAS_(T_BOOL , TD_BOOL );
|
||||
TD_ALIAS_(T_CHAR , TD_CHAR );
|
||||
TD_ALIAS_(T_WCHAR , TD_WCHAR );
|
||||
TD_ALIAS_(T_VOID , TD_VOID );
|
||||
TD_ALIAS_(T_IID , TD_PNSIID );
|
||||
TD_ALIAS_(T_DOMSTRING , TD_DOMSTRING );
|
||||
TD_ALIAS_(T_CHAR_STR , TD_PSTRING );
|
||||
TD_ALIAS_(T_WCHAR_STR , TD_PWSTRING );
|
||||
TD_ALIAS_(T_INTERFACE , TD_INTERFACE_TYPE );
|
||||
TD_ALIAS_(T_INTERFACE_IS , TD_INTERFACE_IS_TYPE);
|
||||
TD_ALIAS_(T_LEGACY_ARRAY , TD_LEGACY_ARRAY );
|
||||
TD_ALIAS_(T_PSTRING_SIZE_IS , TD_PSTRING_SIZE_IS );
|
||||
TD_ALIAS_(T_PWSTRING_SIZE_IS , TD_PWSTRING_SIZE_IS );
|
||||
TD_ALIAS_(T_UTF8STRING , TD_UTF8STRING );
|
||||
TD_ALIAS_(T_CSTRING , TD_CSTRING );
|
||||
TD_ALIAS_(T_ASTRING , TD_ASTRING );
|
||||
TD_ALIAS_(T_JSVAL , TD_JSVAL );
|
||||
TD_ALIAS_(T_DOMOBJECT , TD_DOMOBJECT );
|
||||
TD_ALIAS_(T_PROMISE , TD_PROMISE );
|
||||
TD_ALIAS_(T_ARRAY , TD_ARRAY );
|
||||
#undef TD_ALIAS_
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Ensure these fields are in the same order as xptcodegen.py //
|
||||
@ -376,15 +410,10 @@ struct nsXPTParamInfo
|
||||
const nsXPTType& GetType() const { return Type(); } // XXX remove (backcompat)
|
||||
|
||||
// Whether this parameter is passed indirectly on the stack. All out/inout
|
||||
// params are passed indirectly, although some types are passed indirectly
|
||||
// unconditionally.
|
||||
// params are passed indirectly, and complex types are always passed
|
||||
// indirectly.
|
||||
bool IsIndirect() const {
|
||||
return IsOut() ||
|
||||
mType.Tag() == TD_JSVAL ||
|
||||
mType.Tag() == TD_ASTRING ||
|
||||
mType.Tag() == TD_DOMSTRING ||
|
||||
mType.Tag() == TD_CSTRING ||
|
||||
mType.Tag() == TD_UTF8STRING;
|
||||
return IsOut() || Type().IsComplex();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
@ -502,6 +531,34 @@ struct nsXPTDOMObjectInfo
|
||||
namespace xpt {
|
||||
namespace detail {
|
||||
|
||||
// The UntypedTArray type allows low-level access from XPConnect to nsTArray
|
||||
// internals without static knowledge of the array element type in question.
|
||||
class UntypedTArray
|
||||
: public nsTArray_base<nsTArrayFallibleAllocator, nsTArray_CopyWithMemutils>
|
||||
{
|
||||
public:
|
||||
void* Elements() const {
|
||||
return static_cast<void*>(Hdr() + 1);
|
||||
}
|
||||
|
||||
// Changes the length and capacity to be at least large enough for aTo elements.
|
||||
bool SetLength(const nsXPTType& aEltTy, uint32_t aTo) {
|
||||
if (!EnsureCapacity<nsTArrayFallibleAllocator>(aTo, aEltTy.Stride())) {
|
||||
return false;
|
||||
}
|
||||
mHdr->mLength = aTo;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Free backing memory for the nsTArray object.
|
||||
void Clear() {
|
||||
if (mHdr != EmptyHdr() && !UsesAutoArrayBuffer()) {
|
||||
nsTArrayFallibleAllocator::Free(mHdr);
|
||||
}
|
||||
mHdr = EmptyHdr();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The compressed representation of constants from XPT. Not part of the public
|
||||
* interface, as we also need to support Shim interfaces.
|
||||
@ -593,39 +650,11 @@ GetString(uint32_t aIndex)
|
||||
} // namespace detail
|
||||
} // namespace xpt
|
||||
|
||||
inline bool
|
||||
nsXPTType::HasPointerRepr() const
|
||||
{
|
||||
// This method should return `true` if the given type would be represented as
|
||||
// a pointer when not passed indirectly.
|
||||
switch (Tag()) {
|
||||
case TD_VOID:
|
||||
case TD_PNSIID:
|
||||
case TD_PSTRING:
|
||||
case TD_PWSTRING:
|
||||
case TD_INTERFACE_TYPE:
|
||||
case TD_INTERFACE_IS_TYPE:
|
||||
case TD_ARRAY:
|
||||
case TD_PSTRING_SIZE_IS:
|
||||
case TD_PWSTRING_SIZE_IS:
|
||||
case TD_DOMOBJECT:
|
||||
case TD_PROMISE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline size_t
|
||||
nsXPTType::Stride() const
|
||||
{
|
||||
// Compute the stride to use when walking an array of the given type.
|
||||
//
|
||||
// NOTE: We cast to nsXPTTypeTag here so we get a warning if a type is missed
|
||||
// in this switch statement. It's important that this method returns a value
|
||||
// for every possible type.
|
||||
|
||||
switch (static_cast<nsXPTTypeTag>(Tag())) {
|
||||
switch (Tag()) {
|
||||
case TD_INT8: return sizeof(int8_t);
|
||||
case TD_INT16: return sizeof(int16_t);
|
||||
case TD_INT32: return sizeof(int32_t);
|
||||
@ -639,6 +668,7 @@ nsXPTType::Stride() const
|
||||
case TD_BOOL: return sizeof(bool);
|
||||
case TD_CHAR: return sizeof(char);
|
||||
case TD_WCHAR: return sizeof(char16_t);
|
||||
|
||||
case TD_VOID: return sizeof(void*);
|
||||
case TD_PNSIID: return sizeof(nsIID*);
|
||||
case TD_DOMSTRING: return sizeof(nsString);
|
||||
@ -646,15 +676,17 @@ nsXPTType::Stride() const
|
||||
case TD_PWSTRING: return sizeof(char16_t*);
|
||||
case TD_INTERFACE_TYPE: return sizeof(nsISupports*);
|
||||
case TD_INTERFACE_IS_TYPE: return sizeof(nsISupports*);
|
||||
case TD_ARRAY: return sizeof(void*);
|
||||
case TD_LEGACY_ARRAY: return sizeof(void*);
|
||||
case TD_PSTRING_SIZE_IS: return sizeof(char*);
|
||||
case TD_PWSTRING_SIZE_IS: return sizeof(char16_t*);
|
||||
case TD_DOMOBJECT: return sizeof(void*);
|
||||
case TD_PROMISE: return sizeof(void*);
|
||||
|
||||
case TD_UTF8STRING: return sizeof(nsCString);
|
||||
case TD_CSTRING: return sizeof(nsCString);
|
||||
case TD_ASTRING: return sizeof(nsString);
|
||||
case TD_JSVAL: return sizeof(JS::Value);
|
||||
case TD_DOMOBJECT: return sizeof(void*);
|
||||
case TD_PROMISE: return sizeof(void*);
|
||||
case TD_ARRAY: return sizeof(xpt::detail::UntypedTArray);
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unknown type");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user