mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge inbound to mozilla-central. a=merge
This commit is contained in:
commit
73e569944b
@ -2484,18 +2484,19 @@ class TabBrowser {
|
||||
if ((openerTab &&
|
||||
Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) ||
|
||||
Services.prefs.getBoolPref("browser.tabs.insertAfterCurrent")) {
|
||||
let lastRelatedTab = openerTab && this._lastRelatedTabMap.get(openerTab);
|
||||
let newTabPos = (lastRelatedTab || openerTab || this.mCurrentTab)._tPos + 1;
|
||||
|
||||
let lastRelatedTab = openerTab && this._lastRelatedTabMap.get(openerTab);
|
||||
let newTabPos = (lastRelatedTab || openerTab || this.mCurrentTab)._tPos + 1;
|
||||
|
||||
if (lastRelatedTab)
|
||||
lastRelatedTab.owner = null;
|
||||
else if (openerTab)
|
||||
t.owner = openerTab;
|
||||
this.moveTabTo(t, newTabPos, true);
|
||||
if (openerTab)
|
||||
this._lastRelatedTabMap.set(openerTab, t);
|
||||
}
|
||||
if (lastRelatedTab) {
|
||||
lastRelatedTab.owner = null;
|
||||
} else if (openerTab) {
|
||||
t.owner = openerTab;
|
||||
}
|
||||
this.moveTabTo(t, newTabPos, true);
|
||||
if (openerTab) {
|
||||
this._lastRelatedTabMap.set(openerTab, t);
|
||||
}
|
||||
}
|
||||
|
||||
// This field is updated regardless if we actually animate
|
||||
// since it's important that we keep this count correct in all cases.
|
||||
|
@ -127,6 +127,67 @@ var gTests = [
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "getUserMedia audio+video: with two frames sharing at the same time, sharing UI shows all shared devices",
|
||||
run: async function checkFrameOverridingSharingUI() {
|
||||
// This tests an edge case discovered in bug 1440356 that works like this
|
||||
// - Share audio and video in iframe 1.
|
||||
// - Share only video in iframe 2.
|
||||
// The WebRTC UI should still show both video and audio indicators.
|
||||
|
||||
let promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
await promiseRequestDevice(true, true, "frame1");
|
||||
await promise;
|
||||
await expectObserverCalled("getUserMedia:request");
|
||||
checkDeviceSelectors(true, true);
|
||||
|
||||
let indicator = promiseIndicatorWindow();
|
||||
await promiseMessage("ok", () => {
|
||||
PopupNotifications.panel.firstChild.button.click();
|
||||
});
|
||||
await expectObserverCalled("getUserMedia:response:allow");
|
||||
await expectObserverCalled("recording-device-events");
|
||||
Assert.deepEqual((await getMediaCaptureState()), {audio: true, video: true},
|
||||
"expected camera and microphone to be shared");
|
||||
|
||||
await indicator;
|
||||
await checkSharingUI({video: true, audio: true});
|
||||
await expectNoObserverCalled();
|
||||
|
||||
// Check that requesting a new device from a different frame
|
||||
// doesn't override sharing UI.
|
||||
promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
await promiseRequestDevice(false, true, "frame2");
|
||||
await promise;
|
||||
await expectObserverCalled("getUserMedia:request");
|
||||
checkDeviceSelectors(false, true);
|
||||
|
||||
await promiseMessage("ok", () => {
|
||||
PopupNotifications.panel.firstChild.button.click();
|
||||
});
|
||||
await expectObserverCalled("getUserMedia:response:allow");
|
||||
await expectObserverCalled("recording-device-events");
|
||||
Assert.deepEqual((await getMediaCaptureState()), {audio: true, video: true},
|
||||
"expected camera and microphone to be shared");
|
||||
|
||||
await checkSharingUI({video: true, audio: true});
|
||||
|
||||
// Check that ending the stream with the other frame
|
||||
// doesn't override sharing UI.
|
||||
promise = promiseObserverCalled("recording-device-events");
|
||||
await promiseReloadFrame("frame2");
|
||||
await promise;
|
||||
|
||||
await expectObserverCalled("recording-window-ended");
|
||||
await checkSharingUI({video: true, audio: true});
|
||||
await expectNoObserverCalled();
|
||||
|
||||
await closeStream(false, "frame1");
|
||||
await expectNoObserverCalled();
|
||||
await checkNotSharing();
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "getUserMedia audio+video: reloading a frame updates the sharing UI",
|
||||
run: async function checkUpdateWhenReloading() {
|
||||
|
@ -4373,7 +4373,10 @@ OverflowableToolbar.prototype = {
|
||||
this._panel.addEventListener("popupshown", () => {
|
||||
this._panel.addEventListener("dragover", this);
|
||||
this._panel.addEventListener("dragend", this);
|
||||
resolve();
|
||||
// Wait until the next tick to resolve so all popupshown
|
||||
// handlers have a chance to run before our promise resolution
|
||||
// handlers do.
|
||||
Services.tm.dispatchToMainThread(resolve);
|
||||
}, {once: true});
|
||||
});
|
||||
},
|
||||
|
@ -153,6 +153,29 @@ ChannelMediaDecoder::ResourceCallback::NotifyPrincipalChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaDecoder::NotifyPrincipalChanged()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MediaDecoder::NotifyPrincipalChanged();
|
||||
if (!mInitialChannelPrincipalKnown) {
|
||||
// We'll receive one notification when the channel's initial principal
|
||||
// is known, after all HTTP redirects have resolved. This isn't really a
|
||||
// principal change, so return here to avoid the mSameOriginMedia check
|
||||
// below.
|
||||
mInitialChannelPrincipalKnown = true;
|
||||
return;
|
||||
}
|
||||
if (!mSameOriginMedia &&
|
||||
DecoderTraits::CrossOriginRedirectsProhibited(ContainerType())) {
|
||||
// For some content types we block mid-flight channel redirects to cross
|
||||
// origin destinations due to security constraints. See bug 1441153.
|
||||
LOG("ChannnelMediaDecoder prohibited cross origin redirect blocked.");
|
||||
NetworkError(MediaResult(NS_ERROR_DOM_BAD_URI,
|
||||
"Prohibited cross origin redirect blocked"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged(
|
||||
bool aSuspendedByCache)
|
||||
|
@ -66,6 +66,7 @@ protected:
|
||||
void MetadataLoaded(UniquePtr<MediaInfo> aInfo,
|
||||
UniquePtr<MetadataTags> aTags,
|
||||
MediaDecoderEventVisibility aEventVisibility) override;
|
||||
void NotifyPrincipalChanged() override;
|
||||
|
||||
RefPtr<ResourceCallback> mResourceCallback;
|
||||
RefPtr<BaseMediaResource> mResource;
|
||||
@ -158,6 +159,10 @@ private:
|
||||
int64_t mPlaybackPosition = 0;
|
||||
|
||||
bool mCanPlayThrough = false;
|
||||
|
||||
// True if we've been notified that the ChannelMediaResource has
|
||||
// a principal.
|
||||
bool mInitialChannelPrincipalKnown = false;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -325,4 +325,11 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
||||
false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
DecoderTraits::CrossOriginRedirectsProhibited(const MediaContainerType& aType)
|
||||
{
|
||||
return WaveDecoder::IsSupportedType(aType);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -57,6 +57,10 @@ public:
|
||||
static bool IsMatroskaType(const MediaContainerType& aType);
|
||||
|
||||
static bool IsSupportedType(const MediaContainerType& aType);
|
||||
|
||||
// For some content types we block channel redirects to cross origin
|
||||
// destinations due to security constraints. See bug 1441153.
|
||||
static bool CrossOriginRedirectsProhibited(const MediaContainerType& aType);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -514,7 +514,7 @@ protected:
|
||||
|
||||
// Called by MediaResource when the principal of the resource has
|
||||
// changed. Called on main thread only.
|
||||
void NotifyPrincipalChanged();
|
||||
virtual void NotifyPrincipalChanged();
|
||||
|
||||
MozPromiseRequestHolder<SeekPromise> mSeekRequest;
|
||||
|
||||
|
@ -2196,21 +2196,6 @@ int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
|
||||
return DeviceChangeCallback::AddDeviceChangeCallback(aCallback);
|
||||
}
|
||||
|
||||
static void
|
||||
StopRawIDCallback(MediaManager *aThis,
|
||||
uint64_t aWindowID,
|
||||
GetUserMediaWindowListener *aListener,
|
||||
void *aData)
|
||||
{
|
||||
if (!aListener || !aData) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsString* removedDeviceID = static_cast<nsString*>(aData);
|
||||
aListener->StopRawID(*removedDeviceID);
|
||||
}
|
||||
|
||||
|
||||
void MediaManager::OnDeviceChange() {
|
||||
RefPtr<MediaManager> self(this);
|
||||
NS_DispatchToMainThread(media::NewRunnableFrom([self]() mutable {
|
||||
@ -2238,16 +2223,24 @@ void MediaManager::OnDeviceChange() {
|
||||
}
|
||||
|
||||
for (auto& id : self->mDeviceIDs) {
|
||||
if (!deviceIDs.Contains(id)) {
|
||||
// Stop the coresponding SourceListener
|
||||
nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
|
||||
nsGlobalWindowInner::GetWindowsTable();
|
||||
if (windowsById) {
|
||||
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsGlobalWindowInner* window = iter.Data();
|
||||
self->IterateWindowListeners(window->AsInner(), StopRawIDCallback, &id);
|
||||
}
|
||||
}
|
||||
if (deviceIDs.Contains(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Stop the coresponding SourceListener
|
||||
nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
|
||||
nsGlobalWindowInner::GetWindowsTable();
|
||||
if (!windowsById) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsGlobalWindowInner* window = iter.Data();
|
||||
self->IterateWindowListeners(window->AsInner(),
|
||||
[&id](GetUserMediaWindowListener* aListener)
|
||||
{
|
||||
aListener->StopRawID(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -3094,27 +3087,6 @@ MediaManager::GetBackend(uint64_t aWindowId)
|
||||
return mBackend;
|
||||
}
|
||||
|
||||
static void
|
||||
StopSharingCallback(MediaManager *aThis,
|
||||
uint64_t aWindowID,
|
||||
GetUserMediaWindowListener *aListener,
|
||||
void *aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Grab a strong ref since RemoveAll() might destroy the listener mid-way
|
||||
// when clearing the mActiveWindows reference.
|
||||
RefPtr<GetUserMediaWindowListener> listener(aListener);
|
||||
if (!listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
listener->Stop();
|
||||
listener->RemoveAll();
|
||||
MOZ_ASSERT(!aThis->GetWindowListener(aWindowID));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MediaManager::OnNavigation(uint64_t aWindowID)
|
||||
{
|
||||
@ -3136,7 +3108,19 @@ MediaManager::OnNavigation(uint64_t aWindowID)
|
||||
// be added to from the main-thread
|
||||
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
|
||||
if (window) {
|
||||
IterateWindowListeners(window->AsInner(), StopSharingCallback, nullptr);
|
||||
IterateWindowListeners(window->AsInner(),
|
||||
[self = RefPtr<MediaManager>(this),
|
||||
windowID = DebugOnly<decltype(aWindowID)>(aWindowID)]
|
||||
(GetUserMediaWindowListener* aListener)
|
||||
{
|
||||
// Grab a strong ref since RemoveAll() might destroy the listener
|
||||
// mid-way when clearing the mActiveWindows reference.
|
||||
RefPtr<GetUserMediaWindowListener> listener(aListener);
|
||||
|
||||
listener->Stop();
|
||||
listener->RemoveAll();
|
||||
MOZ_ASSERT(!self->GetWindowListener(windowID));
|
||||
});
|
||||
} else {
|
||||
RemoveWindowID(aWindowID);
|
||||
}
|
||||
@ -3591,63 +3575,52 @@ struct CaptureWindowStateData {
|
||||
uint16_t* mBrowserShare;
|
||||
};
|
||||
|
||||
static void
|
||||
CaptureWindowStateCallback(MediaManager *aThis,
|
||||
uint64_t aWindowID,
|
||||
GetUserMediaWindowListener *aListener,
|
||||
void *aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
|
||||
auto& data = *static_cast<CaptureWindowStateData*>(aData);
|
||||
|
||||
if (!aListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
*data.mCamera =
|
||||
FromCaptureState(aListener->CapturingSource(MediaSourceEnum::Camera));
|
||||
*data.mMicrophone =
|
||||
FromCaptureState(aListener->CapturingSource(MediaSourceEnum::Microphone));
|
||||
*data.mScreenShare =
|
||||
FromCaptureState(aListener->CapturingSource(MediaSourceEnum::Screen));
|
||||
*data.mWindowShare =
|
||||
FromCaptureState(aListener->CapturingSource(MediaSourceEnum::Window));
|
||||
*data.mAppShare =
|
||||
FromCaptureState(aListener->CapturingSource(MediaSourceEnum::Application));
|
||||
*data.mBrowserShare =
|
||||
FromCaptureState(aListener->CapturingSource(MediaSourceEnum::Browser));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaManager::MediaCaptureWindowState(nsIDOMWindow* aWindow,
|
||||
MediaManager::MediaCaptureWindowState(nsIDOMWindow* aCapturedWindow,
|
||||
uint16_t* aCamera,
|
||||
uint16_t* aMicrophone,
|
||||
uint16_t* aScreenShare,
|
||||
uint16_t* aWindowShare,
|
||||
uint16_t* aAppShare,
|
||||
uint16_t* aBrowserShare)
|
||||
uint16_t* aScreen,
|
||||
uint16_t* aWindow,
|
||||
uint16_t* aApplication,
|
||||
uint16_t* aBrowser)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
struct CaptureWindowStateData data;
|
||||
data.mCamera = aCamera;
|
||||
data.mMicrophone = aMicrophone;
|
||||
data.mScreenShare = aScreenShare;
|
||||
data.mWindowShare = aWindowShare;
|
||||
data.mAppShare = aAppShare;
|
||||
data.mBrowserShare = aBrowserShare;
|
||||
|
||||
*aCamera = nsIMediaManagerService::STATE_NOCAPTURE;
|
||||
*aMicrophone = nsIMediaManagerService::STATE_NOCAPTURE;
|
||||
*aScreenShare = nsIMediaManagerService::STATE_NOCAPTURE;
|
||||
*aWindowShare = nsIMediaManagerService::STATE_NOCAPTURE;
|
||||
*aAppShare = nsIMediaManagerService::STATE_NOCAPTURE;
|
||||
*aBrowserShare = nsIMediaManagerService::STATE_NOCAPTURE;
|
||||
CaptureState camera = CaptureState::Off;
|
||||
CaptureState microphone = CaptureState::Off;
|
||||
CaptureState screen = CaptureState::Off;
|
||||
CaptureState window = CaptureState::Off;
|
||||
CaptureState application = CaptureState::Off;
|
||||
CaptureState browser = CaptureState::Off;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> piWin = do_QueryInterface(aWindow);
|
||||
nsCOMPtr<nsPIDOMWindowInner> piWin = do_QueryInterface(aCapturedWindow);
|
||||
if (piWin) {
|
||||
IterateWindowListeners(piWin, CaptureWindowStateCallback, &data);
|
||||
IterateWindowListeners(piWin,
|
||||
[&camera, µphone, &screen, &window, &application, &browser]
|
||||
(GetUserMediaWindowListener* aListener)
|
||||
{
|
||||
camera = CombineCaptureState(
|
||||
camera, aListener->CapturingSource(MediaSourceEnum::Camera));
|
||||
microphone = CombineCaptureState(
|
||||
microphone, aListener->CapturingSource(MediaSourceEnum::Microphone));
|
||||
screen = CombineCaptureState(
|
||||
screen, aListener->CapturingSource(MediaSourceEnum::Screen));
|
||||
window = CombineCaptureState(
|
||||
window, aListener->CapturingSource(MediaSourceEnum::Window));
|
||||
application = CombineCaptureState(
|
||||
application, aListener->CapturingSource(MediaSourceEnum::Application));
|
||||
browser = CombineCaptureState(
|
||||
browser, aListener->CapturingSource(MediaSourceEnum::Browser));
|
||||
});
|
||||
}
|
||||
|
||||
*aCamera = FromCaptureState(camera);
|
||||
*aMicrophone= FromCaptureState(microphone);
|
||||
*aScreen = FromCaptureState(screen);
|
||||
*aWindow = FromCaptureState(window);
|
||||
*aApplication = FromCaptureState(application);
|
||||
*aBrowser = FromCaptureState(browser);
|
||||
|
||||
#ifdef DEBUG
|
||||
LOG(("%s: window %" PRIu64 " capturing %s %s %s %s %s %s", __FUNCTION__, piWin ? piWin->WindowID() : -1,
|
||||
*aCamera == nsIMediaManagerService::STATE_CAPTURE_ENABLED
|
||||
@ -3658,10 +3631,10 @@ MediaManager::MediaCaptureWindowState(nsIDOMWindow* aWindow,
|
||||
? "microphone (enabled)"
|
||||
: (*aMicrophone == nsIMediaManagerService::STATE_CAPTURE_DISABLED
|
||||
? "microphone (disabled)" : ""),
|
||||
*aScreenShare ? "screenshare" : "",
|
||||
*aWindowShare ? "windowshare" : "",
|
||||
*aAppShare ? "appshare" : "",
|
||||
*aBrowserShare ? "browsershare" : ""));
|
||||
*aScreen ? "screenshare" : "",
|
||||
*aWindow ? "windowshare" : "",
|
||||
*aApplication ? "appshare" : "",
|
||||
*aBrowser ? "browsershare" : ""));
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
@ -3676,19 +3649,6 @@ MediaManager::SanitizeDeviceIds(int64_t aSinceWhen)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
StopScreensharingCallback(MediaManager *aThis,
|
||||
uint64_t aWindowID,
|
||||
GetUserMediaWindowListener *aListener,
|
||||
void *aData)
|
||||
{
|
||||
if (!aListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
aListener->StopSharing();
|
||||
}
|
||||
|
||||
void
|
||||
MediaManager::StopScreensharing(uint64_t aWindowID)
|
||||
{
|
||||
@ -3699,14 +3659,17 @@ MediaManager::StopScreensharing(uint64_t aWindowID)
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
IterateWindowListeners(window->AsInner(), &StopScreensharingCallback, nullptr);
|
||||
IterateWindowListeners(window->AsInner(),
|
||||
[](GetUserMediaWindowListener* aListener)
|
||||
{
|
||||
aListener->StopSharing();
|
||||
});
|
||||
}
|
||||
|
||||
// lets us do all sorts of things to the listeners
|
||||
template<typename FunctionType>
|
||||
void
|
||||
MediaManager::IterateWindowListeners(nsPIDOMWindowInner* aWindow,
|
||||
WindowListenerCallback aCallback,
|
||||
void *aData)
|
||||
const FunctionType& aCallback)
|
||||
{
|
||||
// Iterate the docshell tree to find all the child windows, and for each
|
||||
// invoke the callback
|
||||
@ -3714,7 +3677,9 @@ MediaManager::IterateWindowListeners(nsPIDOMWindowInner* aWindow,
|
||||
{
|
||||
uint64_t windowID = aWindow->WindowID();
|
||||
GetUserMediaWindowListener* listener = GetWindowListener(windowID);
|
||||
(*aCallback)(this, windowID, listener, aData);
|
||||
if (listener) {
|
||||
aCallback(listener);
|
||||
}
|
||||
// NB: `listener` might have been destroyed.
|
||||
}
|
||||
|
||||
@ -3729,8 +3694,7 @@ MediaManager::IterateWindowListeners(nsPIDOMWindowInner* aWindow,
|
||||
nsCOMPtr<nsPIDOMWindowOuter> winOuter = item ? item->GetWindow() : nullptr;
|
||||
|
||||
if (winOuter) {
|
||||
IterateWindowListeners(winOuter->GetCurrentInnerWindow(),
|
||||
aCallback, aData);
|
||||
IterateWindowListeners(winOuter->GetCurrentInnerWindow(), aCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,12 +127,6 @@ public:
|
||||
|
||||
typedef nsRefPtrHashtable<nsUint64HashKey, GetUserMediaWindowListener> WindowTable;
|
||||
|
||||
// we could add MediaManager if needed
|
||||
typedef void (*WindowListenerCallback)(MediaManager *aThis,
|
||||
uint64_t aWindowID,
|
||||
GetUserMediaWindowListener *aListener,
|
||||
void *aData);
|
||||
|
||||
class MediaManager final : public nsIMediaManagerService,
|
||||
public nsIObserver
|
||||
,public DeviceChangeCallback
|
||||
@ -253,9 +247,14 @@ private:
|
||||
void Shutdown();
|
||||
|
||||
void StopScreensharing(uint64_t aWindowID);
|
||||
|
||||
/**
|
||||
* Calls aCallback with a GetUserMediaWindowListener argument once for
|
||||
* each window listener associated with aWindow and its child windows.
|
||||
*/
|
||||
template<typename FunctionType>
|
||||
void IterateWindowListeners(nsPIDOMWindowInner *aWindow,
|
||||
WindowListenerCallback aCallback,
|
||||
void *aData);
|
||||
const FunctionType& aCallback);
|
||||
|
||||
void StopMediaStreams();
|
||||
void RemoveMediaDevicesCallback(uint64_t aWindowID);
|
||||
|
@ -1947,7 +1947,7 @@ void
|
||||
ServiceWorkerPrivate::StoreISupports(nsISupports* aSupports)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate);
|
||||
MOZ_ASSERT(!mSupportsArray.Contains(aSupports));
|
||||
|
||||
mSupportsArray.AppendElement(aSupports);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "ServiceWorker.h"
|
||||
#include "ServiceWorkerManager.h"
|
||||
#include "ServiceWorkerPrivate.h"
|
||||
#include "ServiceWorkerRegistration.h"
|
||||
|
||||
#include "nsIDocument.h"
|
||||
@ -133,7 +134,7 @@ namespace {
|
||||
|
||||
void
|
||||
UpdateInternal(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aScope,
|
||||
const nsACString& aScope,
|
||||
ServiceWorkerUpdateFinishCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
@ -146,7 +147,7 @@ UpdateInternal(nsIPrincipal* aPrincipal,
|
||||
return;
|
||||
}
|
||||
|
||||
swm->Update(aPrincipal, NS_ConvertUTF16toUTF8(aScope), aCallback);
|
||||
swm->Update(aPrincipal, aScope, aCallback);
|
||||
}
|
||||
|
||||
class MainThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
|
||||
@ -281,12 +282,52 @@ public:
|
||||
|
||||
class SWRUpdateRunnable final : public Runnable
|
||||
{
|
||||
class TimerCallback final : public nsITimerCallback
|
||||
{
|
||||
RefPtr<ServiceWorkerPrivate> mPrivate;
|
||||
RefPtr<Runnable> mRunnable;
|
||||
|
||||
public:
|
||||
TimerCallback(ServiceWorkerPrivate* aPrivate,
|
||||
Runnable* aRunnable)
|
||||
: mPrivate(aPrivate)
|
||||
, mRunnable(aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(mPrivate);
|
||||
MOZ_ASSERT(aRunnable);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Notify(nsITimer *aTimer) override
|
||||
{
|
||||
mRunnable->Run();
|
||||
mPrivate->RemoveISupports(aTimer);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
private:
|
||||
~TimerCallback()
|
||||
{ }
|
||||
};
|
||||
|
||||
public:
|
||||
SWRUpdateRunnable(PromiseWorkerProxy* aPromiseProxy, const nsAString& aScope)
|
||||
explicit SWRUpdateRunnable(PromiseWorkerProxy* aPromiseProxy)
|
||||
: Runnable("dom::SWRUpdateRunnable")
|
||||
, mPromiseProxy(aPromiseProxy)
|
||||
, mScope(aScope)
|
||||
{}
|
||||
, mDescriptor(aPromiseProxy->GetWorkerPrivate()->GetServiceWorkerDescriptor())
|
||||
, mDelayed(false)
|
||||
{
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
|
||||
// This runnable is used for update calls originating from a worker thread,
|
||||
// which may be delayed in some cases.
|
||||
MOZ_ASSERT(mPromiseProxy->GetWorkerPrivate()->IsServiceWorker());
|
||||
MOZ_ASSERT(mPromiseProxy->GetWorkerPrivate());
|
||||
mPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
@ -307,20 +348,65 @@ public:
|
||||
}
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
if (NS_WARN_IF(!swm)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This will delay update jobs originating from a service worker thread.
|
||||
// We don't currently handle ServiceWorkerRegistration.update() from other
|
||||
// worker types. Also, we assume this registration matches self.registration
|
||||
// on the service worker global. This is ok for now because service worker globals
|
||||
// are the only worker contexts where we expose ServiceWorkerRegistration.
|
||||
RefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
swm->GetRegistration(principal, mDescriptor.Scope());
|
||||
if (NS_WARN_IF(!registration)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerInfo> worker = registration->GetByDescriptor(mDescriptor);
|
||||
uint32_t delay = registration->GetUpdateDelay();
|
||||
|
||||
// if we have a timer object, it means we've already been delayed once.
|
||||
if (delay && !mDelayed) {
|
||||
nsCOMPtr<nsITimerCallback> cb = new TimerCallback(worker->WorkerPrivate(), this);
|
||||
Result<nsCOMPtr<nsITimer>, nsresult> result =
|
||||
NS_NewTimerWithCallback(cb, delay, nsITimer::TYPE_ONE_SHOT,
|
||||
SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||
|
||||
nsCOMPtr<nsITimer> timer = result.unwrapOr(nullptr);
|
||||
if (NS_WARN_IF(!timer)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDelayed = true;
|
||||
// We're storing the timer object on the calling service worker's private.
|
||||
// ServiceWorkerPrivate will drop the reference if the worker terminates,
|
||||
// which will cancel the timer.
|
||||
worker->WorkerPrivate()->StoreISupports(timer);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<WorkerThreadUpdateCallback> cb =
|
||||
new WorkerThreadUpdateCallback(mPromiseProxy);
|
||||
UpdateInternal(principal, mScope, cb);
|
||||
UpdateInternal(principal, mDescriptor.Scope(), cb);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~SWRUpdateRunnable()
|
||||
{}
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
RefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
const nsString mScope;
|
||||
const ServiceWorkerDescriptor mDescriptor;
|
||||
bool mDelayed;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SWRUpdateRunnable::TimerCallback, nsITimerCallback)
|
||||
|
||||
class UnregisterCallback final : public nsIServiceWorkerUnregisterCallback
|
||||
{
|
||||
PromiseWindowProxy mPromise;
|
||||
@ -533,7 +619,7 @@ ServiceWorkerRegistrationMainThread::Update(ErrorResult& aRv)
|
||||
|
||||
RefPtr<MainThreadUpdateCallback> cb =
|
||||
new MainThreadUpdateCallback(mOuter->GetOwner(), promise);
|
||||
UpdateInternal(doc->NodePrincipal(), mScope, cb);
|
||||
UpdateInternal(doc->NodePrincipal(), NS_ConvertUTF16toUTF8(mScope), cb);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
@ -848,7 +934,7 @@ ServiceWorkerRegistrationWorkerThread::Update(ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SWRUpdateRunnable> r = new SWRUpdateRunnable(proxy, mScope);
|
||||
RefPtr<SWRUpdateRunnable> r = new SWRUpdateRunnable(proxy);
|
||||
MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget()));
|
||||
|
||||
return promise.forget();
|
||||
|
@ -87,6 +87,7 @@ ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
|
||||
: mPrincipal(aPrincipal)
|
||||
, mDescriptor(aPrincipal, aScope, aUpdateViaCache)
|
||||
, mControlledClientsCounter(0)
|
||||
, mDelayMultiplier(0)
|
||||
, mUpdateState(NoUpdate)
|
||||
, mCreationTime(PR_Now())
|
||||
, mCreationTimeStamp(TimeStamp::Now())
|
||||
@ -709,5 +710,25 @@ ServiceWorkerRegistrationInfo::Descriptor() const
|
||||
return mDescriptor;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ServiceWorkerRegistrationInfo::GetUpdateDelay()
|
||||
{
|
||||
uint32_t delay = Preferences::GetInt("dom.serviceWorkers.update_delay",
|
||||
1000);
|
||||
// This can potentially happen if you spam registration->Update(). We don't
|
||||
// want to wrap to a lower value.
|
||||
if (mDelayMultiplier >= INT_MAX / (delay ? delay : 1)) {
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
delay *= mDelayMultiplier;
|
||||
|
||||
if (!mControlledClientsCounter && mDelayMultiplier < (INT_MAX / 30)) {
|
||||
mDelayMultiplier = (mDelayMultiplier ? mDelayMultiplier : 1) * 30;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -23,6 +23,7 @@ class ServiceWorkerRegistrationInfo final
|
||||
nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners;
|
||||
|
||||
uint32_t mControlledClientsCounter;
|
||||
uint32_t mDelayMultiplier;
|
||||
|
||||
enum
|
||||
{
|
||||
@ -94,6 +95,7 @@ public:
|
||||
StartControllingClient()
|
||||
{
|
||||
++mControlledClientsCounter;
|
||||
mDelayMultiplier = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -211,6 +213,9 @@ public:
|
||||
const ServiceWorkerRegistrationDescriptor&
|
||||
Descriptor() const;
|
||||
|
||||
uint32_t
|
||||
GetUpdateDelay();
|
||||
|
||||
private:
|
||||
// Roughly equivalent to [[Update Registration State algorithm]]. Make sure
|
||||
// this is called *before* updating SW instances' state, otherwise they
|
||||
|
@ -232,6 +232,7 @@ support-files =
|
||||
bug1290951_worker_imported.sjs
|
||||
sw_storage_not_allow.js
|
||||
update_worker.sjs
|
||||
self_update_worker.sjs
|
||||
|
||||
[test_bug1151916.html]
|
||||
[test_bug1240436.html]
|
||||
@ -348,3 +349,4 @@ tags = openwindow
|
||||
[test_bad_script_cache.html]
|
||||
[test_file_upload.html]
|
||||
support-files = script_file_upload.js sw_file_upload.js server_file_upload.sjs
|
||||
[test_self_update_worker.html]
|
||||
|
43
dom/serviceworkers/test/self_update_worker.sjs
Normal file
43
dom/serviceworkers/test/self_update_worker.sjs
Normal file
@ -0,0 +1,43 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const WORKER_BODY = `
|
||||
onactivate = function(event) {
|
||||
let promise = clients.matchAll({includeUncontrolled: true}).then(function(clients) {
|
||||
for (i = 0; i < clients.length; i++) {
|
||||
clients[i].postMessage({version: version});
|
||||
}
|
||||
}).then(function() {
|
||||
return self.registration.update();
|
||||
});
|
||||
event.waitUntil(promise);
|
||||
};
|
||||
`;
|
||||
|
||||
function handleRequest(request, response) {
|
||||
if (request.queryString == 'clearcounter') {
|
||||
setState('count', "1");
|
||||
response.write("ok");
|
||||
return;
|
||||
}
|
||||
|
||||
let count = getState("count");
|
||||
if (count === "") {
|
||||
count = 1;
|
||||
} else {
|
||||
count = parseInt(count);
|
||||
}
|
||||
|
||||
let worker = "var version = " + count + ";\n";
|
||||
worker = worker + WORKER_BODY;
|
||||
|
||||
// This header is necessary for making this script able to be loaded.
|
||||
response.setHeader("Content-Type", "application/javascript");
|
||||
|
||||
// If this is the first request, return the first source.
|
||||
response.write(worker);
|
||||
setState("count", "" + (count + 1));
|
||||
}
|
||||
|
79
dom/serviceworkers/test/test_self_update_worker.html
Normal file
79
dom/serviceworkers/test/test_self_update_worker.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test that a self updating service worker can't keep running forever when the
|
||||
script changes.
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1432846</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="error_reporting_helpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1432846">Mozilla Bug 1432846</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script src="utils.js"></script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
add_task(function setupPrefs() {
|
||||
return SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]});
|
||||
});
|
||||
|
||||
function activateDummyWorker() {
|
||||
return navigator.serviceWorker.register("empty.js",
|
||||
{ scope: "./empty?random=" + Date.now() })
|
||||
.then(function(registration) {
|
||||
var worker = registration.installing;
|
||||
return waitForState(worker, 'activated', registration).then(function() {
|
||||
ok(true, "got dummy!");
|
||||
return registration.unregister();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_update() {
|
||||
navigator.serviceWorker.onmessage = function(event) {
|
||||
ok (event.data.version < 3, "Service worker updated too many times." + event.data.version);
|
||||
}
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.idle_timeout", 0],
|
||||
["dom.serviceWorkers.update_delay", 30000],
|
||||
["dom.serviceWorkers.idle_extended_timeout", 299999]]});
|
||||
|
||||
// clear version counter
|
||||
await fetch("self_update_worker.sjs?clearcounter");
|
||||
|
||||
var worker;
|
||||
let registration = await navigator.serviceWorker.register(
|
||||
"self_update_worker.sjs",
|
||||
{ scope: "./test_self_update_worker.html?random=" + Date.now()})
|
||||
.then(function(registration) {
|
||||
worker = registration.installing;
|
||||
return waitForState(worker, 'activated', registration);
|
||||
});
|
||||
|
||||
// We need to wait a reasonable time to give the self updating worker a chance
|
||||
// to change to a newer version. Register and activate an empty worker 5 times.
|
||||
for (i = 0; i < 5; i++) {
|
||||
await activateDummyWorker();
|
||||
}
|
||||
|
||||
|
||||
await registration.unregister();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -19,7 +19,7 @@ There's only a simple example function that tries to register and sign right now
|
||||
configure with the `RUST_LOG` environment variable:
|
||||
|
||||
```
|
||||
cargo build
|
||||
cargo build --example main
|
||||
RUST_LOG=debug cargo run --example main
|
||||
```
|
||||
|
||||
@ -45,6 +45,6 @@ To fuzz, you will need cargo-fuzz (the latest version from GitHub) as well as Ru
|
||||
rustup install nightly
|
||||
cargo install --git https://github.com/rust-fuzz/cargo-fuzz/
|
||||
|
||||
rustup run nightly cargo fuzz run u2f_read -- -max_len=512
|
||||
rustup run nightly cargo fuzz run u2f_read_write -- -max_len=512
|
||||
cargo +nightly fuzz run u2f_read -- -max_len=512
|
||||
cargo +nightly fuzz run u2f_read_write -- -max_len=512
|
||||
```
|
||||
|
@ -11,8 +11,17 @@ use std::io;
|
||||
use std::sync::mpsc::channel;
|
||||
use u2fhid::{AuthenticatorTransports, KeyHandle, RegisterFlags, SignFlags, U2FManager};
|
||||
|
||||
extern crate log;
|
||||
extern crate env_logger;
|
||||
extern crate log;
|
||||
|
||||
macro_rules! try_or {
|
||||
($val:expr, $or:expr) => {
|
||||
match $val {
|
||||
Ok(v) => { v }
|
||||
Err(e) => { return $or(e); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn u2f_get_key_handle_from_register_response(register_response: &Vec<u8>) -> io::Result<Vec<u8>> {
|
||||
if register_response[0] != 0x05 {
|
||||
@ -34,8 +43,7 @@ fn main() {
|
||||
env_logger::init().expect("Cannot start logger");
|
||||
|
||||
println!("Asking a security key to register now...");
|
||||
let challenge_str =
|
||||
format!("{}{}",
|
||||
let challenge_str = format!("{}{}",
|
||||
r#"{"challenge": "1vQ9mxionq0ngCnjD-wTsv1zUSrGRtFqG2xP09SbZ70","#,
|
||||
r#" "version": "U2F_V2", "appId": "http://demo.yubico.com"}"#);
|
||||
let mut challenge = Sha256::new();
|
||||
@ -59,13 +67,14 @@ fn main() {
|
||||
chall_bytes.clone(),
|
||||
app_bytes.clone(),
|
||||
vec![],
|
||||
move |rv| { tx.send(rv.unwrap()).unwrap(); },
|
||||
move |rv| {
|
||||
tx.send(rv.unwrap()).unwrap();
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let register_data = try_or!(rx.recv(), |_| {
|
||||
panic!("Problem receiving, unable to continue");
|
||||
return;
|
||||
});
|
||||
println!("Register result: {}", base64::encode(®ister_data));
|
||||
println!("Asking a security key to sign now, with the data from the register...");
|
||||
@ -84,13 +93,16 @@ fn main() {
|
||||
chall_bytes,
|
||||
vec![app_bytes],
|
||||
vec![key_handle],
|
||||
move |rv| { tx.send(rv.unwrap()).unwrap(); },
|
||||
move |rv| {
|
||||
tx.send(rv.unwrap()).unwrap();
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (_, sign_data) = try_or!(rx.recv(), |_| {
|
||||
let (_, handle_used, sign_data) = try_or!(rx.recv(), |_| {
|
||||
println!("Problem receiving");
|
||||
});
|
||||
println!("Sign result: {}", base64::encode(&sign_data));
|
||||
println!("Key handle used: {}", base64::encode(&handle_used));
|
||||
println!("Done.");
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ pub unsafe extern "C" fn rust_u2f_app_ids_new() -> *mut U2FAppIds {
|
||||
pub unsafe extern "C" fn rust_u2f_app_ids_add(
|
||||
ids: *mut U2FAppIds,
|
||||
id_ptr: *const u8,
|
||||
id_len: usize
|
||||
id_len: usize,
|
||||
) {
|
||||
(*ids).push(from_raw(id_ptr, id_len));
|
||||
}
|
||||
@ -177,7 +177,11 @@ pub unsafe extern "C" fn rust_u2f_mgr_register(
|
||||
},
|
||||
);
|
||||
|
||||
if res.is_ok() { tid } else { 0 }
|
||||
if res.is_ok() {
|
||||
tid
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -211,26 +215,23 @@ pub unsafe extern "C" fn rust_u2f_mgr_sign(
|
||||
let key_handles = (*khs).clone();
|
||||
|
||||
let tid = new_tid();
|
||||
let res = (*mgr).sign(
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
app_ids,
|
||||
key_handles,
|
||||
move |rv| {
|
||||
if let Ok((app_id, key_handle, signature)) = rv {
|
||||
let mut result = U2FResult::new();
|
||||
result.insert(RESBUF_ID_KEYHANDLE, key_handle);
|
||||
result.insert(RESBUF_ID_SIGNATURE, signature);
|
||||
result.insert(RESBUF_ID_APPID, app_id);
|
||||
callback(tid, Box::into_raw(Box::new(result)));
|
||||
} else {
|
||||
callback(tid, ptr::null_mut());
|
||||
};
|
||||
},
|
||||
);
|
||||
let res = (*mgr).sign(flags, timeout, challenge, app_ids, key_handles, move |rv| {
|
||||
if let Ok((app_id, key_handle, signature)) = rv {
|
||||
let mut result = U2FResult::new();
|
||||
result.insert(RESBUF_ID_KEYHANDLE, key_handle);
|
||||
result.insert(RESBUF_ID_SIGNATURE, signature);
|
||||
result.insert(RESBUF_ID_APPID, app_id);
|
||||
callback(tid, Box::into_raw(Box::new(result)));
|
||||
} else {
|
||||
callback(tid, ptr::null_mut());
|
||||
};
|
||||
});
|
||||
|
||||
if res.is_ok() { tid } else { 0 }
|
||||
if res.is_ok() {
|
||||
tid
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -27,11 +27,11 @@ pub mod platform;
|
||||
#[path = "stub/mod.rs"]
|
||||
pub mod platform;
|
||||
|
||||
extern crate boxfnonce;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rand;
|
||||
extern crate libc;
|
||||
extern crate boxfnonce;
|
||||
extern crate runloop;
|
||||
|
||||
#[macro_use]
|
||||
|
@ -8,7 +8,7 @@ use std::io;
|
||||
use std::mem;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
use consts::{FIDO_USAGE_PAGE, FIDO_USAGE_U2FHID};
|
||||
use consts::{FIDO_USAGE_U2FHID, FIDO_USAGE_PAGE};
|
||||
use util::{from_unix_result, io_err};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
|
@ -89,9 +89,10 @@ where
|
||||
}
|
||||
|
||||
fn process_event(&mut self, event: libudev::Event) {
|
||||
let path = event.device().devnode().map(
|
||||
|dn| dn.to_owned().into_os_string(),
|
||||
);
|
||||
let path = event
|
||||
.device()
|
||||
.devnode()
|
||||
.map(|dn| dn.to_owned().into_os_string());
|
||||
|
||||
match (event.event_type(), path) {
|
||||
(EventType::Add, Some(path)) => {
|
||||
@ -108,8 +109,10 @@ where
|
||||
let f = self.new_device_cb.clone();
|
||||
let key = path.clone();
|
||||
|
||||
let runloop = RunLoop::new(move |alive| if alive() {
|
||||
f(path, alive);
|
||||
let runloop = RunLoop::new(move |alive| {
|
||||
if alive() {
|
||||
f(path, alive);
|
||||
}
|
||||
});
|
||||
|
||||
if let Ok(runloop) = runloop {
|
||||
|
@ -33,7 +33,9 @@ impl Transaction {
|
||||
timeout,
|
||||
)?;
|
||||
|
||||
Ok(Self { thread: Some(thread) })
|
||||
Ok(Self {
|
||||
thread: Some(thread),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn cancel(&mut self) {
|
||||
|
@ -7,7 +7,7 @@
|
||||
extern crate core_foundation_sys;
|
||||
extern crate libc;
|
||||
|
||||
use consts::{FIDO_USAGE_PAGE, FIDO_USAGE_U2FHID};
|
||||
use consts::{FIDO_USAGE_U2FHID, FIDO_USAGE_PAGE};
|
||||
use core_foundation_sys::base::*;
|
||||
use core_foundation_sys::dictionary::*;
|
||||
use core_foundation_sys::number::*;
|
||||
@ -23,19 +23,23 @@ pub type IOReturn = libc::c_int;
|
||||
pub type IOHIDManagerRef = *mut __IOHIDManager;
|
||||
pub type IOHIDManagerOptions = IOOptionBits;
|
||||
|
||||
pub type IOHIDDeviceCallback = extern "C" fn(context: *mut c_void,
|
||||
result: IOReturn,
|
||||
sender: *mut c_void,
|
||||
device: IOHIDDeviceRef);
|
||||
pub type IOHIDDeviceCallback = extern "C" fn(
|
||||
context: *mut c_void,
|
||||
result: IOReturn,
|
||||
sender: *mut c_void,
|
||||
device: IOHIDDeviceRef,
|
||||
);
|
||||
|
||||
pub type IOHIDReportType = IOOptionBits;
|
||||
pub type IOHIDReportCallback = extern "C" fn(context: *mut c_void,
|
||||
result: IOReturn,
|
||||
sender: IOHIDDeviceRef,
|
||||
report_type: IOHIDReportType,
|
||||
report_id: u32,
|
||||
report: *mut u8,
|
||||
report_len: CFIndex);
|
||||
pub type IOHIDReportCallback = extern "C" fn(
|
||||
context: *mut c_void,
|
||||
result: IOReturn,
|
||||
sender: IOHIDDeviceRef,
|
||||
report_type: IOHIDReportType,
|
||||
report_id: u32,
|
||||
report: *mut u8,
|
||||
report_len: CFIndex,
|
||||
);
|
||||
|
||||
pub const kIOHIDManagerOptionNone: IOHIDManagerOptions = 0;
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
* 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/. */
|
||||
|
||||
extern crate log;
|
||||
extern crate libc;
|
||||
extern crate log;
|
||||
|
||||
use core_foundation_sys::base::*;
|
||||
use core_foundation_sys::runloop::*;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc::{channel, Sender, RecvTimeoutError};
|
||||
use std::sync::mpsc::{channel, RecvTimeoutError, Sender};
|
||||
use std::time::Duration;
|
||||
|
||||
use consts::PARAMETER_SIZE;
|
||||
@ -47,13 +47,13 @@ impl U2FManager {
|
||||
while alive() {
|
||||
match rx.recv_timeout(Duration::from_millis(50)) {
|
||||
Ok(QueueAction::Register {
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
application,
|
||||
key_handles,
|
||||
callback,
|
||||
}) => {
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
application,
|
||||
key_handles,
|
||||
callback,
|
||||
}) => {
|
||||
// This must not block, otherwise we can't cancel.
|
||||
sm.register(
|
||||
flags,
|
||||
@ -65,22 +65,15 @@ impl U2FManager {
|
||||
);
|
||||
}
|
||||
Ok(QueueAction::Sign {
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
app_ids,
|
||||
key_handles,
|
||||
callback,
|
||||
}) => {
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
app_ids,
|
||||
key_handles,
|
||||
callback,
|
||||
}) => {
|
||||
// This must not block, otherwise we can't cancel.
|
||||
sm.sign(
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
app_ids,
|
||||
key_handles,
|
||||
callback,
|
||||
);
|
||||
sm.sign(flags, timeout, challenge, app_ids, key_handles, callback);
|
||||
}
|
||||
Ok(QueueAction::Cancel) => {
|
||||
// Cancelling must block so that we don't start a new
|
||||
@ -173,12 +166,12 @@ impl U2FManager {
|
||||
}
|
||||
|
||||
for app_id in &app_ids {
|
||||
if app_id.len() != PARAMETER_SIZE {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid app_id size",
|
||||
));
|
||||
}
|
||||
if app_id.len() != PARAMETER_SIZE {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid app_id size",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
for key_handle in &key_handles {
|
||||
|
@ -24,16 +24,16 @@ where
|
||||
{
|
||||
// Try all given app_ids in order.
|
||||
for app_id in app_ids {
|
||||
// Find all valid key handles for the current app_id.
|
||||
let valid_handles = key_handles
|
||||
.iter()
|
||||
.filter(|key_handle| is_valid(app_id, key_handle))
|
||||
.collect::<Vec<_>>();
|
||||
// Find all valid key handles for the current app_id.
|
||||
let valid_handles = key_handles
|
||||
.iter()
|
||||
.filter(|key_handle| is_valid(app_id, key_handle))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// If there's at least one, stop.
|
||||
if valid_handles.len() > 0 {
|
||||
return (app_id, valid_handles);
|
||||
}
|
||||
// If there's at least one, stop.
|
||||
if valid_handles.len() > 0 {
|
||||
return (app_id, valid_handles);
|
||||
}
|
||||
}
|
||||
|
||||
return (&app_ids[0], vec![]);
|
||||
@ -87,20 +87,26 @@ impl StateMachine {
|
||||
}
|
||||
|
||||
// Iterate the exclude list and see if there are any matches.
|
||||
// Abort the state machine if we found a valid key handle.
|
||||
if key_handles.iter().any(|key_handle| {
|
||||
is_valid_transport(key_handle.transports) &&
|
||||
u2f_is_keyhandle_valid(dev, &challenge, &application, &key_handle.credential)
|
||||
// If so, we'll keep polling the device anyway to test for user
|
||||
// consent, to be consistent with CTAP2 device behavior.
|
||||
let excluded = key_handles.iter().any(|key_handle| {
|
||||
is_valid_transport(key_handle.transports)
|
||||
&& u2f_is_keyhandle_valid(dev, &challenge, &application, &key_handle.credential)
|
||||
.unwrap_or(false) /* no match on failure */
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
while alive() {
|
||||
if let Ok(bytes) = u2f_register(dev, &challenge, &application) {
|
||||
callback.call(Ok(bytes));
|
||||
break;
|
||||
if excluded {
|
||||
let blank = vec![0u8; PARAMETER_SIZE];
|
||||
if let Ok(_) = u2f_register(dev, &blank, &blank) {
|
||||
callback.call(Err(io_err("duplicate registration")));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if let Ok(bytes) = u2f_register(dev, &challenge, &application) {
|
||||
callback.call(Ok(bytes));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep a bit before trying again.
|
||||
@ -108,9 +114,9 @@ impl StateMachine {
|
||||
}
|
||||
});
|
||||
|
||||
self.transaction = Some(try_or!(transaction, |_| {
|
||||
cbc.call(Err(io_err("couldn't create transaction")))
|
||||
}));
|
||||
self.transaction = Some(try_or!(transaction, |_| cbc.call(Err(io_err(
|
||||
"couldn't create transaction"
|
||||
)))));
|
||||
}
|
||||
|
||||
pub fn sign(
|
||||
@ -153,18 +159,17 @@ impl StateMachine {
|
||||
// For each appId, try all key handles. If there's at least one
|
||||
// valid key handle for an appId, we'll use that appId below.
|
||||
let (app_id, valid_handles) =
|
||||
find_valid_key_handles(&app_ids, &key_handles,
|
||||
|app_id, key_handle| {
|
||||
u2f_is_keyhandle_valid(dev, &challenge, app_id,
|
||||
&key_handle.credential)
|
||||
.unwrap_or(false) /* no match on failure */
|
||||
});
|
||||
find_valid_key_handles(&app_ids, &key_handles, |app_id, key_handle| {
|
||||
u2f_is_keyhandle_valid(dev, &challenge, app_id, &key_handle.credential)
|
||||
.unwrap_or(false) /* no match on failure */
|
||||
});
|
||||
|
||||
// Aggregate distinct transports from all given credentials.
|
||||
let transports = key_handles.iter().fold(
|
||||
::AuthenticatorTransports::empty(),
|
||||
|t, k| t | k.transports,
|
||||
);
|
||||
let transports = key_handles
|
||||
.iter()
|
||||
.fold(::AuthenticatorTransports::empty(), |t, k| {
|
||||
t | k.transports
|
||||
});
|
||||
|
||||
// We currently only support USB. If the RP specifies transports
|
||||
// and doesn't include USB it's probably lying.
|
||||
@ -184,16 +189,13 @@ impl StateMachine {
|
||||
} else {
|
||||
// Otherwise, try to sign.
|
||||
for key_handle in &valid_handles {
|
||||
if let Ok(bytes) = u2f_sign(
|
||||
dev,
|
||||
&challenge,
|
||||
app_id,
|
||||
&key_handle.credential,
|
||||
)
|
||||
if let Ok(bytes) = u2f_sign(dev, &challenge, app_id, &key_handle.credential)
|
||||
{
|
||||
callback.call(Ok((app_id.clone(),
|
||||
key_handle.credential.clone(),
|
||||
bytes)));
|
||||
callback.call(Ok((
|
||||
app_id.clone(),
|
||||
key_handle.credential.clone(),
|
||||
bytes,
|
||||
)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -204,9 +206,9 @@ impl StateMachine {
|
||||
}
|
||||
});
|
||||
|
||||
self.transaction = Some(try_or!(transaction, |_| {
|
||||
cbc.call(Err(io_err("couldn't create transaction")))
|
||||
}));
|
||||
self.transaction = Some(try_or!(transaction, |_| cbc.call(Err(io_err(
|
||||
"couldn't create transaction"
|
||||
)))));
|
||||
}
|
||||
|
||||
// This blocks.
|
||||
|
@ -235,8 +235,8 @@ where
|
||||
mod tests {
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use super::{U2FDevice, init_device, ping_device, sendrecv, send_apdu};
|
||||
use consts::{CID_BROADCAST, U2FHID_INIT, U2FHID_PING, U2FHID_MSG, SW_NO_ERROR};
|
||||
use super::{init_device, ping_device, send_apdu, sendrecv, U2FDevice};
|
||||
use consts::{U2FHID_INIT, U2FHID_MSG, U2FHID_PING, CID_BROADCAST, SW_NO_ERROR};
|
||||
|
||||
mod platform {
|
||||
use std::io;
|
||||
@ -358,21 +358,21 @@ mod tests {
|
||||
// init packet
|
||||
let mut msg = cid.to_vec();
|
||||
msg.extend(vec![U2FHID_PING, 0x00, 0xe4]); // cmd + length = 228
|
||||
// write msg, append [1u8; 57], 171 bytes remaining
|
||||
// write msg, append [1u8; 57], 171 bytes remain
|
||||
device.add_write(&msg, 1);
|
||||
device.add_read(&msg, 1);
|
||||
|
||||
// cont packet
|
||||
let mut msg = cid.to_vec();
|
||||
msg.push(0x00); // seq = 0
|
||||
// write msg, append [1u8; 59], 112 bytes remaining
|
||||
// write msg, append [1u8; 59], 112 bytes remaining
|
||||
device.add_write(&msg, 1);
|
||||
device.add_read(&msg, 1);
|
||||
|
||||
// cont packet
|
||||
let mut msg = cid.to_vec();
|
||||
msg.push(0x01); // seq = 1
|
||||
// write msg, append [1u8; 59], 53 bytes remaining
|
||||
// write msg, append [1u8; 59], 53 bytes remaining
|
||||
device.add_write(&msg, 1);
|
||||
device.add_read(&msg, 1);
|
||||
|
||||
@ -400,7 +400,7 @@ mod tests {
|
||||
let mut msg = cid.to_vec();
|
||||
// sendrecv header
|
||||
msg.extend(vec![U2FHID_MSG, 0x00, 0x0e]); // len = 14
|
||||
// apdu header
|
||||
// apdu header
|
||||
msg.extend(vec![0x00, U2FHID_PING, 0xaa, 0x00, 0x00, 0x00, 0x05]);
|
||||
// apdu data
|
||||
msg.extend_from_slice(&data);
|
||||
|
@ -135,7 +135,6 @@ impl U2FHIDCont {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reply sent after initialization command. Contains information about U2F USB
|
||||
// Key versioning, as well as the communication channel to be used for all
|
||||
// further requests.
|
||||
|
@ -64,7 +64,9 @@ impl<T> OnceCallback<T> {
|
||||
F: Send + 'static,
|
||||
{
|
||||
let cb = Some(SendBoxFnOnce::from(cb));
|
||||
Self { callback: Arc::new(Mutex::new(cb)) }
|
||||
Self {
|
||||
callback: Arc::new(Mutex::new(cb)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&self, rv: io::Result<T>) {
|
||||
@ -78,6 +80,8 @@ impl<T> OnceCallback<T> {
|
||||
|
||||
impl<T> Clone for OnceCallback<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { callback: self.callback.clone() }
|
||||
Self {
|
||||
callback: self.callback.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use std::io;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
|
||||
use consts::{CID_BROADCAST, HID_RPT_SIZE, FIDO_USAGE_PAGE, FIDO_USAGE_U2FHID};
|
||||
use consts::{FIDO_USAGE_U2FHID, CID_BROADCAST, FIDO_USAGE_PAGE, HID_RPT_SIZE};
|
||||
use super::winapi::DeviceCapabilities;
|
||||
|
||||
use u2ftypes::U2FDevice;
|
||||
|
@ -65,8 +65,10 @@ where
|
||||
let path = path.clone();
|
||||
let key = path.clone();
|
||||
|
||||
let runloop = RunLoop::new(move |alive| if alive() {
|
||||
f(path, alive);
|
||||
let runloop = RunLoop::new(move |alive| {
|
||||
if alive() {
|
||||
f(path, alive);
|
||||
}
|
||||
});
|
||||
|
||||
if let Ok(runloop) = runloop {
|
||||
|
@ -32,7 +32,9 @@ impl Transaction {
|
||||
timeout,
|
||||
)?;
|
||||
|
||||
Ok(Self { thread: Some(thread) })
|
||||
Ok(Self {
|
||||
thread: Some(thread),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn cancel(&mut self) {
|
||||
|
@ -722,6 +722,7 @@ protected:
|
||||
virtual ~gfxPlatform();
|
||||
|
||||
virtual void InitAcceleration();
|
||||
virtual void InitWebRenderConfig();
|
||||
|
||||
/**
|
||||
* Called immediately before deleting the gfxPlatform object.
|
||||
@ -839,7 +840,6 @@ private:
|
||||
|
||||
void InitCompositorAccelerationPrefs();
|
||||
void InitGPUProcessPrefs();
|
||||
void InitWebRenderConfig();
|
||||
void InitOMTPConfig();
|
||||
|
||||
static bool IsDXInterop2Blocked();
|
||||
|
@ -370,6 +370,16 @@ gfxWindowsPlatform::InitAcceleration()
|
||||
UpdateCanUseHardwareVideoDecoding();
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitWebRenderConfig()
|
||||
{
|
||||
gfxPlatform::InitWebRenderConfig();
|
||||
|
||||
if (gfxVars::UseWebRender()) {
|
||||
UpdateBackendPrefs();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::CanUseHardwareVideoDecoding()
|
||||
{
|
||||
@ -436,7 +446,8 @@ gfxWindowsPlatform::UpdateBackendPrefs()
|
||||
uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) |
|
||||
BackendTypeBit(BackendType::SKIA);
|
||||
BackendType defaultBackend = BackendType::SKIA;
|
||||
if (gfxConfig::IsEnabled(Feature::DIRECT2D) && Factory::HasD2D1Device()) {
|
||||
if (gfxConfig::IsEnabled(Feature::DIRECT2D) &&
|
||||
Factory::HasD2D1Device() && !gfxVars::UseWebRender()) {
|
||||
contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
|
||||
canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
|
||||
defaultBackend = BackendType::DIRECT2D1_1;
|
||||
|
@ -237,6 +237,7 @@ protected:
|
||||
private:
|
||||
void Init();
|
||||
void InitAcceleration() override;
|
||||
void InitWebRenderConfig() override;
|
||||
|
||||
void InitializeDevices();
|
||||
void InitializeD3D11();
|
||||
|
@ -2835,7 +2835,7 @@ void
|
||||
CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->environmentChain()));
|
||||
pushArg(ImmGCPtr(lir->mir()->info().fun));
|
||||
pushArg(ImmGCPtr(lir->mir()->info().funUnsafe()));
|
||||
callVM(LambdaInfo, lir);
|
||||
}
|
||||
|
||||
@ -2847,18 +2847,16 @@ CodeGenerator::visitLambda(LLambda* lir)
|
||||
Register tempReg = ToRegister(lir->temp());
|
||||
const LambdaFunctionInfo& info = lir->mir()->info();
|
||||
|
||||
OutOfLineCode* ool = oolCallVM(LambdaInfo, lir, ArgList(ImmGCPtr(info.fun), envChain),
|
||||
OutOfLineCode* ool = oolCallVM(LambdaInfo, lir, ArgList(ImmGCPtr(info.funUnsafe()), envChain),
|
||||
StoreRegisterTo(output));
|
||||
|
||||
MOZ_ASSERT(!info.singletonType);
|
||||
|
||||
masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
|
||||
masm.createGCObject(output, tempReg, info.funUnsafe(), gc::DefaultHeap, ool->entry());
|
||||
|
||||
emitLambdaInit(output, envChain, info);
|
||||
|
||||
if (info.flags & JSFunction::EXTENDED) {
|
||||
MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin() ||
|
||||
info.fun->isAsync());
|
||||
static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
|
||||
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
|
||||
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
|
||||
@ -2908,7 +2906,7 @@ CodeGenerator::visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool)
|
||||
|
||||
pushArg(newTarget);
|
||||
pushArg(envChain);
|
||||
pushArg(ImmGCPtr(info.fun));
|
||||
pushArg(ImmGCPtr(info.funUnsafe()));
|
||||
|
||||
callVM(LambdaArrowInfo, ool->lir);
|
||||
StoreRegisterTo(output).generate(this);
|
||||
@ -2945,7 +2943,7 @@ CodeGenerator::visitLambdaArrow(LLambdaArrow* lir)
|
||||
Register tempReg = newTarget.scratchReg();
|
||||
masm.push(newTarget.scratchReg());
|
||||
|
||||
masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
|
||||
masm.createGCObject(output, tempReg, info.funUnsafe(), gc::DefaultHeap, ool->entry());
|
||||
|
||||
masm.pop(newTarget.scratchReg());
|
||||
|
||||
@ -2986,7 +2984,8 @@ CodeGenerator::emitLambdaInit(Register output, Register envChain,
|
||||
masm.storePtr(envChain, Address(output, JSFunction::offsetOfEnvironment()));
|
||||
// No post barrier needed because output is guaranteed to be allocated in
|
||||
// the nursery.
|
||||
masm.storePtr(ImmGCPtr(info.fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
|
||||
masm.storePtr(ImmGCPtr(info.funUnsafe()->displayAtom()),
|
||||
Address(output, JSFunction::offsetOfAtom()));
|
||||
}
|
||||
|
||||
typedef bool (*SetFunNameFn)(JSContext*, HandleFunction, HandleValue, FunctionPrefixKind);
|
||||
|
@ -734,7 +734,6 @@ class LNode
|
||||
|
||||
// Returns information about operands.
|
||||
virtual LAllocation* getOperand(size_t index) = 0;
|
||||
virtual void setOperand(size_t index, const LAllocation& a) = 0;
|
||||
|
||||
bool isCall() const {
|
||||
return isCall_;
|
||||
@ -830,6 +829,9 @@ class LInstruction
|
||||
void setDef(size_t index, const LDefinition& def) {
|
||||
*getDef(index) = def;
|
||||
}
|
||||
void setOperand(size_t index, const LAllocation& a) {
|
||||
*getOperand(index) = a;
|
||||
}
|
||||
|
||||
// Returns information about temporary registers needed. Each temporary
|
||||
// register is an LDefinition with a fixed or virtual register and
|
||||
@ -969,7 +971,7 @@ class LPhi final : public LNode
|
||||
MOZ_ASSERT(index < numOperands());
|
||||
return &inputs_[index];
|
||||
}
|
||||
void setOperand(size_t index, const LAllocation& a) override {
|
||||
void setOperand(size_t index, const LAllocation& a) {
|
||||
MOZ_ASSERT(index < numOperands());
|
||||
inputs_[index] = a;
|
||||
}
|
||||
@ -1166,7 +1168,7 @@ class LInstructionHelper : public details::LInstructionFixedDefsTempsHelper<Defs
|
||||
LAllocation* getOperand(size_t index) final {
|
||||
return &operands_[index];
|
||||
}
|
||||
void setOperand(size_t index, const LAllocation& a) final {
|
||||
void setOperand(size_t index, const LAllocation& a) {
|
||||
operands_[index] = a;
|
||||
}
|
||||
void setBoxOperand(size_t index, const LBoxAllocation& alloc) {
|
||||
@ -1212,7 +1214,7 @@ class LVariadicInstruction : public details::LInstructionFixedDefsTempsHelper<De
|
||||
LAllocation* getOperand(size_t index) final {
|
||||
return &operands_[index];
|
||||
}
|
||||
void setOperand(size_t index, const LAllocation& a) final {
|
||||
void setOperand(size_t index, const LAllocation& a) {
|
||||
operands_[index] = a;
|
||||
}
|
||||
void setBoxOperand(size_t index, const LBoxAllocation& a) {
|
||||
|
@ -8798,7 +8798,10 @@ struct LambdaFunctionInfo
|
||||
// The functions used in lambdas are the canonical original function in
|
||||
// the script, and are immutable except for delazification. Record this
|
||||
// information while still on the active thread to avoid races.
|
||||
CompilerFunction fun;
|
||||
private:
|
||||
CompilerFunction fun_;
|
||||
|
||||
public:
|
||||
uint16_t flags;
|
||||
uint16_t nargs;
|
||||
gc::Cell* scriptOrLazyScript;
|
||||
@ -8806,20 +8809,37 @@ struct LambdaFunctionInfo
|
||||
bool useSingletonForClone;
|
||||
|
||||
explicit LambdaFunctionInfo(JSFunction* fun)
|
||||
: fun(fun), flags(fun->flags()), nargs(fun->nargs()),
|
||||
: fun_(fun), flags(fun->flags()), nargs(fun->nargs()),
|
||||
scriptOrLazyScript(fun->hasScript()
|
||||
? (gc::Cell*) fun->nonLazyScript()
|
||||
: (gc::Cell*) fun->lazyScript()),
|
||||
singletonType(fun->isSingleton()),
|
||||
useSingletonForClone(ObjectGroup::useSingletonForClone(fun))
|
||||
{}
|
||||
{
|
||||
// If this assert fails, make sure CodeGenerator::visitLambda does the
|
||||
// right thing. We can't assert this off-thread in CodeGenerator,
|
||||
// because fun->isAsync() accesses the script/lazyScript and can race
|
||||
// with delazification on the main thread.
|
||||
MOZ_ASSERT_IF(flags & JSFunction::EXTENDED,
|
||||
fun->isArrow() ||
|
||||
fun->allowSuperProperty() ||
|
||||
fun->isSelfHostedBuiltin() ||
|
||||
fun->isAsync());
|
||||
}
|
||||
|
||||
// Be careful when calling this off-thread. Don't call any JSFunction*
|
||||
// methods that depend on script/lazyScript - this can race with
|
||||
// delazification on the main thread.
|
||||
JSFunction* funUnsafe() const {
|
||||
return fun_;
|
||||
}
|
||||
|
||||
bool appendRoots(MRootList& roots) const {
|
||||
if (!roots.append(fun))
|
||||
if (!roots.append(fun_))
|
||||
return false;
|
||||
if (fun->hasScript())
|
||||
return roots.append(fun->nonLazyScript());
|
||||
return roots.append(fun->lazyScript());
|
||||
if (fun_->hasScript())
|
||||
return roots.append(fun_->nonLazyScript());
|
||||
return roots.append(fun_->lazyScript());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -8839,8 +8859,9 @@ class MLambda
|
||||
info_(&cst->toObject().as<JSFunction>())
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun))
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, info().fun));
|
||||
JSFunction* fun = info().funUnsafe();
|
||||
if (!fun->isSingleton() && !ObjectGroup::useSingletonForClone(fun))
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, fun));
|
||||
}
|
||||
|
||||
public:
|
||||
@ -8875,9 +8896,10 @@ class MLambdaArrow
|
||||
info_(&cst->toObject().as<JSFunction>())
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
MOZ_ASSERT(!ObjectGroup::useSingletonForClone(info().fun));
|
||||
if (!info().fun->isSingleton())
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, info().fun));
|
||||
JSFunction* fun = info().funUnsafe();
|
||||
MOZ_ASSERT(!ObjectGroup::useSingletonForClone(fun));
|
||||
if (!fun->isSingleton())
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, fun));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -356,12 +356,9 @@ class RegisterAllocator
|
||||
public:
|
||||
template<typename TakeableSet>
|
||||
static void takeWasmRegisters(TakeableSet& regs) {
|
||||
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || \
|
||||
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
|
||||
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
regs.take(HeapReg);
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
regs.take(HeapReg);
|
||||
regs.take(HeapLenReg);
|
||||
#endif
|
||||
regs.take(FramePointer);
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ RValueAllocation::layoutFromMode(Mode mode)
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_CRASH("Wrong mode type?");
|
||||
MOZ_CRASH_UNSAFE_PRINTF("Unexpected mode: 0x%x", mode);
|
||||
}
|
||||
|
||||
// Pad serialized RValueAllocations by a multiple of X bytes in the allocation
|
||||
|
@ -303,6 +303,9 @@ class RValueAllocation
|
||||
void write(CompactBufferWriter& writer) const;
|
||||
|
||||
public:
|
||||
bool valid() const {
|
||||
return mode_ != INVALID;
|
||||
}
|
||||
Mode mode() const {
|
||||
return Mode(mode_ & MODE_BITS_MASK);
|
||||
}
|
||||
|
@ -71,5 +71,11 @@ FloatRegister::getRegisterDumpOffsetInBytes()
|
||||
return encoding() * sizeof(double);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetARM64Flags()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
@ -491,6 +491,8 @@ hasMultiAlias()
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t GetARM64Flags();
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
@ -87,7 +87,6 @@ static constexpr Register IntArgReg5 { Registers::x5 };
|
||||
static constexpr Register IntArgReg6 { Registers::x6 };
|
||||
static constexpr Register IntArgReg7 { Registers::x7 };
|
||||
static constexpr Register HeapReg { Registers::x21 };
|
||||
static constexpr Register HeapLenReg { Registers::x22 };
|
||||
|
||||
// Define unsized Registers.
|
||||
#define DEFINE_UNSIZED_REGISTERS(N) \
|
||||
|
25
js/src/jit/arm64/Disassembler-arm64.cpp
Normal file
25
js/src/jit/arm64/Disassembler-arm64.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright 2018 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "jit/Disassembler.h"
|
||||
|
||||
MOZ_COLD uint8_t*
|
||||
js::jit::Disassembler::DisassembleHeapAccess(uint8_t*, js::jit::Disassembler::HeapAccess*)
|
||||
{
|
||||
MOZ_CRASH("NYI - asm.js not supported yet on this platform");
|
||||
}
|
@ -2027,29 +2027,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
store32(scratch32.asUnsized(), addr);
|
||||
}
|
||||
|
||||
void BoundsCheck(Register ptrReg, Label* onFail, vixl::CPURegister zeroMe = vixl::NoReg) {
|
||||
// use tst rather than Tst to *ensure* that a single instrution is generated.
|
||||
Cmp(ARMRegister(ptrReg, 32), ARMRegister(HeapLenReg, 32));
|
||||
if (!zeroMe.IsNone()) {
|
||||
if (zeroMe.IsRegister()) {
|
||||
Csel(ARMRegister(zeroMe),
|
||||
ARMRegister(zeroMe),
|
||||
Operand(zeroMe.Is32Bits() ? vixl::wzr : vixl::xzr),
|
||||
Assembler::Below);
|
||||
} else if (zeroMe.Is32Bits()) {
|
||||
vixl::UseScratchRegisterScope temps(this);
|
||||
const ARMFPRegister scratchFloat = temps.AcquireS();
|
||||
Fmov(scratchFloat, JS::GenericNaN());
|
||||
Fcsel(ARMFPRegister(zeroMe), ARMFPRegister(zeroMe), scratchFloat, Assembler::Below);
|
||||
} else {
|
||||
vixl::UseScratchRegisterScope temps(this);
|
||||
const ARMFPRegister scratchDouble = temps.AcquireD();
|
||||
Fmov(scratchDouble, JS::GenericNaN());
|
||||
Fcsel(ARMFPRegister(zeroMe), ARMFPRegister(zeroMe), scratchDouble, Assembler::Below);
|
||||
}
|
||||
}
|
||||
B(onFail, Assembler::AboveOrEqual);
|
||||
}
|
||||
void breakpoint();
|
||||
|
||||
// Emits a simulator directive to save the current sp on an internal stack.
|
||||
|
@ -452,13 +452,15 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir,
|
||||
JSValueType valueType =
|
||||
(type == MIRType::ObjectOrNull) ? JSVAL_TYPE_OBJECT : ValueTypeFromMIRType(type);
|
||||
|
||||
MOZ_ASSERT(payload->isMemory() || payload->isRegister());
|
||||
MOZ_DIAGNOSTIC_ASSERT(payload->isMemory() || payload->isRegister());
|
||||
if (payload->isMemory())
|
||||
alloc = RValueAllocation::Typed(valueType, ToStackIndex(payload));
|
||||
else if (payload->isGeneralReg())
|
||||
alloc = RValueAllocation::Typed(valueType, ToRegister(payload));
|
||||
else if (payload->isFloatReg())
|
||||
alloc = RValueAllocation::Double(ToFloatRegister(payload));
|
||||
else
|
||||
MOZ_CRASH("Unexpected payload type.");
|
||||
break;
|
||||
}
|
||||
case MIRType::Float32:
|
||||
@ -541,6 +543,7 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir,
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(alloc.valid());
|
||||
|
||||
// This set an extra bit as part of the RValueAllocation, such that we know
|
||||
// that recover instruction have to be executed without wrapping the
|
||||
|
@ -6939,7 +6939,7 @@ class LGetPropertyPolymorphicV : public LInstructionHelper<BOX_PIECES, 1, 0>
|
||||
const MGetPropertyPolymorphic* mir() const {
|
||||
return mir_->toGetPropertyPolymorphic();
|
||||
}
|
||||
virtual const char* extraName() const {
|
||||
const char* extraName() const {
|
||||
return PropertyNameToExtraName(mir()->name());
|
||||
}
|
||||
};
|
||||
@ -6964,7 +6964,7 @@ class LGetPropertyPolymorphicT : public LInstructionHelper<1, 1, 1>
|
||||
const MGetPropertyPolymorphic* mir() const {
|
||||
return mir_->toGetPropertyPolymorphic();
|
||||
}
|
||||
virtual const char* extraName() const {
|
||||
const char* extraName() const {
|
||||
return PropertyNameToExtraName(mir()->name());
|
||||
}
|
||||
};
|
||||
|
@ -3685,9 +3685,9 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
static void PatchDataWithValueCheck(CodeLocationLabel data, PatchedImmPtr newData,
|
||||
PatchedImmPtr expectedData) {
|
||||
// The pointer given is a pointer to *after* the data.
|
||||
uintptr_t* ptr = ((uintptr_t*) data.raw()) - 1;
|
||||
MOZ_ASSERT(*ptr == (uintptr_t)expectedData.value);
|
||||
*ptr = (uintptr_t)newData.value;
|
||||
uint8_t* ptr = data.raw() - sizeof(uintptr_t);
|
||||
MOZ_ASSERT(mozilla::LittleEndian::readUintptr(ptr) == uintptr_t(expectedData.value));
|
||||
mozilla::LittleEndian::writeUintptr(ptr, uintptr_t(newData.value));
|
||||
}
|
||||
static void PatchDataWithValueCheck(CodeLocationLabel data, ImmPtr newData, ImmPtr expectedData) {
|
||||
PatchDataWithValueCheck(data, PatchedImmPtr(newData.value), PatchedImmPtr(expectedData.value));
|
||||
|
@ -519,6 +519,7 @@ elif CONFIG['JS_CODEGEN_ARM64']:
|
||||
'jit/arm64/Bailouts-arm64.cpp',
|
||||
'jit/arm64/BaselineIC-arm64.cpp',
|
||||
'jit/arm64/CodeGenerator-arm64.cpp',
|
||||
'jit/arm64/Disassembler-arm64.cpp',
|
||||
'jit/arm64/Lowering-arm64.cpp',
|
||||
'jit/arm64/MacroAssembler-arm64.cpp',
|
||||
'jit/arm64/MoveEmitter-arm64.cpp',
|
||||
@ -652,11 +653,13 @@ if CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['ENABLE_WASM_SATURATING_TRUNC_OPS'] = True
|
||||
DEFINES['ENABLE_WASM_SIGNEXTEND_OPS'] = True
|
||||
DEFINES['ENABLE_WASM_THREAD_OPS'] = True
|
||||
# An experiment we want to run on Nightly: Can we change the JS
|
||||
# representation of an exported global from the global's value
|
||||
# to an instance of WebAssembly.Global without breaking existing
|
||||
# wasm content?
|
||||
DEFINES['ENABLE_WASM_GLOBAL'] = True
|
||||
|
||||
# An experiment we want to run on Nightly and early Beta: Can we change the JS
|
||||
# representation of an exported global from the global's value to an instance
|
||||
# of WebAssembly.Global without breaking existing wasm content?
|
||||
#
|
||||
# Additionally guarded by EARLY_BETA_OR_EARLIER in the code.
|
||||
DEFINES['ENABLE_WASM_GLOBAL'] = True
|
||||
|
||||
if CONFIG['JS_BUILD_BINAST']:
|
||||
# Using SOURCES as UNIFIED_SOURCES causes mysterious bugs on 32-bit platforms.
|
||||
@ -679,7 +682,7 @@ if CONFIG['JS_BUILD_BINAST']:
|
||||
# so that it is easy to use the huge-mapping optimization for other
|
||||
# 64-bit platforms in the future.
|
||||
|
||||
if CONFIG['JS_CODEGEN_X64']:
|
||||
if CONFIG['JS_CODEGEN_X64'] or CONFIG['JS_CODEGEN_ARM64']:
|
||||
DEFINES['WASM_HUGE_MEMORY'] = True
|
||||
|
||||
if CONFIG['MOZ_DEBUG'] or CONFIG['NIGHTLY_BUILD']:
|
||||
|
@ -1551,6 +1551,7 @@ dnl ========================================================
|
||||
MOZ_ARG_HEADER(Misc. Options)
|
||||
|
||||
if test -z "$SKIP_COMPILER_CHECKS"; then
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Compiler Options
|
||||
@ -1825,6 +1826,19 @@ if test -n "$MOZ_DEV_EDITION"; then
|
||||
AC_DEFINE(MOZ_DEV_EDITION)
|
||||
fi
|
||||
|
||||
# Allow influencing configure with a defines.sh script.
|
||||
. "${srcdir}/build/defines.sh"
|
||||
|
||||
# If we're not building a release build, define EARLY_BETA_OR_EARLIER if it is
|
||||
# set in defines.sh
|
||||
if test "$BUILDING_RELEASE"; then
|
||||
# Override value in defines.sh, if any
|
||||
EARLY_BETA_OR_EARLIER=
|
||||
elif test "$EARLY_BETA_OR_EARLIER"; then
|
||||
AC_DEFINE(EARLY_BETA_OR_EARLIER)
|
||||
fi
|
||||
AC_SUBST(EARLY_BETA_OR_EARLIER)
|
||||
|
||||
dnl ========================================================
|
||||
dnl JavaScript shell
|
||||
dnl ========================================================
|
||||
|
@ -111,7 +111,9 @@ JSScript::ensureNonLazyCanonicalFunction()
|
||||
inline JSFunction*
|
||||
JSScript::getFunction(size_t index)
|
||||
{
|
||||
JSFunction* fun = &getObject(index)->as<JSFunction>();
|
||||
JSObject* obj = getObject(index);
|
||||
MOZ_RELEASE_ASSERT(obj->is<JSFunction>(), "Script object is not JSFunction");
|
||||
JSFunction* fun = &obj->as<JSFunction>();
|
||||
MOZ_ASSERT_IF(fun->isNative(), IsAsmJSModuleNative(fun->native()));
|
||||
return fun;
|
||||
}
|
||||
@ -119,13 +121,17 @@ JSScript::getFunction(size_t index)
|
||||
inline js::RegExpObject*
|
||||
JSScript::getRegExp(size_t index)
|
||||
{
|
||||
return &getObject(index)->as<js::RegExpObject>();
|
||||
JSObject* obj = getObject(index);
|
||||
MOZ_RELEASE_ASSERT(obj->is<js::RegExpObject>(), "Script object is not RegExpObject");
|
||||
return &obj->as<js::RegExpObject>();
|
||||
}
|
||||
|
||||
inline js::RegExpObject*
|
||||
JSScript::getRegExp(jsbytecode* pc)
|
||||
{
|
||||
return &getObject(pc)->as<js::RegExpObject>();
|
||||
JSObject* obj = getObject(pc);
|
||||
MOZ_RELEASE_ASSERT(obj->is<js::RegExpObject>(), "Script object is not RegExpObject");
|
||||
return &obj->as<js::RegExpObject>();
|
||||
}
|
||||
|
||||
inline js::GlobalObject&
|
||||
|
@ -2375,12 +2375,14 @@ JSStructuredCloneReader::readHeader()
|
||||
return in.reportTruncated();
|
||||
|
||||
if (tag != SCTAG_HEADER) {
|
||||
// Old structured clone buffer. We must have read it from disk or
|
||||
// somewhere, so we can assume it's scope-compatible.
|
||||
// Old structured clone buffer. We must have read it from disk.
|
||||
storedScope = JS::StructuredCloneScope::DifferentProcess;
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
|
||||
storedScope = JS::StructuredCloneScope(data);
|
||||
|
||||
if (data != uint32_t(JS::StructuredCloneScope::SameProcessSameThread) &&
|
||||
data != uint32_t(JS::StructuredCloneScope::SameProcessDifferentThread) &&
|
||||
data != uint32_t(JS::StructuredCloneScope::DifferentProcess))
|
||||
@ -2389,7 +2391,6 @@ JSStructuredCloneReader::readHeader()
|
||||
"invalid structured clone scope");
|
||||
return false;
|
||||
}
|
||||
storedScope = JS::StructuredCloneScope(data);
|
||||
if (storedScope < allowedScope) {
|
||||
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
|
||||
"incompatible structured clone scope");
|
||||
|
@ -253,7 +253,7 @@ GetImports(JSContext* cx,
|
||||
MOZ_ASSERT(global.importIndex() == globalIndex - 1);
|
||||
MOZ_ASSERT(!global.isMutable());
|
||||
|
||||
#ifdef ENABLE_WASM_GLOBAL
|
||||
#if defined(ENABLE_WASM_GLOBAL) && defined(EARLY_BETA_OR_EARLIER)
|
||||
if (v.isObject() && v.toObject().is<WasmGlobalObject>())
|
||||
v.set(v.toObject().as<WasmGlobalObject>().value());
|
||||
#endif
|
||||
@ -1935,7 +1935,7 @@ WasmTableObject::table() const
|
||||
// ============================================================================
|
||||
// WebAssembly.global class and methods
|
||||
|
||||
#ifdef ENABLE_WASM_GLOBAL
|
||||
#if defined(ENABLE_WASM_GLOBAL) && defined(EARLY_BETA_OR_EARLIER)
|
||||
|
||||
const ClassOps WasmGlobalObject::classOps_ =
|
||||
{
|
||||
@ -2128,7 +2128,7 @@ WasmGlobalObject::value() const
|
||||
return getReservedSlot(VALUE_SLOT);
|
||||
}
|
||||
|
||||
#endif // ENABLE_WASM_GLOBAL
|
||||
#endif // ENABLE_WASM_GLOBAL && EARLY_BETA_OR_EARLIER
|
||||
|
||||
// ============================================================================
|
||||
// WebAssembly class and static methods
|
||||
@ -2968,7 +2968,7 @@ js::InitWebAssemblyClass(JSContext* cx, HandleObject obj)
|
||||
return nullptr;
|
||||
|
||||
RootedObject moduleProto(cx), instanceProto(cx), memoryProto(cx), tableProto(cx);
|
||||
#ifdef ENABLE_WASM_GLOBAL
|
||||
#if defined(ENABLE_WASM_GLOBAL) && defined(EARLY_BETA_OR_EARLIER)
|
||||
RootedObject globalProto(cx);
|
||||
#endif
|
||||
if (!InitConstructor<WasmModuleObject>(cx, wasm, "Module", &moduleProto))
|
||||
@ -2979,7 +2979,7 @@ js::InitWebAssemblyClass(JSContext* cx, HandleObject obj)
|
||||
return nullptr;
|
||||
if (!InitConstructor<WasmTableObject>(cx, wasm, "Table", &tableProto))
|
||||
return nullptr;
|
||||
#ifdef ENABLE_WASM_GLOBAL
|
||||
#if defined(ENABLE_WASM_GLOBAL) && defined(EARLY_BETA_OR_EARLIER)
|
||||
if (!InitConstructor<WasmGlobalObject>(cx, wasm, "Global", &globalProto))
|
||||
return nullptr;
|
||||
#endif
|
||||
@ -3002,7 +3002,7 @@ js::InitWebAssemblyClass(JSContext* cx, HandleObject obj)
|
||||
global->setPrototype(JSProto_WasmInstance, ObjectValue(*instanceProto));
|
||||
global->setPrototype(JSProto_WasmMemory, ObjectValue(*memoryProto));
|
||||
global->setPrototype(JSProto_WasmTable, ObjectValue(*tableProto));
|
||||
#ifdef ENABLE_WASM_GLOBAL
|
||||
#if defined(ENABLE_WASM_GLOBAL) && defined(EARLY_BETA_OR_EARLIER)
|
||||
global->setPrototype(JSProto_WasmGlobal, ObjectValue(*globalProto));
|
||||
#endif
|
||||
global->setConstructor(JSProto_WebAssembly, ObjectValue(*wasm));
|
||||
|
@ -285,7 +285,7 @@ class WasmTableObject : public NativeObject
|
||||
wasm::Table& table() const;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_WASM_GLOBAL
|
||||
#if defined(ENABLE_WASM_GLOBAL) && defined(EARLY_BETA_OR_EARLIER)
|
||||
|
||||
// The class of WebAssembly.Global. A WasmGlobalObject holds either the value
|
||||
// of an immutable wasm global or the cell of a mutable wasm global.
|
||||
@ -319,7 +319,7 @@ class WasmGlobalObject : public NativeObject
|
||||
Value value() const;
|
||||
};
|
||||
|
||||
#endif // ENABLE_WASM_GLOBAL
|
||||
#endif // ENABLE_WASM_GLOBAL && EARLY_BETA_OR_EARLIER
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
@ -1016,7 +1016,7 @@ GetGlobalExport(JSContext* cx, const GlobalDescVector& globals, uint32_t globalI
|
||||
|
||||
ToJSValue(val, jsval);
|
||||
|
||||
#ifdef ENABLE_WASM_GLOBAL
|
||||
#if defined(ENABLE_WASM_GLOBAL) && defined(EARLY_BETA_OR_EARLIER)
|
||||
Rooted<WasmGlobalObject*> go(cx, WasmGlobalObject::create(cx, ValType::I32, false, jsval));
|
||||
if (!go)
|
||||
return false;
|
||||
|
@ -625,6 +625,7 @@ StoreValueFromGPImm(SharedMem<void*> addr, size_t size, int32_t imm)
|
||||
AtomicOperations::memcpySafeWhenRacy(addr, static_cast<void*>(&imm), size);
|
||||
}
|
||||
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
# if !defined(XP_DARWIN)
|
||||
MOZ_COLD static void*
|
||||
AddressOfFPRegisterSlot(CONTEXT* context, FloatRegisters::Encoding encoding)
|
||||
@ -726,6 +727,19 @@ AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
|
||||
MOZ_CRASH();
|
||||
}
|
||||
# endif // !XP_DARWIN
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_COLD static void*
|
||||
AddressOfFPRegisterSlot(EMULATOR_CONTEXT* context, FloatRegisters::Encoding encoding)
|
||||
{
|
||||
MOZ_CRASH("NYI - asm.js not supported yet on this platform");
|
||||
}
|
||||
|
||||
MOZ_COLD static void*
|
||||
AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
|
||||
{
|
||||
MOZ_CRASH("NYI - asm.js not supported yet on this platform");
|
||||
}
|
||||
#endif
|
||||
|
||||
MOZ_COLD static void
|
||||
SetRegisterToCoercedUndefined(EMULATOR_CONTEXT* context, size_t size,
|
||||
|
@ -32,11 +32,18 @@ using namespace js::wasm;
|
||||
using mozilla::IsPowerOfTwo;
|
||||
using mozilla::MakeEnumeratedRange;
|
||||
|
||||
// A sanity check. We have only tested WASM_HUGE_MEMORY on x64, and only tested
|
||||
// x64 with WASM_HUGE_MEMORY.
|
||||
// We have only tested x64 with WASM_HUGE_MEMORY.
|
||||
|
||||
#if defined(WASM_HUGE_MEMORY) != defined(JS_CODEGEN_X64)
|
||||
# error "Not an expected configuration"
|
||||
#if defined(JS_CODEGEN_X64) && !defined(WASM_HUGE_MEMORY)
|
||||
# error "Not an expected configuration"
|
||||
#endif
|
||||
|
||||
// We have only tested WASM_HUGE_MEMORY on x64 and arm64.
|
||||
|
||||
#if defined(WASM_HUGE_MEMORY)
|
||||
# if !(defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64))
|
||||
# error "Not an expected configuration"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Another sanity check.
|
||||
@ -102,6 +109,7 @@ GetCPUID()
|
||||
ARM = 0x3,
|
||||
MIPS = 0x4,
|
||||
MIPS64 = 0x5,
|
||||
ARM64 = 0x6,
|
||||
ARCH_BITS = 3
|
||||
};
|
||||
|
||||
@ -115,7 +123,8 @@ GetCPUID()
|
||||
MOZ_ASSERT(jit::GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
|
||||
return ARM | (jit::GetARMFlags() << ARCH_BITS);
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_CRASH("not enabled");
|
||||
MOZ_ASSERT(jit::GetARM64Flags() <= (UINT32_MAX >> ARCH_BITS));
|
||||
return ARM64 | (jit::GetARM64Flags() << ARCH_BITS);
|
||||
#elif defined(JS_CODEGEN_MIPS32)
|
||||
MOZ_ASSERT(jit::GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
|
||||
return MIPS | (jit::GetMIPSFlags() << ARCH_BITS);
|
||||
|
@ -207,7 +207,7 @@ WhitespaceOnlyChangedOnAppend(const CharT* aBuffer,
|
||||
size_t aOldLength,
|
||||
size_t aNewLength)
|
||||
{
|
||||
MOZ_ASSERT(aOldLength < aNewLength);
|
||||
MOZ_ASSERT(aOldLength <= aNewLength);
|
||||
if (!WhitespaceOnly(aBuffer, aOldLength)) {
|
||||
// The old text was already not whitespace-only.
|
||||
return false;
|
||||
|
10
layout/base/crashtests/1442506.html
Normal file
10
layout/base/crashtests/1442506.html
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
function go() {
|
||||
var b = window.getSelection();
|
||||
var c = document.getSelection();
|
||||
b.setBaseAndExtent(document.getElementById("a"), 0, document.body.firstChild, 1);
|
||||
c.deleteFromDocument();
|
||||
}
|
||||
</script>
|
||||
<body onload=go()>
|
||||
<p id="a">
|
@ -525,3 +525,4 @@ load 1429961.html
|
||||
load 1435015.html
|
||||
load 1429962.html
|
||||
pref(dom.webcomponents.shadowdom.enabled,true) load 1439016.html
|
||||
load 1442506.html
|
||||
|
@ -2911,7 +2911,7 @@ css::URLValueData::GetUTF16String() const
|
||||
nsDependentCSubstring rust = GetRustString();
|
||||
nsString converted = NS_ConvertUTF8toUTF16(rust);
|
||||
Servo_ReleaseArcStringData(&mStrings.mRustString);
|
||||
mStrings.mString = converted;
|
||||
new (&mStrings) RustOrGeckoString(converted);
|
||||
mUsingRustString = false;
|
||||
}
|
||||
return mStrings.mString;
|
||||
|
@ -134,15 +134,12 @@ MOZ_END_EXTERN_C
|
||||
#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
|
||||
#endif
|
||||
#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
|
||||
#elif __cplusplus >= 201103
|
||||
#else
|
||||
/*
|
||||
* C++11 has deprecated exception-specifications in favour of |noexcept|.
|
||||
*/
|
||||
#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS noexcept(true)
|
||||
#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS noexcept(false)
|
||||
#else
|
||||
#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
|
||||
#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc)
|
||||
#endif
|
||||
|
||||
#define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
|
||||
|
@ -9,7 +9,9 @@
|
||||
/*
|
||||
* The classes LittleEndian and BigEndian expose static methods for
|
||||
* reading and writing 16-, 32-, and 64-bit signed and unsigned integers
|
||||
* in their respective endianness. The naming scheme is:
|
||||
* in their respective endianness. The addresses read from or written
|
||||
* to may be misaligned (although misaligned accesses may incur
|
||||
* architecture-specific performance costs). The naming scheme is:
|
||||
*
|
||||
* {Little,Big}Endian::{read,write}{Uint,Int}<bitsize>
|
||||
*
|
||||
@ -361,6 +363,12 @@ protected:
|
||||
return read<uint64_t>(aPtr);
|
||||
}
|
||||
|
||||
/** Read a uintptr_t in ThisEndian endianness from |aPtr| and return it. */
|
||||
static MOZ_MUST_USE uintptr_t readUintptr(const void* aPtr)
|
||||
{
|
||||
return read<uintptr_t>(aPtr);
|
||||
}
|
||||
|
||||
/** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */
|
||||
static MOZ_MUST_USE int16_t readInt16(const void* aPtr)
|
||||
{
|
||||
@ -379,6 +387,12 @@ protected:
|
||||
return read<int64_t>(aPtr);
|
||||
}
|
||||
|
||||
/** Read an intptr_t in ThisEndian endianness from |aPtr| and return it. */
|
||||
static MOZ_MUST_USE intptr_t readIntptr(const void* aPtr)
|
||||
{
|
||||
return read<intptr_t>(aPtr);
|
||||
}
|
||||
|
||||
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
|
||||
static void writeUint16(void* aPtr, uint16_t aValue)
|
||||
{
|
||||
@ -397,6 +411,12 @@ protected:
|
||||
write(aPtr, aValue);
|
||||
}
|
||||
|
||||
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
|
||||
static void writeUintptr(void* aPtr, uintptr_t aValue)
|
||||
{
|
||||
write(aPtr, aValue);
|
||||
}
|
||||
|
||||
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
|
||||
static void writeInt16(void* aPtr, int16_t aValue)
|
||||
{
|
||||
@ -415,6 +435,12 @@ protected:
|
||||
write(aPtr, aValue);
|
||||
}
|
||||
|
||||
/** Write |aValue| to |aPtr| using ThisEndian endianness. */
|
||||
static void writeIntptr(void* aPtr, intptr_t aValue)
|
||||
{
|
||||
write(aPtr, aValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a value of type T to little-endian format.
|
||||
*
|
||||
@ -630,15 +656,19 @@ public:
|
||||
using super::readUint16;
|
||||
using super::readUint32;
|
||||
using super::readUint64;
|
||||
using super::readUintptr;
|
||||
using super::readInt16;
|
||||
using super::readInt32;
|
||||
using super::readInt64;
|
||||
using super::readIntptr;
|
||||
using super::writeUint16;
|
||||
using super::writeUint32;
|
||||
using super::writeUint64;
|
||||
using super::writeUintptr;
|
||||
using super::writeInt16;
|
||||
using super::writeInt32;
|
||||
using super::writeInt64;
|
||||
using super::writeIntptr;
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
@ -325,69 +325,101 @@ int
|
||||
main()
|
||||
{
|
||||
static const uint8_t unsigned_bytes[16] = {
|
||||
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
|
||||
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
|
||||
};
|
||||
static const int8_t signed_bytes[16] = {
|
||||
-0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08,
|
||||
-0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08
|
||||
};
|
||||
static const uint16_t uint16_values[8] = {
|
||||
0x102, 0x304, 0x506, 0x708, 0x102, 0x304, 0x506, 0x708
|
||||
0x0102, 0x0304, 0x0506, 0x0708, 0x0102, 0x0304, 0x0506, 0x0708
|
||||
};
|
||||
static const int16_t int16_values[8] = {
|
||||
int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8),
|
||||
int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8)
|
||||
};
|
||||
static const uint32_t uint32_values[4] = {
|
||||
0x1020304, 0x5060708, 0x1020304, 0x5060708
|
||||
0x01020304, 0x05060708, 0x01020304, 0x05060708
|
||||
};
|
||||
static const int32_t int32_values[4] = {
|
||||
int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8),
|
||||
int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8)
|
||||
};
|
||||
static const uint64_t uint64_values[2] = {
|
||||
0x102030405060708, 0x102030405060708
|
||||
0x0102030405060708, 0x0102030405060708
|
||||
};
|
||||
static const int64_t int64_values[2] = {
|
||||
int64_t(0xf1f2f3f4f5f6f7f8), int64_t(0xf1f2f3f4f5f6f7f8)
|
||||
};
|
||||
uint8_t buffer[8];
|
||||
|
||||
MOZ_RELEASE_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x201);
|
||||
MOZ_RELEASE_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x102);
|
||||
MOZ_RELEASE_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x0201);
|
||||
MOZ_RELEASE_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x0102);
|
||||
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUint32(&unsigned_bytes[0]) == 0x4030201U);
|
||||
LittleEndian::readUint32(&unsigned_bytes[0]) == 0x04030201U);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U);
|
||||
BigEndian::readUint32(&unsigned_bytes[0]) == 0x01020304U);
|
||||
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL);
|
||||
LittleEndian::readUint64(&unsigned_bytes[0]) == 0x0807060504030201ULL);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL);
|
||||
BigEndian::readUint64(&unsigned_bytes[0]) == 0x0102030405060708ULL);
|
||||
|
||||
LittleEndian::writeUint16(&buffer[0], 0x201);
|
||||
if (sizeof(uintptr_t) == 8) {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUintptr(&unsigned_bytes[0]) == 0x0807060504030201ULL);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
BigEndian::readUintptr(&unsigned_bytes[0]) == 0x0102030405060708ULL);
|
||||
} else {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUintptr(&unsigned_bytes[0]) == 0x04030201U);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
BigEndian::readUintptr(&unsigned_bytes[0]) == 0x01020304U);
|
||||
}
|
||||
|
||||
LittleEndian::writeUint16(&buffer[0], 0x0201);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
|
||||
BigEndian::writeUint16(&buffer[0], 0x102);
|
||||
BigEndian::writeUint16(&buffer[0], 0x0102);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
|
||||
|
||||
LittleEndian::writeUint32(&buffer[0], 0x4030201U);
|
||||
LittleEndian::writeUint32(&buffer[0], 0x04030201U);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
|
||||
BigEndian::writeUint32(&buffer[0], 0x1020304U);
|
||||
BigEndian::writeUint32(&buffer[0], 0x01020304U);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
|
||||
|
||||
LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL);
|
||||
LittleEndian::writeUint64(&buffer[0], 0x0807060504030201ULL);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
|
||||
BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL);
|
||||
BigEndian::writeUint64(&buffer[0], 0x0102030405060708ULL);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
|
||||
|
||||
memset(&buffer[0], 0xff, sizeof(buffer));
|
||||
LittleEndian::writeUintptr(&buffer[0], uintptr_t(0x0807060504030201ULL));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uintptr_t)) == 0);
|
||||
if (sizeof(uintptr_t) == 4) {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
|
||||
}
|
||||
|
||||
memset(&buffer[0], 0xff, sizeof(buffer));
|
||||
if (sizeof(uintptr_t) == 8) {
|
||||
BigEndian::writeUintptr(&buffer[0], uintptr_t(0x0102030405060708ULL));
|
||||
} else {
|
||||
BigEndian::writeUintptr(&buffer[0], uintptr_t(0x01020304U));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uintptr_t)) == 0);
|
||||
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
@ -403,6 +435,18 @@ main()
|
||||
MOZ_RELEASE_ASSERT(
|
||||
BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL));
|
||||
|
||||
if (sizeof(uintptr_t) == 8) {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf8f7f6f5f4f3f2f1LL));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
BigEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf1f2f3f4f5f6f7f8LL));
|
||||
} else {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf4f3f2f1));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
BigEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf1f2f3f4));
|
||||
}
|
||||
|
||||
LittleEndian::writeInt16(&buffer[0], int16_t(0xf2f1));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
|
||||
@ -424,6 +468,26 @@ main()
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
|
||||
|
||||
memset(&buffer[0], 0xff, sizeof(buffer));
|
||||
LittleEndian::writeIntptr(&buffer[0], intptr_t(0xf8f7f6f5f4f3f2f1LL));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&signed_bytes[0], &buffer[0], sizeof(intptr_t)) == 0);
|
||||
if (sizeof(intptr_t) == 4) {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
|
||||
}
|
||||
|
||||
memset(&buffer[0], 0xff, sizeof(buffer));
|
||||
if (sizeof(intptr_t) == 8) {
|
||||
BigEndian::writeIntptr(&buffer[0], intptr_t(0xf1f2f3f4f5f6f7f8LL));
|
||||
} else {
|
||||
BigEndian::writeIntptr(&buffer[0], intptr_t(0xf1f2f3f4));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(
|
||||
memcmp(&signed_bytes[0], &buffer[0], sizeof(intptr_t)) == 0);
|
||||
|
||||
TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2));
|
||||
TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4));
|
||||
TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8));
|
||||
|
@ -174,6 +174,10 @@ pref("dom.serviceWorkers.idle_timeout", 30000);
|
||||
// The amount of time (milliseconds) service workers can be kept running using waitUntil promises.
|
||||
pref("dom.serviceWorkers.idle_extended_timeout", 300000);
|
||||
|
||||
// The amount of time (milliseconds) an update request is delayed when triggered
|
||||
// by a service worker that doesn't control any clients.
|
||||
pref("dom.serviceWorkers.update_delay", 1000);
|
||||
|
||||
// Enable test for 24 hours update, service workers will always treat last update check time is over 24 hours
|
||||
pref("dom.serviceWorkers.testUpdateOverOneDay", false);
|
||||
|
||||
|
@ -14,3 +14,9 @@ kind-dependencies:
|
||||
|
||||
job-template:
|
||||
shipping-phase: promote
|
||||
worker-type:
|
||||
by-project:
|
||||
mozilla-central: scriptworker-prov-v1/beetmoverworker-v1
|
||||
mozilla-beta: scriptworker-prov-v1/beetmoverworker-v1
|
||||
mozilla-release: scriptworker-prov-v1/beetmoverworker-v1
|
||||
default: scriptworker-prov-v1/beetmoverworker-dev
|
||||
|
@ -202,7 +202,7 @@ talos-g4:
|
||||
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
|
||||
max-run-time:
|
||||
by-test-platform:
|
||||
linux64.*: 900
|
||||
linux64.*: 1500
|
||||
default: 1800
|
||||
mozharness:
|
||||
extra-options:
|
||||
@ -223,7 +223,7 @@ talos-g4-profiling:
|
||||
- --webServer,localhost
|
||||
max-run-time:
|
||||
by-test-platform:
|
||||
linux64.*: 900
|
||||
linux64.*: 1500
|
||||
default: 1800
|
||||
|
||||
talos-g5:
|
||||
|
@ -368,6 +368,9 @@ def mozharness_test_on_native_engine(config, job, taskdesc):
|
||||
if test['reboot']:
|
||||
worker['reboot'] = test['reboot']
|
||||
|
||||
if test['max-run-time']:
|
||||
worker['max-run-time'] = test['max-run-time']
|
||||
|
||||
worker['env'] = env = {
|
||||
'GECKO_HEAD_REPOSITORY': config.params['head_repository'],
|
||||
'GECKO_HEAD_REV': config.params['head_rev'],
|
||||
|
@ -8,7 +8,7 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from taskgraph.transforms.base import TransformSequence
|
||||
from taskgraph.util.attributes import copy_attributes_from_dependent_job
|
||||
from taskgraph.util.schema import validate_schema, Schema
|
||||
from taskgraph.util.schema import validate_schema, Schema, resolve_keyed_by, optionally_keyed_by
|
||||
from taskgraph.util.scriptworker import (get_beetmover_bucket_scope,
|
||||
get_beetmover_action_scope,
|
||||
get_phase)
|
||||
@ -54,6 +54,7 @@ release_generate_checksums_beetmover_schema = Schema({
|
||||
|
||||
Optional('shipping-phase'): task_description_schema['shipping-phase'],
|
||||
Optional('shipping-product'): task_description_schema['shipping-product'],
|
||||
Required('worker-type'): optionally_keyed_by('project', basestring),
|
||||
})
|
||||
|
||||
|
||||
@ -102,10 +103,14 @@ def make_task_description(config, jobs):
|
||||
action_scope = get_beetmover_action_scope(config)
|
||||
phase = get_phase(config)
|
||||
|
||||
resolve_keyed_by(
|
||||
job, 'worker-type', item_name=label, project=config.params['project']
|
||||
)
|
||||
|
||||
task = {
|
||||
'label': label,
|
||||
'description': description,
|
||||
'worker-type': 'scriptworker-prov-v1/beetmoverworker-dev',
|
||||
'worker-type': job['worker-type'],
|
||||
'scopes': [bucket_scope, action_scope],
|
||||
'dependencies': dependencies,
|
||||
'attributes': attributes,
|
||||
|
@ -77,8 +77,6 @@ def make_release_generate_checksums_signing_description(config, jobs):
|
||||
}]
|
||||
|
||||
signing_cert_scope = get_signing_cert_scope(config)
|
||||
# XXX hardcode on maple to get a green graph. DO NOT UPLIFT
|
||||
signing_cert_scope = 'project:releng:signing:cert:dep-signing'
|
||||
|
||||
task = {
|
||||
'label': label,
|
||||
|
@ -449,6 +449,9 @@ task_description_schema = Schema({
|
||||
Required('implementation'): 'native-engine',
|
||||
Required('os'): Any('macosx', 'linux'),
|
||||
|
||||
# the maximum time to run, in seconds
|
||||
Required('max-run-time'): int,
|
||||
|
||||
# A link for an executable to download
|
||||
Optional('context'): basestring,
|
||||
|
||||
@ -1221,6 +1224,7 @@ def build_macosx_engine_payload(config, task, task_def):
|
||||
'command': worker['command'],
|
||||
'env': worker['env'],
|
||||
'artifacts': artifacts,
|
||||
'maxRunTime': worker['max-run-time'],
|
||||
}
|
||||
if worker.get('reboot'):
|
||||
task_def['payload'] = worker['reboot']
|
||||
|
@ -1581,46 +1581,45 @@ or run without that action (ie: --no-{action})"
|
||||
else:
|
||||
self.fatal("could not determine packageName")
|
||||
|
||||
interests = ['libxul.so', 'classes.dex', 'omni.ja']
|
||||
installer = os.path.join(dirs['abs_obj_dir'], 'dist', packageName)
|
||||
interests = ['libxul.so', 'classes.dex', 'omni.ja', 'xul.dll']
|
||||
installer = os.path.join(dist_dir, packageName)
|
||||
installer_size = 0
|
||||
size_measurements = []
|
||||
|
||||
def paths_with_sizes(installer):
|
||||
if zipfile.is_zipfile(installer):
|
||||
with zipfile.ZipFile(installer, 'r') as zf:
|
||||
for zi in zf.infolist():
|
||||
yield zi.filename, zi.file_size
|
||||
elif tarfile.is_tarfile(installer):
|
||||
with tarfile.open(installer, 'r:*') as tf:
|
||||
for ti in tf:
|
||||
yield ti.name, ti.size
|
||||
|
||||
if os.path.exists(installer):
|
||||
installer_size = self.query_filesize(installer)
|
||||
self.info('Size of %s: %s bytes' % (packageName, installer_size))
|
||||
try:
|
||||
subtests = {}
|
||||
if zipfile.is_zipfile(installer):
|
||||
with zipfile.ZipFile(installer, 'r') as zf:
|
||||
for zi in zf.infolist():
|
||||
name = os.path.basename(zi.filename)
|
||||
size = zi.file_size
|
||||
if name in interests:
|
||||
if name in subtests:
|
||||
# File seen twice in same archive;
|
||||
# ignore to avoid confusion.
|
||||
subtests[name] = None
|
||||
else:
|
||||
subtests[name] = size
|
||||
elif tarfile.is_tarfile(installer):
|
||||
with tarfile.open(installer, 'r:*') as tf:
|
||||
for ti in tf:
|
||||
name = os.path.basename(ti.name)
|
||||
size = ti.size
|
||||
if name in interests:
|
||||
if name in subtests:
|
||||
# File seen twice in same archive;
|
||||
# ignore to avoid confusion.
|
||||
subtests[name] = None
|
||||
else:
|
||||
subtests[name] = size
|
||||
for path, size in paths_with_sizes(installer):
|
||||
name = os.path.basename(path)
|
||||
if name in interests:
|
||||
# We have to be careful here: desktop Firefox installers
|
||||
# contain two omni.ja files: one for the general runtime,
|
||||
# and one for the browser proper.
|
||||
if name == 'omni.ja':
|
||||
containing_dir = os.path.basename(os.path.dirname(path))
|
||||
if containing_dir == 'browser':
|
||||
name = 'browser-omni.ja'
|
||||
if name in subtests:
|
||||
self.fatal('should not see %s (%s) multiple times!'
|
||||
% (name, path))
|
||||
subtests[name] = size
|
||||
for name in subtests:
|
||||
if subtests[name] is not None:
|
||||
self.info('Size of %s: %s bytes' % (name,
|
||||
subtests[name]))
|
||||
size_measurements.append(
|
||||
{'name': name, 'value': subtests[name]})
|
||||
self.info('Size of %s: %s bytes' % (name,
|
||||
subtests[name]))
|
||||
size_measurements.append(
|
||||
{'name': name, 'value': subtests[name]})
|
||||
except:
|
||||
self.info('Unable to search %s for component sizes.' % installer)
|
||||
size_measurements = []
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@
|
||||
[cssSkewX.tentative.html]
|
||||
[CSSSkewX tests]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,4 @@
|
||||
[display.html]
|
||||
['display' property]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,4 @@
|
||||
[margin-top.html]
|
||||
['margin-top' property]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,97 @@
|
||||
[pseudo-class-defined.html]
|
||||
[<div> should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElement("div") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/1999/xhtml", "div") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/2000/svg", "div") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElement("div") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/1999/xhtml", "div") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/2000/svg", "div") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[<a-a> should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElement("a-a") should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/1999/xhtml", "a-a") should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/2000/svg", "a-a") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Upgraded createElement("a-a") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Upgraded createElementNS("http://www.w3.org/1999/xhtml", "a-a") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElement("a-a") should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/1999/xhtml", "a-a") should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/2000/svg", "a-a") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[<font-face> should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElement("font-face") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/1999/xhtml", "font-face") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/2000/svg", "font-face") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElement("font-face") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/1999/xhtml", "font-face") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/2000/svg", "font-face") should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[<abbr is=my-abbr> should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElement("abbr", { is: "my-abbr" }) should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/1999/xhtml", "abbr", { is: "my-abbr" }) should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[createElementNS("http://www.w3.org/2000/svg", "abbr", { is: "my-abbr" }) should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Upgraded createElement("abbr", { is: "my-abbr" }) should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Upgraded createElementNS("http://www.w3.org/1999/xhtml", "abbr", { is: "my-abbr" }) should be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElement("abbr", { is: "my-abbr" }) should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/1999/xhtml", "abbr", { is: "my-abbr" }) should not be :defined]
|
||||
expected: FAIL
|
||||
|
||||
[Without browsing context: createElementNS("http://www.w3.org/2000/svg", "abbr", { is: "my-abbr" }) should be :defined]
|
||||
expected: FAIL
|
||||
|
@ -2,7 +2,6 @@
|
||||
prefs: [dom.webcomponents.shadowdom.enabled:true]
|
||||
disabled:
|
||||
if not stylo: Shadow DOM is stylo only.
|
||||
|
||||
[removeAttribute on Element must not enqueue an attributeChanged reaction when removing an attribute that does not exist]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
local: c32b6b173c0008be57ce56cc78878c2e29ef5472
|
||||
upstream: bb1f35100ad0aedeeb6897dd640b360f80498027
|
||||
local: 001cf1ba27c3446ae6e4650a773a7022f4ce48b9
|
||||
upstream: 3197bbb8a67f73a36230d3c2deab7f70cd660727
|
||||
|
@ -0,0 +1,2 @@
|
||||
[panner-automation-basic.html]
|
||||
expected: ERROR
|
@ -0,0 +1,2 @@
|
||||
[panner-automation-position.html]
|
||||
expected: TIMEOUT
|
@ -0,0 +1,28 @@
|
||||
[panner-distance-clamping.html]
|
||||
[X new PannerNode(c, {refDistance: -1}) did not throw an exception.]
|
||||
expected: FAIL
|
||||
|
||||
[X panner.refDistance = -1 did not throw an exception.]
|
||||
expected: FAIL
|
||||
|
||||
[< [ref-distance-error\] 2 out of 6 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[X new PannerNode(c, {maxDistance: -1}) did not throw an exception.]
|
||||
expected: FAIL
|
||||
|
||||
[X new PannerNode(c, {maxDistance: 0}) did not throw an exception.]
|
||||
expected: FAIL
|
||||
|
||||
[X panner.maxDistance = -1 did not throw an exception.]
|
||||
expected: FAIL
|
||||
|
||||
[X panner.maxDistance = 0 did not throw an exception.]
|
||||
expected: FAIL
|
||||
|
||||
[< [max-distance-error\] 4 out of 6 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[# AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed.]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,40 @@
|
||||
[panner-rolloff-clamping.html]
|
||||
[X Panner distanceModel: "linear", rolloffFactor: -1 expected to be equal to the array [0,0.018875712528824806,0.05621177703142166,0.06847958266735077,0.09856243431568146,0.12242205440998077,0.1495940238237381,0.16251686215400696,0.20651382207870483,0.21217726171016693,0.2435699999332428,0.2771494388580322,0.28300273418426514,0.32210540771484375,0.344368577003479,0.36553990840911865...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t2.8312625363469124e-2\t1.8875712528824806e-2\n\t[2\]\t8.4314860403537750e-2\t5.6211777031421661e-2\n\t[3\]\t1.0271595418453217e-1\t6.8479582667350769e-2\n\t[4\]\t1.4783872663974762e-1\t9.8562434315681458e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
[< [linear-clamp-low\] 1 out of 1 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[X Panner distanceModel: "linear", rolloffFactor: 2 expected to be equal to the array [0,0.009438800625503063,0.02810869924724102,0.03424321487545967,0.049286145716905594,0.06121714785695076,0.07480449229478836,0.08126655966043472,0.10326723754405975,0.10609924048185349,0.12179718166589737,0.1385885775089264,0.14151552319526672,0.16106881201267242,0.1722015142440796,0.18278823792934418...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t1.8877600496125524e-6\t9.4388006255030632e-3\n\t[2\]\t5.6217400015157182e-6\t2.8108699247241020e-2\n\t[3\]\t6.8486433519865386e-6\t3.4243214875459671e-2\n\t[4\]\t9.8572290880838409e-6\t4.9286145716905594e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
[< [linear-clamp-high\] 1 out of 1 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[X Panner distanceModel: "inverse", rolloffFactor: -1 expected to be equal to the array [0,0.018875712528824806,0.05621177703142166,0.06847958266735077,0.09856243431568146,0.12242205440998077,0.1495940238237381,0.16251686215400696,0.20651382207870483,0.21217726171016693,0.2435699999332428,0.2771494388580322,0.28300273418426514,0.32210540771484375,0.344368577003479,0.36553990840911865...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t0.0000000000000000e+0\t1.8875712528824806e-2\n\t[2\]\t0.0000000000000000e+0\t5.6211777031421661e-2\n\t[3\]\t0.0000000000000000e+0\t6.8479582667350769e-2\n\t[4\]\t0.0000000000000000e+0\t9.8562434315681458e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
[< [inverse-clamp\] 1 out of 1 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[X Panner distanceModel: "exponential", rolloffFactor: -2 expected to be equal to the array [0,0.018875712528824806,0.05621177703142166,0.06847958266735077,0.09856243431568146,0.12242205440998077,0.1495940238237381,0.16251686215400696,0.20651382207870483,0.21217726171016693,0.2435699999332428,0.2771494388580322,0.28300273418426514,0.32210540771484375,0.344368577003479,0.36553990840911865...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t4.7189281250000000e+5\t1.8875712528824806e-2\n\t[2\]\t1.4052943750000000e+6\t5.6211777031421661e-2\n\t[3\]\t1.7119896250000000e+6\t6.8479582667350769e-2\n\t[4\]\t2.4640607500000000e+6\t9.8562434315681458e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
[< [exponential-clamp\] 1 out of 1 assertions were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[# AUDIT TASK RUNNER FINISHED: 4 out of 4 tasks were failed.]
|
||||
expected: FAIL
|
||||
|
||||
[X Panner distanceModel: "linear", rolloffFactor: -1 expected to be equal to the array [0,0.0188757237046957,0.056211769580841064,0.06847962737083435,0.09856244176626205,0.12242206931114197,0.1495940387248993,0.16251686215400696,0.2065138816833496,0.21217726171016693,0.24357002973556519,0.2771494686603546,0.2830027937889099,0.3221054673194885,0.344368577003479,0.36553993821144104...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t2.8312642127275467e-2\t1.8875723704695702e-2\n\t[2\]\t8.4314845502376556e-2\t5.6211769580841064e-2\n\t[3\]\t1.0271602123975754e-1\t6.8479627370834351e-2\n\t[4\]\t1.4783874154090881e-1\t9.8562441766262054e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
[X Panner distanceModel: "linear", rolloffFactor: 2 expected to be equal to the array [0,0.009438806213438511,0.028108695521950722,0.03424323722720146,0.04928614944219589,0.06121715530753136,0.07480449974536896,0.08126655966043472,0.10326726734638214,0.10609924048185349,0.12179719656705856,0.13858859241008759,0.1415155529975891,0.1610688418149948,0.1722015142440796,0.18278825283050537...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t1.8877611864809296e-6\t9.4388062134385109e-3\n\t[2\]\t5.6217390920210164e-6\t2.8108695521950722e-2\n\t[3\]\t6.8486474447126966e-6\t3.4243237227201462e-2\n\t[4\]\t9.8572299975785427e-6\t4.9286149442195892e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
[X Panner distanceModel: "inverse", rolloffFactor: -1 expected to be equal to the array [0,0.0188757237046957,0.056211769580841064,0.06847962737083435,0.09856244176626205,0.12242206931114197,0.1495940387248993,0.16251686215400696,0.2065138816833496,0.21217726171016693,0.24357002973556519,0.2771494686603546,0.2830027937889099,0.3221054673194885,0.344368577003479,0.36553993821144104...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t0.0000000000000000e+0\t1.8875723704695702e-2\n\t[2\]\t0.0000000000000000e+0\t5.6211769580841064e-2\n\t[3\]\t0.0000000000000000e+0\t6.8479627370834351e-2\n\t[4\]\t0.0000000000000000e+0\t9.8562441766262054e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
||||
[X Panner distanceModel: "exponential", rolloffFactor: -2 expected to be equal to the array [0,0.0188757237046957,0.056211769580841064,0.06847962737083435,0.09856244176626205,0.12242206931114197,0.1495940387248993,0.16251686215400696,0.2065138816833496,0.21217726171016693,0.24357002973556519,0.2771494686603546,0.2830027937889099,0.3221054673194885,0.344368577003479,0.36553993821144104...\] but differs in 2047 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t4.7189309375000000e+5\t1.8875723704695702e-2\n\t[2\]\t1.4052942500000000e+6\t5.6211769580841064e-2\n\t[3\]\t1.7119906250000000e+6\t6.8479627370834351e-2\n\t[4\]\t2.4640610000000000e+6\t9.8562441766262054e-2\n\t...and 2043 more errors.]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,2 @@
|
||||
[pannernode-basic.html]
|
||||
expected: ERROR
|
@ -54,6 +54,9 @@ function assert_style_value_equals(a, b) {
|
||||
assert_style_value_equals(a.ax, b.ax);
|
||||
assert_style_value_equals(a.ay, b.ay);
|
||||
break;
|
||||
case 'CSSSkewX':
|
||||
assert_style_value_equals(a.ax, b.ax);
|
||||
break;
|
||||
case 'CSSPerspective':
|
||||
assert_style_value_equals(a.length, b.length);
|
||||
break;
|
||||
|
@ -123,6 +123,11 @@ const gTestCases = [
|
||||
expected: new CSSSkew(CSS.deg(90), CSS.deg(0)),
|
||||
desc: 'skew() with only X'
|
||||
},
|
||||
{
|
||||
cssText: 'skew(90deg, 0deg)',
|
||||
expected: new CSSSkew(CSS.deg(90), CSS.deg(0)),
|
||||
desc: 'skew() with X and Y which is 0 value'
|
||||
},
|
||||
{
|
||||
cssText: 'skew(90deg, 45deg)',
|
||||
expected: new CSSSkew(CSS.deg(90), CSS.deg(45)),
|
||||
@ -130,7 +135,7 @@ const gTestCases = [
|
||||
},
|
||||
{
|
||||
cssText: 'skewX(90deg)',
|
||||
expected: new CSSSkew(CSS.deg(90), CSS.deg(0)),
|
||||
expected: new CSSSkewX(CSS.deg(90)),
|
||||
desc: 'skewX()'
|
||||
},
|
||||
{
|
||||
@ -153,12 +158,13 @@ for (const {cssText, expected, desc} of gTestCases) {
|
||||
|
||||
test(t => {
|
||||
test_transform_normalization(t,
|
||||
'translate(1px) rotateX(90deg) perspective(1px) skew(90deg) scale3d(1, 2, 3)',
|
||||
'translate(1px) rotateX(90deg) perspective(1px) skew(90deg) skewX(20deg) scale3d(1, 2, 3)',
|
||||
new CSSTransformValue([
|
||||
new CSSTranslate(CSS.px(1), CSS.px(0)),
|
||||
new CSSRotate(CSS.number(1), CSS.number(0), CSS.number(0), CSS.deg(90)),
|
||||
new CSSPerspective(CSS.px(1)),
|
||||
new CSSSkew(CSS.deg(90), CSS.deg(0)),
|
||||
new CSSSkewX(CSS.deg(20)),
|
||||
new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)),
|
||||
]));
|
||||
}, 'Normalizing a <transform-list> returns a CSSTransformValue containing all the transforms');
|
||||
|
@ -49,6 +49,11 @@ const gTestCases = [
|
||||
cssText: 'skew(90deg)',
|
||||
desc: 'CSSSkew with Y which is 0 value'
|
||||
},
|
||||
{
|
||||
value: new CSSSkewX(CSS.deg(90)),
|
||||
cssText: 'skewX(90deg)',
|
||||
desc: 'CSSSkewX'
|
||||
},
|
||||
{
|
||||
value: new CSSPerspective(CSS.px(1)),
|
||||
cssText: 'perspective(1px)',
|
||||
|
@ -0,0 +1,62 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSSSkewX tests</title>
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssskewx">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/testhelper.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const gInvalidTestCases = [
|
||||
{ value: 'auto', desc: 'a keyword'},
|
||||
{ value: 3.14, desc: 'a double'},
|
||||
{ value: 0, desc: 'a unitless zero'},
|
||||
{ value: '10deg', desc: 'a string angle'},
|
||||
{ value: CSS.number(10), desc: 'a number CSSUnitValue'},
|
||||
{ value: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
|
||||
{ value: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
|
||||
];
|
||||
|
||||
for (const {value, desc} of gInvalidTestCases) {
|
||||
test(() => {
|
||||
assert_throws(new TypeError(), () => new CSSSkewX(value));
|
||||
}, 'Constructing a CSSSkewX with ' + desc + ' throws a TypeError');
|
||||
}
|
||||
|
||||
for (const {value, desc} of gInvalidTestCases) {
|
||||
test(() => {
|
||||
let skewX = new CSSSkewX(CSS.deg(0));
|
||||
assert_throws(new TypeError(), () => skewX.ax = value);
|
||||
assert_style_value_equals(skewX.ax, CSS.deg(0));
|
||||
}, 'Updating CSSSkewX.ax with ' + desc + ' throws a TypeError');
|
||||
}
|
||||
|
||||
const gValidTestCases = [
|
||||
{ value: CSS.deg(-3.14), desc: 'an angle CSSUnitValue' },
|
||||
{ value: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
|
||||
];
|
||||
|
||||
for (const {value: ax, desc: axDesc} of gValidTestCases) {
|
||||
test(() => {
|
||||
const skewX = new CSSSkewX(ax);
|
||||
assert_equals(skewX.ax, ax);
|
||||
assert_true(skewX.is2D);
|
||||
}, 'CSSSkewX can be constructed from ' + axDesc);
|
||||
}
|
||||
|
||||
for (const {value, desc} of gValidTestCases) {
|
||||
test(() => {
|
||||
let skewX = new CSSSkewX(CSS.deg(0));
|
||||
skewX.ax = value;
|
||||
assert_style_value_equals(skewX.ax, value);
|
||||
}, 'CSSSkew.ax can be updated to ' + desc);
|
||||
}
|
||||
|
||||
test(() => {
|
||||
let skewX = new CSSSkewX(CSS.deg(0));
|
||||
skewX.is2D = false;
|
||||
assert_true(skewX.is2D);
|
||||
}, 'Modifying skewX.is2D is a no-op');
|
||||
|
||||
</script>
|
@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>'display' property</title>
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/testhelper.js"></script>
|
||||
<script src="resources/testsuite.js"></script>
|
||||
<body>
|
||||
<div id="log">
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
runPropertyTests('display', [
|
||||
{
|
||||
specified: '<ident>',
|
||||
examples: [new CSSKeywordValue('none'), new CSSKeywordValue('block')]
|
||||
},
|
||||
]);
|
||||
|
||||
</script>
|
@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>'margin-top' property</title>
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/testhelper.js"></script>
|
||||
<script src="resources/testsuite.js"></script>
|
||||
<body>
|
||||
<div id="log">
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
runPropertyTests('margin-top', [
|
||||
{ specified: '0' },
|
||||
{ specified: '<ident>', examples: [new CSSKeywordValue('auto')] },
|
||||
{ specified: '<percentage>' },
|
||||
{ specified: '<length>' },
|
||||
]);
|
||||
|
||||
</script>
|
@ -0,0 +1,62 @@
|
||||
function testGet(propertyName, values, description) {
|
||||
test(t => {
|
||||
let element = createDivWithStyle(t);
|
||||
let styleMap = element.attributeStyleMap;
|
||||
|
||||
for (const styleValue of values) {
|
||||
element.style[propertyName] = styleValue.toString();
|
||||
|
||||
getComputedStyle(element); // Force a style recalc.
|
||||
const result = styleMap.get(propertyName);
|
||||
assert_style_value_equals(result, styleValue);
|
||||
}
|
||||
}, `Can get ${description} from '${propertyName}'`);
|
||||
}
|
||||
|
||||
function testSet(propertyName, values, description) {
|
||||
test(t => {
|
||||
let element = createDivWithStyle(t);
|
||||
let styleMap = element.attributeStyleMap;
|
||||
|
||||
for (const styleValue of values) {
|
||||
styleMap.set(propertyName, styleValue);
|
||||
|
||||
getComputedStyle(element); // Force a style recalc.
|
||||
assert_equals(element.style[propertyName], styleValue.toString());
|
||||
}
|
||||
}, `Can set '${propertyName}' to ${description}`);
|
||||
}
|
||||
|
||||
function testGetSet(propertyName, values, description) {
|
||||
testGet(propertyName, values, description);
|
||||
testSet(propertyName, values, description);
|
||||
}
|
||||
|
||||
function runPropertyTests(propertyName, testCases) {
|
||||
for (const testCase of testCases) {
|
||||
if (testCase.specified == '0') {
|
||||
testSet(propertyName, [
|
||||
new CSSUnitValue(0, 'number'),
|
||||
], 'unitless zero');
|
||||
} else if (testCase.specified === '<length>') {
|
||||
testGetSet(propertyName, [
|
||||
new CSSUnitValue(0, 'px'),
|
||||
new CSSUnitValue(-3.14, 'em'),
|
||||
new CSSUnitValue(3.14, 'cm'),
|
||||
], 'a length CSSUnitValue');
|
||||
} else if (testCase.specified == '<percentage>') {
|
||||
testGetSet(propertyName, [
|
||||
new CSSUnitValue(0, 'percent'),
|
||||
new CSSUnitValue(-3.14, 'percent'),
|
||||
new CSSUnitValue(3.14, 'percent'),
|
||||
], 'a percent CSSUnitValue');
|
||||
} else if (testCase.specified == '<ident>') {
|
||||
if (!testCase.examples) {
|
||||
throw new Error('<ident> tests require examples');
|
||||
}
|
||||
|
||||
testGetSet(propertyName, testCase.examples,
|
||||
'a CSSKeywordValue');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Basic User Interface Test Reference</title>
|
||||
<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
|
||||
<style>
|
||||
div { font-family: monospace; }
|
||||
</style>
|
||||
|
||||
<p>The test passes if the following text is visible below: 123456 FE…</p>
|
||||
<div>123456 FE…</bdo></div>
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Basic User Interface Test Reference</title>
|
||||
<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
|
||||
<style>
|
||||
div { font-family: monospace; }
|
||||
</style>
|
||||
|
||||
<p>The test passes if the following text is visible below: …56 FEDCBA</p>
|
||||
<div>…56 FEDCBA</div>
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Basic User Interface Reference</title>
|
||||
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
|
||||
<style>
|
||||
div { font: 20px monospace; }
|
||||
</style>
|
||||
|
||||
<div>Test passed…</div>
|
21
testing/web-platform/tests/css/css-ui/text-overflow-027.html
Normal file
21
testing/web-platform/tests/css/css-ui/text-overflow-027.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Basic User Interface Test: text-overflow applies visually to bidi</title>
|
||||
<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-ui-3/#text-overflow">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-ui-4/#text-overflow">
|
||||
<link rel="match" href="reference/text-overflow-027-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="text-overflow is a visual operation that occurs after layout, and therfore ellides text from the visual end of the line, even in bidi situations">
|
||||
<style>
|
||||
div {
|
||||
font-family: monospace;
|
||||
width: 10ch;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>The test passes if the following text is visible below: 123456 FE…</p>
|
||||
<div>123456 <bdo dir=rtl>ABCDEF</bdo></div>
|
21
testing/web-platform/tests/css/css-ui/text-overflow-028.html
Normal file
21
testing/web-platform/tests/css/css-ui/text-overflow-028.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Basic User Interface Test: text-overflow applies visually to bidi</title>
|
||||
<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-ui-3/#text-overflow">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-ui-4/#text-overflow">
|
||||
<link rel="match" href="reference/text-overflow-028-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="text-overflow is a visual operation that occurs after layout, and therfore ellides text from the visual end of the line, even in bidi situations">
|
||||
<style>
|
||||
div {
|
||||
font-family: monospace;
|
||||
width: 10ch;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>The test passes if the following text is visible below: …56 FEDCBA</p>
|
||||
<div dir=rtl><bdo dir=rtl>ABCDEF</bdo> 123456</div>
|
21
testing/web-platform/tests/css/css-ui/text-overflow-029.html
Normal file
21
testing/web-platform/tests/css/css-ui/text-overflow-029.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Basic User Interface Test: text-overflow and bidi interaction</title>
|
||||
<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-ui-3/#text-overflow">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-ui-4/#text-overflow">
|
||||
<link rel="match" href="reference/text-overflow-029-ref.html">
|
||||
<meta name="assert" content="When there's content of mixed directionality, text-overflow ellides the characters at the physical end of the line.">
|
||||
<meta name="flags" content="">
|
||||
<style>
|
||||
div {
|
||||
font: 20px monospace;
|
||||
width: 12.3ch; /* slightly more than 12ch because in some browsers (safari) the ellipsis is slightly large than other characters, even in monospace fonts. */
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>Test ‮deliafdessap‬</div>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user