mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
9d3617e4b7
@ -1816,6 +1816,7 @@ pref("print.enable_e10s_testing", true);
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Enable e10s add-on interposition by default.
|
||||
pref("extensions.interposition.enabled", true);
|
||||
pref("extensions.interposition.prefetching", true);
|
||||
#endif
|
||||
|
||||
pref("browser.defaultbrowser.notificationbar", false);
|
||||
|
@ -838,6 +838,7 @@ nsDocShell::nsDocShell():
|
||||
mAllowKeywordFixup(false),
|
||||
mIsOffScreenBrowser(false),
|
||||
mIsActive(true),
|
||||
mIsPrerendered(false),
|
||||
mIsAppTab(false),
|
||||
mUseGlobalHistory(false),
|
||||
mInPrivateBrowsing(false),
|
||||
@ -3386,6 +3387,11 @@ nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
|
||||
{
|
||||
SetIsActive(value);
|
||||
}
|
||||
if (NS_SUCCEEDED(parentAsDocShell->GetIsPrerendered(&value))) {
|
||||
if (value) {
|
||||
SetIsPrerendered(true);
|
||||
}
|
||||
}
|
||||
if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
|
||||
value = false;
|
||||
}
|
||||
@ -6052,6 +6058,22 @@ nsDocShell::GetIsActive(bool *aIsActive)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetIsPrerendered(bool aPrerendered)
|
||||
{
|
||||
MOZ_ASSERT(!aPrerendered || !mIsPrerendered,
|
||||
"SetIsPrerendered(true) called on already prerendered docshell");
|
||||
mIsPrerendered = aPrerendered;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetIsPrerendered(bool *aIsPrerendered)
|
||||
{
|
||||
*aIsPrerendered = mIsPrerendered;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetIsAppTab(bool aIsAppTab)
|
||||
{
|
||||
@ -8553,8 +8575,8 @@ nsDocShell::RestoreFromHistory()
|
||||
|
||||
// this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
|
||||
// that the child inherits our state. Among other things, this means
|
||||
// that the child inherits our mIsActive and mInPrivateBrowsing, which
|
||||
// is what we want.
|
||||
// that the child inherits our mIsActive, mIsPrerendered and mInPrivateBrowsing,
|
||||
// which is what we want.
|
||||
AddChild(childItem);
|
||||
|
||||
childShell->SetAllowPlugins(allowPlugins);
|
||||
|
@ -877,6 +877,7 @@ protected:
|
||||
bool mAllowKeywordFixup;
|
||||
bool mIsOffScreenBrowser;
|
||||
bool mIsActive;
|
||||
bool mIsPrerendered;
|
||||
bool mIsAppTab;
|
||||
bool mUseGlobalHistory;
|
||||
bool mInPrivateBrowsing;
|
||||
|
@ -54,7 +54,7 @@ interface nsITabParent;
|
||||
|
||||
typedef unsigned long nsLoadFlags;
|
||||
|
||||
[scriptable, builtinclass, uuid(c2756385-bc54-417b-9ae4-c5a40053a2a3)]
|
||||
[scriptable, builtinclass, uuid(fef3bae1-6673-4c49-9f5a-fcc075926730)]
|
||||
interface nsIDocShell : nsIDocShellTreeItem
|
||||
{
|
||||
/**
|
||||
@ -619,6 +619,13 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
*/
|
||||
attribute boolean isActive;
|
||||
|
||||
/**
|
||||
* Puts the docshell in prerendering mode. noscript because we want only
|
||||
* native code to be able to put a docshell in prerendering.
|
||||
*/
|
||||
[noscript] void SetIsPrerendered(in boolean prerendered);
|
||||
readonly attribute boolean isPrerendered;
|
||||
|
||||
/**
|
||||
* The ID of the docshell in the session history.
|
||||
*/
|
||||
|
@ -60,14 +60,8 @@ AnimationTimeline::FastForward(const TimeStamp& aTimeStamp)
|
||||
return;
|
||||
}
|
||||
|
||||
// Bug 1113413: If the refresh driver has just been restored from test
|
||||
// control it's possible that aTimeStamp could be before the most recent
|
||||
// refresh.
|
||||
if (refreshDriver &&
|
||||
aTimeStamp < refreshDriver->MostRecentRefresh()) {
|
||||
mFastForwardTime = refreshDriver->MostRecentRefresh();
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(!refreshDriver || aTimeStamp >= refreshDriver->MostRecentRefresh(),
|
||||
"aTimeStamp must be >= the refresh driver time");
|
||||
|
||||
// FIXME: For all animations attached to this timeline, we should mark
|
||||
// their target elements as needing restyling. Otherwise, tasks that run
|
||||
|
@ -67,4 +67,36 @@ async_test(function(t) {
|
||||
}, 'ready promise is rejected when a transition is cancelled by updating'
|
||||
+ ' transition-property');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t);
|
||||
|
||||
// Set up pending transition
|
||||
div.style.marginLeft = '0px';
|
||||
window.getComputedStyle(div).marginLeft;
|
||||
div.style.transition = 'margin-left 100s';
|
||||
div.style.marginLeft = '100px';
|
||||
window.getComputedStyle(div).marginLeft;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
assert_equals(player.playState, 'pending', 'Player is initially pending');
|
||||
|
||||
// Set up listeners on ready promise
|
||||
player.ready.then(t.step_func(function() {
|
||||
assert_unreached('ready promise was fulfilled');
|
||||
})).catch(t.step_func(function(err) {
|
||||
assert_equals(err.name, 'AbortError',
|
||||
'ready promise is rejected with AbortError');
|
||||
assert_equals(player.playState, 'idle',
|
||||
'Player is idle after transition was cancelled');
|
||||
})).then(t.step_func(function() {
|
||||
t.done();
|
||||
}));
|
||||
|
||||
// Now update the transition to animate to something not-interpolable
|
||||
div.style.marginLeft = 'auto';
|
||||
window.getComputedStyle(div).marginLeft;
|
||||
|
||||
}, 'ready promise is rejected when a transition is cancelled by changing'
|
||||
+ ' the transition property to something not interpolable');
|
||||
|
||||
</script>
|
||||
|
@ -7,7 +7,7 @@ skip-if = buildapp == 'mulet'
|
||||
[css-animations/test_animations-dynamic-changes.html]
|
||||
[css-animations/test_animation-effect-name.html]
|
||||
[css-animations/test_animation-pausing.html]
|
||||
skip-if = os == "mac" && os_version == "10.8" # disabled until bug 1112480 lands
|
||||
skip-if = os == "win" || (os == "mac" && os_version == "10.8") # disabled until bug 1112480 lands
|
||||
[css-animations/test_animation-player-playstate.html]
|
||||
[css-animations/test_animation-player-ready.html]
|
||||
[css-animations/test_animation-target.html]
|
||||
|
@ -407,7 +407,13 @@ this.PermissionsTable = { geolocation: {
|
||||
privileged: PROMPT_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"nfc": {
|
||||
"audio-capture:3gpp": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"nfc": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
|
@ -201,11 +201,7 @@ EventSource::Init(nsISupports* aOwner,
|
||||
|
||||
// The conditional here is historical and not necessarily sane.
|
||||
if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
|
||||
const char *filename;
|
||||
if (nsJSUtils::GetCallingLocation(cx, &filename, &mScriptLine)) {
|
||||
mScriptFile.AssignASCII(filename);
|
||||
}
|
||||
|
||||
nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine);
|
||||
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
|
||||
}
|
||||
|
||||
|
@ -83,8 +83,11 @@ WindowNamedPropertiesHandler::getOwnPropDescriptor(JSContext* aCx,
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
|
||||
if (HasPropertyOnPrototype(aCx, aProxy, aId)) {
|
||||
bool hasOnPrototype;
|
||||
if (!HasPropertyOnPrototype(aCx, aProxy, aId, &hasOnPrototype)) {
|
||||
return false;
|
||||
}
|
||||
if (hasOnPrototype) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -94,6 +97,7 @@ WindowNamedPropertiesHandler::getOwnPropDescriptor(JSContext* aCx,
|
||||
}
|
||||
|
||||
// Grab the DOM window.
|
||||
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
|
||||
nsGlobalWindow* win = xpc::WindowOrNull(global);
|
||||
if (win->Length() > 0) {
|
||||
nsCOMPtr<nsIDOMWindow> childWin = win->GetChildWindow(str);
|
||||
|
@ -3364,12 +3364,7 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
|
||||
if (!aLineNumber) {
|
||||
JSContext *cx = GetCurrentJSContext();
|
||||
if (cx) {
|
||||
const char* filename;
|
||||
uint32_t lineno;
|
||||
if (nsJSUtils::GetCallingLocation(cx, &filename, &lineno)) {
|
||||
spec = filename;
|
||||
aLineNumber = lineno;
|
||||
}
|
||||
nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber);
|
||||
}
|
||||
}
|
||||
if (spec.IsEmpty() && aURI)
|
||||
|
@ -112,6 +112,9 @@ nsElementFrameLoaderOwner::EnsureFrameLoader()
|
||||
// Strangely enough, this method doesn't actually ensure that the
|
||||
// frameloader exists. It's more of a best-effort kind of thing.
|
||||
mFrameLoader = nsFrameLoader::Create(thisElement, mNetworkCreated);
|
||||
if (mIsPrerendered) {
|
||||
mFrameLoader->SetIsPrerendered();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -135,6 +138,14 @@ nsElementFrameLoaderOwner::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsElementFrameLoaderOwner::SetIsPrerendered()
|
||||
{
|
||||
MOZ_ASSERT(!mFrameLoader, "Please call SetIsPrerendered before frameLoader is created");
|
||||
mIsPrerendered = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsElementFrameLoaderOwner::LoadSrc()
|
||||
{
|
||||
|
@ -33,6 +33,7 @@ class nsElementFrameLoaderOwner : public nsIFrameLoaderOwner
|
||||
public:
|
||||
explicit nsElementFrameLoaderOwner(mozilla::dom::FromParser aFromParser)
|
||||
: mNetworkCreated(aFromParser == mozilla::dom::FROM_PARSER_NETWORK)
|
||||
, mIsPrerendered(false)
|
||||
, mBrowserFrameListenersRegistered(false)
|
||||
, mFrameLoaderCreationDisallowed(false)
|
||||
{
|
||||
@ -70,6 +71,7 @@ protected:
|
||||
*/
|
||||
bool mNetworkCreated;
|
||||
|
||||
bool mIsPrerendered;
|
||||
bool mBrowserFrameListenersRegistered;
|
||||
bool mFrameLoaderCreationDisallowed;
|
||||
};
|
||||
|
@ -154,6 +154,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
|
||||
: mOwnerContent(aOwner)
|
||||
, mAppIdSentToPermissionManager(nsIScriptSecurityManager::NO_APP_ID)
|
||||
, mDetachedSubdocViews(nullptr)
|
||||
, mIsPrerendered(false)
|
||||
, mDepthTooGreat(false)
|
||||
, mIsTopLevelContent(false)
|
||||
, mDestroyCalled(false)
|
||||
@ -295,6 +296,15 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::SetIsPrerendered()
|
||||
{
|
||||
MOZ_ASSERT(!mDocShell, "Please call SetIsPrerendered before docShell is created");
|
||||
mIsPrerendered = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameLoader::ReallyStartLoading()
|
||||
{
|
||||
@ -1613,6 +1623,11 @@ nsFrameLoader::MaybeCreateDocShell()
|
||||
mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
|
||||
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
|
||||
|
||||
if (mIsPrerendered) {
|
||||
nsresult rv = mDocShell->SetIsPrerendered(true);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// Apply sandbox flags even if our owner is not an iframe, as this copies
|
||||
// flags from our owning content's owning document.
|
||||
uint32_t sandboxFlags = 0;
|
||||
|
@ -331,6 +331,7 @@ private:
|
||||
// a reframe, so that we know not to restore the presentation.
|
||||
nsCOMPtr<nsIDocument> mContainerDocWhileDetached;
|
||||
|
||||
bool mIsPrerendered : 1;
|
||||
bool mDepthTooGreat : 1;
|
||||
bool mIsTopLevelContent : 1;
|
||||
bool mDestroyCalled : 1;
|
||||
|
@ -951,6 +951,7 @@ GK_ATOM(precedingSibling, "preceding-sibling")
|
||||
GK_ATOM(predicate, "predicate")
|
||||
GK_ATOM(prefix, "prefix")
|
||||
GK_ATOM(preload, "preload")
|
||||
GK_ATOM(prerendered, "prerendered")
|
||||
GK_ATOM(preserve, "preserve")
|
||||
GK_ATOM(preserveSpace, "preserve-space")
|
||||
GK_ATOM(preventdefault, "preventdefault")
|
||||
|
@ -1118,6 +1118,8 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||
mCanSkipCCGeneration(0),
|
||||
mVRDevicesInitialized(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsLayoutStatics::AddRef();
|
||||
|
||||
// Initialize the PRCList (this).
|
||||
@ -1218,10 +1220,23 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsGlobalWindow::AssertIsOnMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsGlobalWindow::Init()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
|
||||
NS_ASSERTION(gEntropyCollector,
|
||||
"gEntropyCollector should have been initialized!");
|
||||
@ -1245,6 +1260,8 @@ DisconnectEventTargetObjects(nsPtrHashKey<DOMEventTargetHelper>* aKey,
|
||||
|
||||
nsGlobalWindow::~nsGlobalWindow()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
|
||||
mEventTargetObjects.Clear();
|
||||
|
||||
@ -1363,6 +1380,8 @@ nsGlobalWindow::RemoveEventTargetObject(DOMEventTargetHelper* aObject)
|
||||
void
|
||||
nsGlobalWindow::ShutDown()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (gDumpFile && gDumpFile != stdout) {
|
||||
fclose(gDumpFile);
|
||||
}
|
||||
|
@ -334,6 +334,14 @@ public:
|
||||
typedef mozilla::TimeDuration TimeDuration;
|
||||
typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindow*> WindowByIdTable;
|
||||
|
||||
static void
|
||||
AssertIsOnMainThread()
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
|
||||
// public methods
|
||||
nsPIDOMWindow* GetPrivateParent();
|
||||
|
||||
@ -670,6 +678,8 @@ public:
|
||||
}
|
||||
|
||||
static nsGlobalWindow* GetOuterWindowWithId(uint64_t aWindowID) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!sWindowsById) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -679,6 +689,8 @@ public:
|
||||
}
|
||||
|
||||
static nsGlobalWindow* GetInnerWindowWithId(uint64_t aInnerWindowID) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!sWindowsById) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -688,6 +700,8 @@ public:
|
||||
}
|
||||
|
||||
static WindowByIdTable* GetWindowsTable() {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
return sWindowsById;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ interface nsIDOMElement;
|
||||
interface nsITabParent;
|
||||
interface nsILoadContext;
|
||||
|
||||
[scriptable, builtinclass, uuid(7600aa92-88dc-491c-896d-0564159b6a66)]
|
||||
[scriptable, builtinclass, uuid(28b6b043-46ec-412f-9be9-db22938b0d6d)]
|
||||
interface nsIFrameLoader : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -49,6 +49,11 @@ interface nsIFrameLoader : nsISupports
|
||||
*/
|
||||
void loadURI(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Puts the frameloader in prerendering mode.
|
||||
*/
|
||||
void setIsPrerendered();
|
||||
|
||||
/**
|
||||
* Destroy the frame loader and everything inside it. This will
|
||||
* clear the weak owner content reference.
|
||||
@ -192,7 +197,7 @@ class nsFrameLoader;
|
||||
|
||||
native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
|
||||
|
||||
[scriptable, uuid(5879040e-83e9-40e3-b2bb-5ddf43b76e47)]
|
||||
[scriptable, uuid(c4abebcf-55f3-47d4-af15-151311971255)]
|
||||
interface nsIFrameLoaderOwner : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -201,6 +206,11 @@ interface nsIFrameLoaderOwner : nsISupports
|
||||
readonly attribute nsIFrameLoader frameLoader;
|
||||
[noscript, notxpcom] alreadyAddRefed_nsFrameLoader GetFrameLoader();
|
||||
|
||||
/**
|
||||
* Puts the FrameLoaderOwner in prerendering mode.
|
||||
*/
|
||||
void setIsPrerendered();
|
||||
|
||||
/**
|
||||
* Swap frame loaders with the given nsIFrameLoaderOwner. This may
|
||||
* only be posible in a very limited range of circumstances, or
|
||||
|
@ -173,11 +173,8 @@ CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)
|
||||
|
||||
// Get the calling location.
|
||||
uint32_t lineNum = 0;
|
||||
const char *fileName;
|
||||
nsAutoString fileNameString;
|
||||
if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNum)) {
|
||||
AppendUTF8toUTF16(fileName, fileNameString);
|
||||
} else {
|
||||
if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum)) {
|
||||
fileNameString.AssignLiteral("unknown");
|
||||
}
|
||||
|
||||
@ -233,10 +230,7 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
|
||||
}
|
||||
|
||||
// Get the calling location.
|
||||
const char *filename;
|
||||
if (nsJSUtils::GetCallingLocation(aCx, &filename, &mLineNo)) {
|
||||
mFileName.Assign(filename);
|
||||
}
|
||||
nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo);
|
||||
}
|
||||
|
||||
nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler()
|
||||
@ -353,10 +347,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval,
|
||||
AssignJSFlatString(mExpr, expr);
|
||||
|
||||
// Get the calling location.
|
||||
const char *filename;
|
||||
if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
|
||||
mFileName.Assign(filename);
|
||||
}
|
||||
nsJSUtils::GetCallingLocation(cx, mFileName, &mLineNo);
|
||||
} else if (funobj) {
|
||||
*aAllowEval = true;
|
||||
|
||||
|
@ -34,19 +34,28 @@
|
||||
using namespace mozilla::dom;
|
||||
|
||||
bool
|
||||
nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
|
||||
nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
|
||||
uint32_t* aLineno)
|
||||
{
|
||||
JS::AutoFilename filename;
|
||||
unsigned lineno = 0;
|
||||
|
||||
if (!JS::DescribeScriptedCaller(aContext, &filename, &lineno)) {
|
||||
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aFilename = filename.get();
|
||||
*aLineno = lineno;
|
||||
aFilename.Assign(filename.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
|
||||
uint32_t* aLineno)
|
||||
{
|
||||
JS::AutoFilename filename;
|
||||
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aFilename.Assign(NS_ConvertUTF8toUTF16(filename.get()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,9 @@ class Element;
|
||||
class nsJSUtils
|
||||
{
|
||||
public:
|
||||
static bool GetCallingLocation(JSContext* aContext, const char* *aFilename,
|
||||
static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
|
||||
uint32_t* aLineno);
|
||||
static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
|
||||
uint32_t* aLineno);
|
||||
|
||||
static nsIScriptGlobalObject *GetStaticScriptGlobal(JSObject* aObj);
|
||||
|
@ -324,6 +324,7 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
|
||||
// if aDeep is true, deal with aNode's children (and recurse into their
|
||||
// attributes and children).
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
AutoJSContext cx;
|
||||
nsresult rv;
|
||||
|
||||
|
@ -1199,6 +1199,12 @@ nsObjectLoadingContent::GetFrameLoader()
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::SetIsPrerendered()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoader)
|
||||
{
|
||||
|
@ -366,6 +366,10 @@ nsresult TestPaths() {
|
||||
"connect-src http://www.example.com/foo;sessionid=12,34" },
|
||||
{ "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@",
|
||||
"connect-src http://test.com/pathincludingaz19-._~!$&'()*+=:@" },
|
||||
{ "script-src http://www.example.com:88/.js",
|
||||
"script-src http://www.example.com:88/.js" },
|
||||
{ "script-src https://foo.com/_abc/abc_/_/_a_b_c_",
|
||||
"script-src https://foo.com/_abc/abc_/_/_a_b_c_" }
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
@ -490,8 +494,6 @@ nsresult TestPoliciesWithInvalidSrc() {
|
||||
"script-src 'none'" },
|
||||
{ "script-src http://www.example.com:88//path-1",
|
||||
"script-src 'none'" },
|
||||
{ "script-src http://www.example.com:88/.js",
|
||||
"script-src 'none'" },
|
||||
{ "script-src http://www.example.com:88.js",
|
||||
"script-src 'none'" },
|
||||
{ "script-src http://www.example.com:*.js",
|
||||
|
@ -92,7 +92,10 @@ public:
|
||||
protected:
|
||||
JS::Rooted<JSObject*> mGlobalJSObject;
|
||||
JSContext* mCx;
|
||||
mutable nsISupports* mGlobalObject;
|
||||
mutable nsISupports* MOZ_UNSAFE_REF("Valid because GlobalObject is a stack "
|
||||
"class, and mGlobalObject points to the "
|
||||
"global, so it won't be destroyed as long "
|
||||
"as GlobalObject lives on the stack") mGlobalObject;
|
||||
};
|
||||
|
||||
// Class for representing optional arguments.
|
||||
|
@ -1613,7 +1613,7 @@ NativePropertyHooks sWorkerNativePropertyHooks = {
|
||||
bool
|
||||
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id, bool* found,
|
||||
JS::Value* vp)
|
||||
JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
if (!js::GetObjectProto(cx, proxy, &proto)) {
|
||||
@ -1624,33 +1624,31 @@ GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasProp;
|
||||
if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
|
||||
if (!JS_HasPropertyById(cx, proto, id, found)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*found = hasProp;
|
||||
if (!hasProp || !vp) {
|
||||
if (!*found) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
if (!JS_ForwardGetPropertyTo(cx, proto, id, proxy, &value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*vp = value;
|
||||
return true;
|
||||
return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id)
|
||||
JS::Handle<jsid> id, bool* has)
|
||||
{
|
||||
bool found;
|
||||
// We ignore an error from GetPropertyOnPrototype. We pass nullptr
|
||||
// for vp so that GetPropertyOnPrototype won't actually do a get.
|
||||
return !GetPropertyOnPrototype(cx, proxy, id, &found, nullptr) || found;
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
if (!js::GetObjectProto(cx, proxy, &proto)) {
|
||||
return false;
|
||||
}
|
||||
if (!proto) {
|
||||
*has = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return JS_HasPropertyById(cx, proto, id, has);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1670,7 +1668,16 @@ AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shadowPrototypeProperties || !HasPropertyOnPrototype(cx, proxy, id)) {
|
||||
bool shouldAppend = shadowPrototypeProperties;
|
||||
if (!shouldAppend) {
|
||||
bool has;
|
||||
if (!HasPropertyOnPrototype(cx, proxy, id, &has)) {
|
||||
return false;
|
||||
}
|
||||
shouldAppend = !has;
|
||||
}
|
||||
|
||||
if (shouldAppend) {
|
||||
if (!props.append(id)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1810,16 +1810,15 @@ ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
bool
|
||||
ThrowConstructorWithoutNew(JSContext* cx, const char* name);
|
||||
|
||||
// vp is allowed to be null; in that case no get will be attempted,
|
||||
// and *found will simply indicate whether the property exists.
|
||||
bool
|
||||
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id, bool* found,
|
||||
JS::Value* vp);
|
||||
JS::MutableHandle<JS::Value> vp);
|
||||
|
||||
//
|
||||
bool
|
||||
HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id);
|
||||
JS::Handle<jsid> id, bool* has);
|
||||
|
||||
|
||||
// Append the property names in "names" to "props". If
|
||||
|
@ -10104,15 +10104,41 @@ class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
|
||||
"return true;\n" % (readonly, enumerable))
|
||||
templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
|
||||
'obj': 'proxy', 'successCode': fillDescriptor}
|
||||
condition = "!HasPropertyOnPrototype(cx, proxy, id)"
|
||||
|
||||
computeCondition = dedent("""
|
||||
bool hasOnProto;
|
||||
if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
|
||||
return false;
|
||||
}
|
||||
callNamedGetter = !hasOnProto;
|
||||
""")
|
||||
if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
condition = "(!isXray || %s)" % condition
|
||||
condition = "!ignoreNamedProps && " + condition
|
||||
computeCondition = fill("""
|
||||
if (!isXray) {
|
||||
callNamedGetter = true;
|
||||
} else {
|
||||
$*{hasOnProto}
|
||||
}
|
||||
""",
|
||||
hasOnProto=computeCondition)
|
||||
|
||||
outerCondition = "!ignoreNamedProps"
|
||||
if self.descriptor.supportsIndexedProperties():
|
||||
condition = "!IsArrayIndex(index) && " + condition
|
||||
namedGet = (CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
|
||||
condition).define() +
|
||||
"\n")
|
||||
outerCondition = "!IsArrayIndex(index) && " + outerCondition
|
||||
|
||||
namedGet = fill("""
|
||||
bool callNamedGetter = false;
|
||||
if (${outerCondition}) {
|
||||
$*{computeCondition}
|
||||
}
|
||||
if (callNamedGetter) {
|
||||
$*{namedGetCode}
|
||||
}
|
||||
""",
|
||||
outerCondition=outerCondition,
|
||||
computeCondition=computeCondition,
|
||||
namedGetCode=CGProxyNamedGetter(self.descriptor, templateValues).define())
|
||||
namedGet += "\n"
|
||||
else:
|
||||
namedGet = ""
|
||||
|
||||
@ -10345,8 +10371,16 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
||||
""",
|
||||
namedBody=namedBody)
|
||||
if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
delete = CGIfWrapper(CGGeneric(delete),
|
||||
"!HasPropertyOnPrototype(cx, proxy, id)").define()
|
||||
delete = fill("""
|
||||
bool hasOnProto;
|
||||
if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
|
||||
return false;
|
||||
}
|
||||
if (!hasOnProto) {
|
||||
$*{delete}
|
||||
}
|
||||
""",
|
||||
delete=delete)
|
||||
|
||||
delete += dedent("""
|
||||
|
||||
@ -10485,8 +10519,17 @@ class CGDOMJSProxyHandler_hasOwn(ClassMethod):
|
||||
""",
|
||||
presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
|
||||
if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
named = CGIfWrapper(CGGeneric(named + "return true;\n"),
|
||||
"!HasPropertyOnPrototype(cx, proxy, id)").define()
|
||||
named = fill("""
|
||||
bool hasOnProto;
|
||||
if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
|
||||
return false;
|
||||
}
|
||||
if (!hasOnProto) {
|
||||
$*{protoLacksProperty}
|
||||
return true;
|
||||
}
|
||||
""",
|
||||
protoLacksProperty=named)
|
||||
named += "*bp = false;\n"
|
||||
else:
|
||||
named += "\n"
|
||||
@ -10593,7 +10636,7 @@ class CGDOMJSProxyHandler_get(ClassMethod):
|
||||
|
||||
getOnPrototype = dedent("""
|
||||
bool foundOnPrototype;
|
||||
if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp.address())) {
|
||||
if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -146,15 +146,22 @@ static const double THRESHOLD_LOW_PLAYBACKRATE_AUDIO = 0.5;
|
||||
// start playing afterward, so we need to stay alive.
|
||||
// 4) If autoplay could start playback in this element (if we got enough data),
|
||||
// then we need to stay alive.
|
||||
// 5) if the element is currently loading and not suspended,
|
||||
// script might be waiting for progress events or a 'suspend' event,
|
||||
// so we need to stay alive. If we're already suspended then (all other
|
||||
// conditions being met) it's OK to just disappear without firing any more
|
||||
// events, since we have the freedom to remain suspended indefinitely. Note
|
||||
// 5) if the element is currently loading, not suspended, and its source is
|
||||
// not a MediaSource, then script might be waiting for progress events or a
|
||||
// 'stalled' or 'suspend' event, so we need to stay alive.
|
||||
// If we're already suspended then (all other conditions being met),
|
||||
// it's OK to just disappear without firing any more events,
|
||||
// since we have the freedom to remain suspended indefinitely. Note
|
||||
// that we could use this 'suspended' loophole to garbage-collect a suspended
|
||||
// element in case 4 even if it had 'autoplay' set, but we choose not to.
|
||||
// If someone throws away all references to a loading 'autoplay' element
|
||||
// sound should still eventually play.
|
||||
// 6) If the source is a MediaSource, most loading events will not fire unless
|
||||
// appendBuffer() is called on a SourceBuffer, in which case something is
|
||||
// already referencing the SourceBuffer, which keeps the associated media
|
||||
// element alive. Further, a MediaSource will never time out the resource
|
||||
// fetch, and so should not keep the media element alive if it is
|
||||
// unreferenced. A pending 'stalled' event keeps the media element alive.
|
||||
//
|
||||
// Media elements owned by inactive documents (i.e. documents not contained in any
|
||||
// document viewer) should never hold a self-reference because none of the
|
||||
@ -684,7 +691,7 @@ void HTMLMediaElement::AbortExistingLoads()
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
|
||||
}
|
||||
|
||||
// We may have changed mPaused, mAutoplaying, mNetworkState and other
|
||||
// We may have changed mPaused, mAutoplaying, and other
|
||||
// things which can affect AddRemoveSelfReference
|
||||
AddRemoveSelfReference();
|
||||
|
||||
@ -699,7 +706,6 @@ void HTMLMediaElement::NoSupportedMediaSourceError()
|
||||
mError = new MediaError(this, nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("error"));
|
||||
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
|
||||
ChangeDelayLoadStatus(false);
|
||||
}
|
||||
|
||||
@ -814,7 +820,6 @@ void HTMLMediaElement::SelectResource()
|
||||
// The media element has neither a src attribute nor any source
|
||||
// element children, abort the load.
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
|
||||
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
|
||||
ChangeDelayLoadStatus(false);
|
||||
return;
|
||||
}
|
||||
@ -822,8 +827,6 @@ void HTMLMediaElement::SelectResource()
|
||||
ChangeDelayLoadStatus(true);
|
||||
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
|
||||
// Load event was delayed, and still is, so no need to call
|
||||
// AddRemoveSelfReference, since it must still be held
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
|
||||
|
||||
// Delay setting mIsRunningSeletResource until after UpdatePreloadAction
|
||||
@ -2133,7 +2136,6 @@ HTMLMediaElement::ResetConnectionState()
|
||||
FireTimeUpdate(false);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
|
||||
AddRemoveSelfReference();
|
||||
ChangeDelayLoadStatus(false);
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
|
||||
}
|
||||
@ -2858,7 +2860,6 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
|
||||
AddRemoveSelfReference();
|
||||
// FirstFrameLoaded() will be called when the stream has current data.
|
||||
}
|
||||
|
||||
@ -3010,7 +3011,6 @@ void HTMLMediaElement::Error(uint16_t aErrorCode)
|
||||
} else {
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
|
||||
}
|
||||
AddRemoveSelfReference();
|
||||
ChangeDelayLoadStatus(false);
|
||||
}
|
||||
|
||||
@ -3084,7 +3084,6 @@ void HTMLMediaElement::DownloadSuspended()
|
||||
}
|
||||
if (mBegun) {
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
|
||||
AddRemoveSelfReference();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3092,7 +3091,6 @@ void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading)
|
||||
{
|
||||
if (mBegun || aForceNetworkLoading) {
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
|
||||
AddRemoveSelfReference();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3145,6 +3143,8 @@ void HTMLMediaElement::CheckProgress(bool aHaveNewProgress)
|
||||
// is more progress.
|
||||
StopProgress();
|
||||
}
|
||||
|
||||
AddRemoveSelfReference();
|
||||
}
|
||||
|
||||
/* static */
|
||||
@ -3358,6 +3358,9 @@ void HTMLMediaElement::ChangeNetworkState(nsMediaNetworkState aState)
|
||||
// Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
|
||||
}
|
||||
|
||||
// Changing mNetworkState affects AddRemoveSelfReference().
|
||||
AddRemoveSelfReference();
|
||||
}
|
||||
|
||||
bool HTMLMediaElement::CanActivateAutoplay()
|
||||
@ -3628,7 +3631,8 @@ void HTMLMediaElement::AddRemoveSelfReference()
|
||||
(!mPaused && mSrcStream && !mSrcStream->IsFinished()) ||
|
||||
(mDecoder && mDecoder->IsSeeking()) ||
|
||||
CanActivateAutoplay() ||
|
||||
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
|
||||
(mMediaSource ? mProgressTimer :
|
||||
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING));
|
||||
|
||||
if (needSelfReference != mHasSelfReference) {
|
||||
mHasSelfReference = needSelfReference;
|
||||
|
@ -168,16 +168,7 @@ IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo)
|
||||
MOZ_ASSERT(aLineNo);
|
||||
|
||||
ThreadsafeAutoJSContext cx;
|
||||
|
||||
const char* filename = nullptr;
|
||||
uint32_t lineNo = 0;
|
||||
if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
|
||||
*aLineNo = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
aFilename.Assign(NS_ConvertUTF8toUTF16(filename));
|
||||
*aLineNo = lineNo;
|
||||
nsJSUtils::GetCallingLocation(cx, aFilename, aLineNo);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "mozilla/dom/VideoStreamTrack.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsProxyRelease.h"
|
||||
@ -545,6 +546,33 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
bool Check3gppPermission()
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
doc->NodePrincipal()->GetAppStatus(&appStatus);
|
||||
|
||||
// Certified applications can always assign AUDIO_3GPP
|
||||
if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> pm =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
|
||||
if (!pm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t perm = nsIPermissionManager::DENY_ACTION;
|
||||
pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), "audio-capture:3gpp", &perm);
|
||||
return perm == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
void InitEncoder(uint8_t aTrackTypes)
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("Session.InitEncoder %p", this));
|
||||
@ -553,14 +581,8 @@ private:
|
||||
// Allocate encoder and bind with union stream.
|
||||
// At this stage, the API doesn't allow UA to choose the output mimeType format.
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
|
||||
uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
if (doc) {
|
||||
doc->NodePrincipal()->GetAppStatus(&appStatus);
|
||||
}
|
||||
// Only allow certificated application can assign AUDIO_3GPP
|
||||
if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
|
||||
mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP)) {
|
||||
// Make sure the application has permission to assign AUDIO_3GPP
|
||||
if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && Check3gppPermission()) {
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP), aTrackTypes);
|
||||
} else {
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
|
||||
|
@ -148,6 +148,8 @@ private:
|
||||
// Register MediaRecorder into Document to listen the activity changes.
|
||||
void RegisterActivityObserver();
|
||||
void UnRegisterActivityObserver();
|
||||
|
||||
bool Check3gppPermission();
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -312,9 +312,12 @@ MediaSource::Attach(MediaSourceDecoder* aDecoder)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("MediaSource(%p)::Attach(aDecoder=%p) owner=%p", this, aDecoder, aDecoder->GetOwner());
|
||||
MOZ_ASSERT(aDecoder);
|
||||
MOZ_ASSERT(aDecoder->GetOwner());
|
||||
if (mReadyState != MediaSourceReadyState::Closed) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(!mMediaElement);
|
||||
mMediaElement = aDecoder->GetOwner()->GetMediaElement();
|
||||
MOZ_ASSERT(!mDecoder);
|
||||
mDecoder = aDecoder;
|
||||
mDecoder->AttachMediaSource(this);
|
||||
@ -335,6 +338,7 @@ MediaSource::Detach()
|
||||
}
|
||||
mDecoder->DetachMediaSource();
|
||||
mDecoder = nullptr;
|
||||
mMediaElement = nullptr;
|
||||
mFirstSourceBufferInitialized = false;
|
||||
SetReadyState(MediaSourceReadyState::Closed);
|
||||
if (mActiveSourceBuffers) {
|
||||
@ -487,6 +491,7 @@ MediaSource::WrapObject(JSContext* aCx)
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaSource, DOMEventTargetHelper,
|
||||
mMediaElement,
|
||||
mSourceBuffers, mActiveSourceBuffers)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MediaSource, DOMEventTargetHelper)
|
||||
|
@ -128,6 +128,9 @@ private:
|
||||
nsRefPtr<SourceBufferList> mActiveSourceBuffers;
|
||||
|
||||
nsRefPtr<MediaSourceDecoder> mDecoder;
|
||||
// Ensures the media element remains alive to dispatch progress and
|
||||
// durationchanged events.
|
||||
nsRefPtr<HTMLMediaElement> mMediaElement;
|
||||
|
||||
nsRefPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
|
230
dom/media/tests/mochitest/dataChannel.js
Normal file
230
dom/media/tests/mochitest/dataChannel.js
Normal file
@ -0,0 +1,230 @@
|
||||
/* 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/. */
|
||||
|
||||
function addInitialDataChannel(chain) {
|
||||
chain.insertBefore('PC_LOCAL_CREATE_OFFER', [
|
||||
['PC_LOCAL_CREATE_DATA_CHANNEL',
|
||||
function (test) {
|
||||
var channel = test.pcLocal.createDataChannel({});
|
||||
|
||||
is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
|
||||
is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
|
||||
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
"Create datachannel does not change signaling state");
|
||||
|
||||
test.next();
|
||||
}
|
||||
]
|
||||
]);
|
||||
chain.insertAfter('PC_REMOTE_CREATE_ANSWER', [
|
||||
[
|
||||
'PC_LOCAL_SETUP_DATA_CHANNEL_CALLBACK',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcLocal, function () {
|
||||
ok(true, test.pcLocal + " dataChannels[0] switched to 'open'");
|
||||
},
|
||||
// At this point a timeout failure will be of no value
|
||||
null);
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SETUP_DATA_CHANNEL_CALLBACK',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcRemote, function () {
|
||||
ok(true, test.pcRemote + " dataChannels[0] switched to 'open'");
|
||||
},
|
||||
// At this point a timeout failure will be of no value
|
||||
null);
|
||||
test.next();
|
||||
}
|
||||
]
|
||||
]);
|
||||
chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS', [
|
||||
[
|
||||
'PC_LOCAL_VERIFY_DATA_CHANNEL_STATE',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcLocal, function() {
|
||||
test.next();
|
||||
}, function() {
|
||||
ok(false, test.pcLocal + " initial dataChannels[0] failed to switch to 'open'");
|
||||
//TODO: use stopAndExit() once bug 1019323 has landed
|
||||
unexpectedEventAndFinish(this, 'timeout')
|
||||
// to prevent test framework timeouts
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_VERIFY_DATA_CHANNEL_STATE',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcRemote, function() {
|
||||
test.next();
|
||||
}, function() {
|
||||
ok(false, test.pcRemote + " initial dataChannels[0] failed to switch to 'open'");
|
||||
//TODO: use stopAndExit() once bug 1019323 has landed
|
||||
unexpectedEventAndFinish(this, 'timeout');
|
||||
// to prevent test framework timeouts
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
]
|
||||
]);
|
||||
chain.removeAfter('PC_REMOTE_CHECK_ICE_CONNECTIONS');
|
||||
chain.append([
|
||||
[
|
||||
'SEND_MESSAGE',
|
||||
function (test) {
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(data, message, "Message correctly transmitted from pcLocal to pcRemote.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_BLOB',
|
||||
function (test) {
|
||||
var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
|
||||
var blob = new Blob(contents, { "type" : "text/plain" });
|
||||
|
||||
test.send(blob, function (channel, data) {
|
||||
ok(data instanceof Blob, "Received data is of instance Blob");
|
||||
is(data.size, blob.size, "Received data has the correct size.");
|
||||
|
||||
getBlobContent(data, function (recv_contents) {
|
||||
is(recv_contents, contents, "Received data has the correct content.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'CREATE_SECOND_DATA_CHANNEL',
|
||||
function (test) {
|
||||
test.createDataChannel({ }, function (sourceChannel, targetChannel) {
|
||||
is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
|
||||
is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
|
||||
|
||||
is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
|
||||
is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL',
|
||||
function (test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(channels.indexOf(channel), channels.length - 1, "Last channel used");
|
||||
is(data, message, "Received message has the correct content.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_THROUGH_FIRST_CHANNEL',
|
||||
function (test) {
|
||||
var message = "Message through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcLocal.dataChannels[0],
|
||||
targetChannel: test.pcRemote.dataChannels[0]
|
||||
};
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(test.pcRemote.dataChannels.indexOf(channel), 0, "1st channel used");
|
||||
is(data, message, "Received message has the correct content.");
|
||||
|
||||
test.next();
|
||||
}, options);
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL',
|
||||
function (test) {
|
||||
var message = "Return a message also through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcRemote.dataChannels[0],
|
||||
targetChannel: test.pcLocal.dataChannels[0]
|
||||
};
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(test.pcLocal.dataChannels.indexOf(channel), 0, "1st channel used");
|
||||
is(data, message, "Return message has the correct content.");
|
||||
|
||||
test.next();
|
||||
}, options);
|
||||
}
|
||||
],
|
||||
[
|
||||
'CREATE_NEGOTIATED_DATA_CHANNEL',
|
||||
function (test) {
|
||||
var options = {negotiated:true, id: 5, protocol:"foo/bar", ordered:false,
|
||||
maxRetransmits:500};
|
||||
test.createDataChannel(options, function (sourceChannel2, targetChannel2) {
|
||||
is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
|
||||
is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
|
||||
|
||||
is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
|
||||
is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
|
||||
|
||||
if (options.id != undefined) {
|
||||
is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
|
||||
}
|
||||
else {
|
||||
options.id = sourceChannel2.id;
|
||||
}
|
||||
var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
|
||||
is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
|
||||
is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
|
||||
is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
|
||||
sourceChannel2.maxRetransmits);
|
||||
is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
|
||||
sourceChannel2.maxRetransmitTime);
|
||||
*/
|
||||
|
||||
is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
|
||||
is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
|
||||
is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
|
||||
is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
|
||||
targetChannel2.maxRetransmits);
|
||||
is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
|
||||
targetChannel2.maxRetransmitTime);
|
||||
*/
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2',
|
||||
function (test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(channels.indexOf(channel), channels.length - 1, "Last channel used");
|
||||
is(data, message, "Received message has the correct content.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
]
|
||||
]);
|
||||
}
|
@ -4,6 +4,7 @@ skip-if = (os == 'win' && strictContentSandbox) || android_version == '10'
|
||||
support-files =
|
||||
head.js
|
||||
constraints.js
|
||||
dataChannel.js
|
||||
mediaStreamPlayback.js
|
||||
nonTrickleIce.js
|
||||
pc.js
|
||||
|
@ -584,7 +584,7 @@ function PeerConnectionTest(options) {
|
||||
* @param {Function} onSuccess
|
||||
* Callback to execute when the peer connection has been closed successfully
|
||||
*/
|
||||
PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
|
||||
PeerConnectionTest.prototype.closePC = function PCT_closePC(onSuccess) {
|
||||
info("Closing peer connections");
|
||||
|
||||
var self = this;
|
||||
@ -655,6 +655,316 @@ PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
|
||||
closeEverything();
|
||||
};
|
||||
|
||||
/**
|
||||
* Close the open data channels, followed by the underlying peer connection
|
||||
*
|
||||
* @param {Function} onSuccess
|
||||
* Callback to execute when all connections have been closed
|
||||
*/
|
||||
PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
|
||||
var self = this;
|
||||
var pendingDcClose = []
|
||||
var closeTimeout = null;
|
||||
|
||||
info("PeerConnectionTest.close() called");
|
||||
|
||||
function _closePeerConnection() {
|
||||
info("Now closing PeerConnection");
|
||||
self.closePC.call(self, onSuccess);
|
||||
}
|
||||
|
||||
function _closePeerConnectionCallback(index) {
|
||||
info("_closePeerConnection called with index " + index);
|
||||
var pos = pendingDcClose.indexOf(index);
|
||||
if (pos != -1) {
|
||||
pendingDcClose.splice(pos, 1);
|
||||
}
|
||||
else {
|
||||
info("_closePeerConnection index " + index + " is missing from pendingDcClose: " + pendingDcClose);
|
||||
}
|
||||
if (pendingDcClose.length === 0) {
|
||||
clearTimeout(closeTimeout);
|
||||
_closePeerConnection();
|
||||
}
|
||||
}
|
||||
|
||||
var myDataChannels = null;
|
||||
if (self.pcLocal) {
|
||||
myDataChannels = self.pcLocal.dataChannels;
|
||||
}
|
||||
else if (self.pcRemote) {
|
||||
myDataChannels = self.pcRemote.dataChannels;
|
||||
}
|
||||
var length = myDataChannels.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
var dataChannel = myDataChannels[i];
|
||||
if (dataChannel.readyState !== "closed") {
|
||||
pendingDcClose.push(i);
|
||||
self.closeDataChannels(i, _closePeerConnectionCallback);
|
||||
}
|
||||
}
|
||||
if (pendingDcClose.length === 0) {
|
||||
_closePeerConnection();
|
||||
}
|
||||
else {
|
||||
closeTimeout = setTimeout(function() {
|
||||
ok(false, "Failed to properly close data channels: " +
|
||||
pendingDcClose);
|
||||
_closePeerConnection();
|
||||
}, 60000);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Close the specified data channels
|
||||
*
|
||||
* @param {Number} index
|
||||
* Index of the data channels to close on both sides
|
||||
* @param {Function} onSuccess
|
||||
* Callback to execute when the data channels has been closed
|
||||
*/
|
||||
PeerConnectionTest.prototype.closeDataChannels = function PCT_closeDataChannels(index, onSuccess) {
|
||||
info("closeDataChannels called with index: " + index);
|
||||
var localChannel = null;
|
||||
if (this.pcLocal) {
|
||||
localChannel = this.pcLocal.dataChannels[index];
|
||||
}
|
||||
var remoteChannel = null;
|
||||
if (this.pcRemote) {
|
||||
remoteChannel = this.pcRemote.dataChannels[index];
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var wait = false;
|
||||
var pollingMode = false;
|
||||
var everythingClosed = false;
|
||||
var verifyInterval = null;
|
||||
var remoteCloseTimer = null;
|
||||
|
||||
function _allChannelsAreClosed() {
|
||||
var ret = null;
|
||||
if (localChannel) {
|
||||
ret = (localChannel.readyState === "closed");
|
||||
}
|
||||
if (remoteChannel) {
|
||||
if (ret !== null) {
|
||||
ret = (ret && (remoteChannel.readyState === "closed"));
|
||||
}
|
||||
else {
|
||||
ret = (remoteChannel.readyState === "closed");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function verifyClosedChannels() {
|
||||
if (everythingClosed) {
|
||||
// safety protection against events firing late
|
||||
return;
|
||||
}
|
||||
if (_allChannelsAreClosed()) {
|
||||
ok(true, "DataChannel(s) have reached 'closed' state for data channel " + index);
|
||||
if (remoteCloseTimer !== null) {
|
||||
clearTimeout(remoteCloseTimer);
|
||||
}
|
||||
if (verifyInterval !== null) {
|
||||
clearInterval(verifyInterval);
|
||||
}
|
||||
everythingClosed = true;
|
||||
onSuccess(index);
|
||||
}
|
||||
else {
|
||||
info("Still waiting for DataChannel closure");
|
||||
}
|
||||
}
|
||||
|
||||
if ((localChannel) && (localChannel.readyState !== "closed")) {
|
||||
// in case of steeplechase there is no far end, so we can only poll
|
||||
if (remoteChannel) {
|
||||
remoteChannel.onclose = function () {
|
||||
is(remoteChannel.readyState, "closed", "remoteChannel is in state 'closed'");
|
||||
verifyClosedChannels();
|
||||
};
|
||||
}
|
||||
else {
|
||||
pollingMode = true;
|
||||
verifyInterval = setInterval(verifyClosedChannels, 1000);
|
||||
}
|
||||
|
||||
localChannel.close();
|
||||
wait = true;
|
||||
}
|
||||
if ((remoteChannel) && (remoteChannel.readyState !== "closed")) {
|
||||
if (localChannel) {
|
||||
localChannel.onclose = function () {
|
||||
is(localChannel.readyState, "closed", "localChannel is in state 'closed'");
|
||||
verifyClosedChannels();
|
||||
};
|
||||
|
||||
// Apparently we are running a local test which has both ends of the
|
||||
// data channel locally available, so by default lets wait for the
|
||||
// remoteChannel.onclose handler from above to confirm closure on both
|
||||
// ends.
|
||||
remoteCloseTimer = setTimeout(function() {
|
||||
todo(false, "localChannel.close() did not resulted in close signal on remote side");
|
||||
remoteChannel.close();
|
||||
verifyClosedChannels();
|
||||
}, 30000);
|
||||
}
|
||||
else {
|
||||
pollingMode = true;
|
||||
verifyTimer = setInterval(verifyClosedChannels, 1000);
|
||||
|
||||
remoteChannel.close();
|
||||
}
|
||||
|
||||
wait = true;
|
||||
}
|
||||
|
||||
if (!wait) {
|
||||
onSuccess(index);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wait for the initial data channel to get into the open state
|
||||
*
|
||||
* @param {PeerConnectionWrapper} peer
|
||||
* The peer connection wrapper to run the command on
|
||||
* @param {Function} onSuccess
|
||||
* Callback when the creation was successful
|
||||
*/
|
||||
PeerConnectionTest.prototype.waitForInitialDataChannel =
|
||||
function PCT_waitForInitialDataChannel(peer, onSuccess, onFailure) {
|
||||
var dcConnectionTimeout = null;
|
||||
var dcOpened = false;
|
||||
|
||||
function dataChannelConnected(channel) {
|
||||
// in case the switch statement below had called onSuccess already we
|
||||
// don't want to call it again
|
||||
if (!dcOpened) {
|
||||
clearTimeout(dcConnectionTimeout);
|
||||
is(channel.readyState, "open", peer + " dataChannels[0] switched to state: 'open'");
|
||||
dcOpened = true;
|
||||
onSuccess();
|
||||
} else {
|
||||
info("dataChannelConnected() called, but data channel was open already");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: drno: convert dataChannels into an object and make
|
||||
// registerDataChannelOpenEvent a generic function
|
||||
if (peer == this.pcLocal) {
|
||||
peer.dataChannels[0].onopen = dataChannelConnected;
|
||||
} else {
|
||||
peer.registerDataChannelOpenEvents(dataChannelConnected);
|
||||
}
|
||||
|
||||
if (peer.dataChannels.length >= 1) {
|
||||
// snapshot of the live value as it might change during test execution
|
||||
const readyState = peer.dataChannels[0].readyState;
|
||||
switch (readyState) {
|
||||
case "open": {
|
||||
is(readyState, "open", peer + " dataChannels[0] is already in state: 'open'");
|
||||
dcOpened = true;
|
||||
onSuccess();
|
||||
break;
|
||||
}
|
||||
case "connecting": {
|
||||
is(readyState, "connecting", peer + " dataChannels[0] is in state: 'connecting'");
|
||||
if (onFailure) {
|
||||
dcConnectionTimeout = setTimeout(function () {
|
||||
is(peer.dataChannels[0].readyState, "open", peer + " timed out while waiting for dataChannels[0] to open");
|
||||
onFailure();
|
||||
}, 60000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ok(false, "dataChannels[0] is in unexpected state " + readyState);
|
||||
if (onFailure) {
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send data (message or blob) to the other peer
|
||||
*
|
||||
* @param {String|Blob} data
|
||||
* Data to send to the other peer. For Blobs the MIME type will be lost.
|
||||
* @param {Function} onSuccess
|
||||
* Callback to execute when data has been sent
|
||||
* @param {Object} [options={ }]
|
||||
* Options to specify the data channels to be used
|
||||
* @param {DataChannelWrapper} [options.sourceChannel=pcLocal.dataChannels[length - 1]]
|
||||
* Data channel to use for sending the message
|
||||
* @param {DataChannelWrapper} [options.targetChannel=pcRemote.dataChannels[length - 1]]
|
||||
* Data channel to use for receiving the message
|
||||
*/
|
||||
PeerConnectionTest.prototype.send = function PCT_send(data, onSuccess, options) {
|
||||
options = options || { };
|
||||
var source = options.sourceChannel ||
|
||||
this.pcLocal.dataChannels[this.pcLocal.dataChannels.length - 1];
|
||||
var target = options.targetChannel ||
|
||||
this.pcRemote.dataChannels[this.pcRemote.dataChannels.length - 1];
|
||||
|
||||
// Register event handler for the target channel
|
||||
target.onmessage = function (recv_data) {
|
||||
onSuccess(target, recv_data);
|
||||
};
|
||||
|
||||
source.send(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a data channel
|
||||
*
|
||||
* @param {Dict} options
|
||||
* Options for the data channel (see nsIPeerConnection)
|
||||
* @param {Function} onSuccess
|
||||
* Callback when the creation was successful
|
||||
*/
|
||||
PeerConnectionTest.prototype.createDataChannel = function DCT_createDataChannel(options, onSuccess) {
|
||||
var localChannel = null;
|
||||
var remoteChannel = null;
|
||||
var self = this;
|
||||
|
||||
// Method to synchronize all asynchronous events.
|
||||
function check_next_test() {
|
||||
if (localChannel && remoteChannel) {
|
||||
onSuccess(localChannel, remoteChannel);
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.negotiated) {
|
||||
// Register handlers for the remote peer
|
||||
this.pcRemote.registerDataChannelOpenEvents(function (channel) {
|
||||
remoteChannel = channel;
|
||||
check_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
// Create the datachannel and handle the local 'onopen' event
|
||||
this.pcLocal.createDataChannel(options, function (channel) {
|
||||
localChannel = channel;
|
||||
|
||||
if (options.negotiated) {
|
||||
// externally negotiated - we need to open from both ends
|
||||
options.id = options.id || channel.id; // allow for no id to let the impl choose
|
||||
self.pcRemote.createDataChannel(options, function (channel) {
|
||||
remoteChannel = channel;
|
||||
check_next_test();
|
||||
});
|
||||
} else {
|
||||
check_next_test();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes the next command.
|
||||
*/
|
||||
@ -995,372 +1305,6 @@ PCT_getSignalingMessage(messageType, onMessage) {
|
||||
this.registerSignalingCallback(messageType, onMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class handles tests for data channels.
|
||||
*
|
||||
* @constructor
|
||||
* @param {object} [options={}]
|
||||
* Optional options for the peer connection test
|
||||
* @param {object} [options.commands=commandsDataChannel]
|
||||
* Commands to run for the test
|
||||
* @param {object} [options.config_local=undefined]
|
||||
* Configuration for the local peer connection instance
|
||||
* @param {object} [options.config_remote=undefined]
|
||||
* Configuration for the remote peer connection instance. If not defined
|
||||
* the configuration from the local instance will be used
|
||||
*/
|
||||
function DataChannelTest(options) {
|
||||
options = options || { };
|
||||
options.commands = options.commands || commandsDataChannel;
|
||||
|
||||
PeerConnectionTest.call(this, options);
|
||||
}
|
||||
|
||||
DataChannelTest.prototype = Object.create(PeerConnectionTest.prototype, {
|
||||
close : {
|
||||
/**
|
||||
* Close the open data channels, followed by the underlying peer connection
|
||||
*
|
||||
* @param {Function} onSuccess
|
||||
* Callback to execute when all connections have been closed
|
||||
*/
|
||||
value : function DCT_close(onSuccess) {
|
||||
var self = this;
|
||||
var pendingDcClose = []
|
||||
var closeTimeout = null;
|
||||
|
||||
info("DataChannelTest.close() called");
|
||||
|
||||
function _closePeerConnection() {
|
||||
info("DataChannelTest closing PeerConnection");
|
||||
PeerConnectionTest.prototype.close.call(self, onSuccess);
|
||||
}
|
||||
|
||||
function _closePeerConnectionCallback(index) {
|
||||
info("_closePeerConnection called with index " + index);
|
||||
var pos = pendingDcClose.indexOf(index);
|
||||
if (pos != -1) {
|
||||
pendingDcClose.splice(pos, 1);
|
||||
}
|
||||
else {
|
||||
info("_closePeerConnection index " + index + " is missing from pendingDcClose: " + pendingDcClose);
|
||||
}
|
||||
if (pendingDcClose.length === 0) {
|
||||
clearTimeout(closeTimeout);
|
||||
_closePeerConnection();
|
||||
}
|
||||
}
|
||||
|
||||
var myDataChannels = null;
|
||||
if (self.pcLocal) {
|
||||
myDataChannels = self.pcLocal.dataChannels;
|
||||
}
|
||||
else if (self.pcRemote) {
|
||||
myDataChannels = self.pcRemote.dataChannels;
|
||||
}
|
||||
var length = myDataChannels.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
var dataChannel = myDataChannels[i];
|
||||
if (dataChannel.readyState !== "closed") {
|
||||
pendingDcClose.push(i);
|
||||
self.closeDataChannels(i, _closePeerConnectionCallback);
|
||||
}
|
||||
}
|
||||
if (pendingDcClose.length === 0) {
|
||||
_closePeerConnection();
|
||||
}
|
||||
else {
|
||||
closeTimeout = setTimeout(function() {
|
||||
ok(false, "Failed to properly close data channels: " +
|
||||
pendingDcClose);
|
||||
_closePeerConnection();
|
||||
}, 60000);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
closeDataChannels : {
|
||||
/**
|
||||
* Close the specified data channels
|
||||
*
|
||||
* @param {Number} index
|
||||
* Index of the data channels to close on both sides
|
||||
* @param {Function} onSuccess
|
||||
* Callback to execute when the data channels has been closed
|
||||
*/
|
||||
value : function DCT_closeDataChannels(index, onSuccess) {
|
||||
info("_closeDataChannels called with index: " + index);
|
||||
var localChannel = null;
|
||||
if (this.pcLocal) {
|
||||
localChannel = this.pcLocal.dataChannels[index];
|
||||
}
|
||||
var remoteChannel = null;
|
||||
if (this.pcRemote) {
|
||||
remoteChannel = this.pcRemote.dataChannels[index];
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var wait = false;
|
||||
var pollingMode = false;
|
||||
var everythingClosed = false;
|
||||
var verifyInterval = null;
|
||||
var remoteCloseTimer = null;
|
||||
|
||||
function _allChannelsAreClosed() {
|
||||
var ret = null;
|
||||
if (localChannel) {
|
||||
ret = (localChannel.readyState === "closed");
|
||||
}
|
||||
if (remoteChannel) {
|
||||
if (ret !== null) {
|
||||
ret = (ret && (remoteChannel.readyState === "closed"));
|
||||
}
|
||||
else {
|
||||
ret = (remoteChannel.readyState === "closed");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function verifyClosedChannels() {
|
||||
if (everythingClosed) {
|
||||
// safety protection against events firing late
|
||||
return;
|
||||
}
|
||||
if (_allChannelsAreClosed) {
|
||||
ok(true, "DataChannel(s) have reached 'closed' state for data channel " + index);
|
||||
if (remoteCloseTimer !== null) {
|
||||
clearTimeout(remoteCloseTimer);
|
||||
}
|
||||
if (verifyInterval !== null) {
|
||||
clearInterval(verifyInterval);
|
||||
}
|
||||
everythingClosed = true;
|
||||
onSuccess(index);
|
||||
}
|
||||
else {
|
||||
info("Still waiting for DataChannel closure");
|
||||
}
|
||||
}
|
||||
|
||||
if ((localChannel) && (localChannel.readyState !== "closed")) {
|
||||
// in case of steeplechase there is no far end, so we can only poll
|
||||
if (remoteChannel) {
|
||||
remoteChannel.onclose = function () {
|
||||
is(remoteChannel.readyState, "closed", "remoteChannel is in state 'closed'");
|
||||
verifyClosedChannels();
|
||||
};
|
||||
}
|
||||
else {
|
||||
pollingMode = true;
|
||||
verifyInterval = setInterval(verifyClosedChannels, 1000);
|
||||
}
|
||||
|
||||
localChannel.close();
|
||||
wait = true;
|
||||
}
|
||||
if ((remoteChannel) && (remoteChannel.readyState !== "closed")) {
|
||||
if (localChannel) {
|
||||
localChannel.onclose = function () {
|
||||
is(localChannel.readyState, "closed", "localChannel is in state 'closed'");
|
||||
verifyClosedChannels();
|
||||
};
|
||||
|
||||
// Apparently we are running a local test which has both ends of the
|
||||
// data channel locally available, so by default lets wait for the
|
||||
// remoteChannel.onclose handler from above to confirm closure on both
|
||||
// ends.
|
||||
remoteCloseTimer = setTimeout(function() {
|
||||
todo(false, "localChannel.close() did not resulted in close signal on remote side");
|
||||
remoteChannel.close();
|
||||
verifyClosedChannels();
|
||||
}, 30000);
|
||||
}
|
||||
else {
|
||||
pollingMode = true;
|
||||
verifyTimer = setInterval(verifyClosedChannels, 1000);
|
||||
|
||||
remoteChannel.close();
|
||||
}
|
||||
|
||||
wait = true;
|
||||
}
|
||||
|
||||
if (!wait) {
|
||||
onSuccess(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
createDataChannel : {
|
||||
/**
|
||||
* Create a data channel
|
||||
*
|
||||
* @param {Dict} options
|
||||
* Options for the data channel (see nsIPeerConnection)
|
||||
* @param {Function} onSuccess
|
||||
* Callback when the creation was successful
|
||||
*/
|
||||
value : function DCT_createDataChannel(options, onSuccess) {
|
||||
var localChannel = null;
|
||||
var remoteChannel = null;
|
||||
var self = this;
|
||||
|
||||
// Method to synchronize all asynchronous events.
|
||||
function check_next_test() {
|
||||
if (localChannel && remoteChannel) {
|
||||
onSuccess(localChannel, remoteChannel);
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.negotiated) {
|
||||
// Register handlers for the remote peer
|
||||
this.pcRemote.registerDataChannelOpenEvents(function (channel) {
|
||||
remoteChannel = channel;
|
||||
check_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
// Create the datachannel and handle the local 'onopen' event
|
||||
this.pcLocal.createDataChannel(options, function (channel) {
|
||||
localChannel = channel;
|
||||
|
||||
if (options.negotiated) {
|
||||
// externally negotiated - we need to open from both ends
|
||||
options.id = options.id || channel.id; // allow for no id to let the impl choose
|
||||
self.pcRemote.createDataChannel(options, function (channel) {
|
||||
remoteChannel = channel;
|
||||
check_next_test();
|
||||
});
|
||||
} else {
|
||||
check_next_test();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
send : {
|
||||
/**
|
||||
* Send data (message or blob) to the other peer
|
||||
*
|
||||
* @param {String|Blob} data
|
||||
* Data to send to the other peer. For Blobs the MIME type will be lost.
|
||||
* @param {Function} onSuccess
|
||||
* Callback to execute when data has been sent
|
||||
* @param {Object} [options={ }]
|
||||
* Options to specify the data channels to be used
|
||||
* @param {DataChannelWrapper} [options.sourceChannel=pcLocal.dataChannels[length - 1]]
|
||||
* Data channel to use for sending the message
|
||||
* @param {DataChannelWrapper} [options.targetChannel=pcRemote.dataChannels[length - 1]]
|
||||
* Data channel to use for receiving the message
|
||||
*/
|
||||
value : function DCT_send(data, onSuccess, options) {
|
||||
options = options || { };
|
||||
var source = options.sourceChannel ||
|
||||
this.pcLocal.dataChannels[this.pcLocal.dataChannels.length - 1];
|
||||
var target = options.targetChannel ||
|
||||
this.pcRemote.dataChannels[this.pcRemote.dataChannels.length - 1];
|
||||
|
||||
// Register event handler for the target channel
|
||||
target.onmessage = function (recv_data) {
|
||||
onSuccess(target, recv_data);
|
||||
};
|
||||
|
||||
source.send(data);
|
||||
}
|
||||
},
|
||||
|
||||
createOffer : {
|
||||
value : function DCT_createOffer(peer, onSuccess) {
|
||||
PeerConnectionTest.prototype.createOffer.call(this, peer, onSuccess);
|
||||
}
|
||||
},
|
||||
|
||||
setLocalDescription : {
|
||||
/**
|
||||
* Sets the local description for the specified peer connection instance
|
||||
* and automatically handles the failure case.
|
||||
*
|
||||
* @param {PeerConnectionWrapper} peer
|
||||
The peer connection wrapper to run the command on
|
||||
* @param {mozRTCSessionDescription} desc
|
||||
* Session description for the local description request
|
||||
* @param {function} onSuccess
|
||||
* Callback to execute if the local description was set successfully
|
||||
*/
|
||||
value : function DCT_setLocalDescription(peer, desc, state, onSuccess) {
|
||||
PeerConnectionTest.prototype.setLocalDescription.call(this, peer,
|
||||
desc, state, onSuccess);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
waitForInitialDataChannel : {
|
||||
/**
|
||||
* Wait for the initial data channel to get into the open state
|
||||
*
|
||||
* @param {PeerConnectionWrapper} peer
|
||||
* The peer connection wrapper to run the command on
|
||||
* @param {Function} onSuccess
|
||||
* Callback when the creation was successful
|
||||
*/
|
||||
value : function DCT_waitForInitialDataChannel(peer, onSuccess, onFailure) {
|
||||
var dcConnectionTimeout = null;
|
||||
var dcOpened = false;
|
||||
|
||||
function dataChannelConnected(channel) {
|
||||
// in case the switch statement below had called onSuccess already we
|
||||
// don't want to call it again
|
||||
if (!dcOpened) {
|
||||
clearTimeout(dcConnectionTimeout);
|
||||
is(channel.readyState, "open", peer + " dataChannels[0] switched to state: 'open'");
|
||||
dcOpened = true;
|
||||
onSuccess();
|
||||
} else {
|
||||
info("dataChannelConnected() called, but data channel was open already");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: drno: convert dataChannels into an object and make
|
||||
// registerDataChannelOpenEvent a generic function
|
||||
if (peer == this.pcLocal) {
|
||||
peer.dataChannels[0].onopen = dataChannelConnected;
|
||||
} else {
|
||||
peer.registerDataChannelOpenEvents(dataChannelConnected);
|
||||
}
|
||||
|
||||
if (peer.dataChannels.length >= 1) {
|
||||
// snapshot of the live value as it might change during test execution
|
||||
const readyState = peer.dataChannels[0].readyState;
|
||||
switch (readyState) {
|
||||
case "open": {
|
||||
is(readyState, "open", peer + " dataChannels[0] is already in state: 'open'");
|
||||
dcOpened = true;
|
||||
onSuccess();
|
||||
break;
|
||||
}
|
||||
case "connecting": {
|
||||
is(readyState, "connecting", peer + " dataChannels[0] is in state: 'connecting'");
|
||||
if (onFailure) {
|
||||
dcConnectionTimeout = setTimeout(function () {
|
||||
is(peer.dataChannels[0].readyState, "open", peer + " timed out while waiting for dataChannels[0] to open");
|
||||
onFailure();
|
||||
}, 60000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ok(false, "dataChannels[0] is in unexpected state " + readyState);
|
||||
if (onFailure) {
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* This class acts as a wrapper around a DataChannel instance.
|
||||
@ -2574,6 +2518,7 @@ PeerConnectionWrapper.prototype = {
|
||||
"Spec and MapClass variant of RTCStatsReport enumeration agree");
|
||||
var nin = numTracks(this._pc.getRemoteStreams());
|
||||
var nout = numTracks(this._pc.getLocalStreams());
|
||||
var ndata = this.dataChannels.length;
|
||||
|
||||
// TODO(Bug 957145): Restore stronger inboundrtp test once Bug 948249 is fixed
|
||||
//is(toNum(counters["inboundrtp"]), nin, "Have " + nin + " inboundrtp stat(s)");
|
||||
@ -2584,7 +2529,7 @@ PeerConnectionWrapper.prototype = {
|
||||
var numLocalCandidates = toNum(counters.localcandidate);
|
||||
var numRemoteCandidates = toNum(counters.remotecandidate);
|
||||
// If there are no tracks, there will be no stats either.
|
||||
if (nin + nout > 0) {
|
||||
if (nin + nout + ndata > 0) {
|
||||
ok(numLocalCandidates, "Have localcandidate stat(s)");
|
||||
ok(numRemoteCandidates, "Have remotecandidate stat(s)");
|
||||
} else {
|
||||
@ -2648,7 +2593,7 @@ PeerConnectionWrapper.prototype = {
|
||||
* The SDP answer to check for SDP bundle support
|
||||
*/
|
||||
checkStatsIceConnections : function PCW_checkStatsIceConnections(stats,
|
||||
offerConstraintsList, offerOptions, numDataTracks, answer) {
|
||||
offerConstraintsList, offerOptions, answer) {
|
||||
var numIceConnections = 0;
|
||||
Object.keys(stats).forEach(function(key) {
|
||||
if ((stats[key].type === "candidatepair") && stats[key].selected) {
|
||||
@ -2669,6 +2614,8 @@ PeerConnectionWrapper.prototype = {
|
||||
this.countVideoTracksInMediaConstraint(offerConstraintsList) ||
|
||||
this.videoInOfferOptions(offerOptions);
|
||||
|
||||
var numDataTracks = this.dataChannels.length;
|
||||
|
||||
var numAudioVideoDataTracks = numAudioTracks + numVideoTracks + numDataTracks;
|
||||
info("expected audio + video + data tracks: " + numAudioVideoDataTracks);
|
||||
is(numAudioVideoDataTracks, numIceConnections, "stats ICE connections matches expected A/V tracks");
|
||||
|
@ -535,7 +535,6 @@ var commandsPeerConnection = [
|
||||
test.pcLocal.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
0,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
@ -548,7 +547,6 @@ var commandsPeerConnection = [
|
||||
test.pcRemote.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
0,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
@ -724,626 +722,3 @@ var commandsPeerConnection = [
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Default list of commands to execute for a Datachannel test.
|
||||
*/
|
||||
var commandsDataChannel = [
|
||||
[
|
||||
'PC_LOCAL_SETUP_ICE_LOGGER',
|
||||
function (test) {
|
||||
test.pcLocal.logIceConnectionState();
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SETUP_ICE_LOGGER',
|
||||
function (test) {
|
||||
test.pcRemote.logIceConnectionState();
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SETUP_SIGNALING_LOGGER',
|
||||
function (test) {
|
||||
test.pcLocal.logSignalingState();
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SETUP_SIGNALING_LOGGER',
|
||||
function (test) {
|
||||
test.pcRemote.logSignalingState();
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_GUM',
|
||||
function (test) {
|
||||
test.pcLocal.getAllUserMedia(test.pcLocal.constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_INITIAL_SIGNALINGSTATE',
|
||||
function (test) {
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
"Initial local signalingState is stable");
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_INITIAL_ICE_STATE',
|
||||
function (test) {
|
||||
is(test.pcLocal.iceConnectionState, ICE_NEW,
|
||||
"Initial local ICE connection state is 'new'");
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_GUM',
|
||||
function (test) {
|
||||
test.pcRemote.getAllUserMedia(test.pcRemote.constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_INITIAL_SIGNALINGSTATE',
|
||||
function (test) {
|
||||
is(test.pcRemote.signalingState, STABLE,
|
||||
"Initial remote signalingState is stable");
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CHECK_INITIAL_ICE_STATE',
|
||||
function (test) {
|
||||
is(test.pcRemote.iceConnectionState, ICE_NEW,
|
||||
"Initial remote ICE connection state is 'new'");
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SETUP_ICE_HANDLER',
|
||||
function (test) {
|
||||
test.pcLocal.setupIceCandidateHandler(test);
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SETUP_ICE_HANDLER',
|
||||
function (test) {
|
||||
test.pcRemote.setupIceCandidateHandler(test);
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CREATE_DATA_CHANNEL',
|
||||
function (test) {
|
||||
var channel = test.pcLocal.createDataChannel({});
|
||||
|
||||
is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
|
||||
is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
|
||||
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
"Create datachannel does not change signaling state");
|
||||
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CREATE_OFFER',
|
||||
function (test) {
|
||||
test.createOffer(test.pcLocal, function (offer) {
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
"Local create offer does not change signaling state");
|
||||
ok(offer.sdp.contains("m=application"),
|
||||
"m=application is contained in the SDP");
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_STEEPLECHASE_SIGNAL_OFFER',
|
||||
function (test) {
|
||||
if (test.steeplechase) {
|
||||
send_message({"type": "offer",
|
||||
"offer": test.originalOffer,
|
||||
"offer_constraints": test.pcLocal.constraints,
|
||||
"offer_options": test.pcLocal.offerOptions});
|
||||
test._local_offer = test.originalOffer;
|
||||
test._offer_constraints = test.pcLocal.constraints;
|
||||
test._offer_options = test.pcLocal.offerOptions;
|
||||
}
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SET_LOCAL_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setLocalDescription(test.pcLocal, test.originalOffer, HAVE_LOCAL_OFFER,
|
||||
function () {
|
||||
is(test.pcLocal.signalingState, HAVE_LOCAL_OFFER,
|
||||
"signalingState after local setLocalDescription is 'have-local-offer'");
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_GET_OFFER',
|
||||
function (test) {
|
||||
if (!test.steeplechase) {
|
||||
test._local_offer = test.originalOffer;
|
||||
test._offer_constraints = test.pcLocal.constraints;
|
||||
test._offer_options = test.pcLocal.offerOptions;
|
||||
test.next();
|
||||
} else {
|
||||
test.getSignalingMessage("offer", function (message) {
|
||||
ok("offer" in message, "Got an offer message");
|
||||
test._local_offer = new mozRTCSessionDescription(message.offer);
|
||||
test._offer_constraints = message.offer_constraints;
|
||||
test._offer_options = message.offer_options;
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SET_REMOTE_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setRemoteDescription(test.pcRemote, test._local_offer, HAVE_REMOTE_OFFER,
|
||||
function () {
|
||||
is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
|
||||
"signalingState after remote setRemoteDescription is 'have-remote-offer'");
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
function(trickle) {
|
||||
test.pcLocal.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._local_offer, "offer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CREATE_ANSWER',
|
||||
function (test) {
|
||||
test.createAnswer(test.pcRemote, function (answer) {
|
||||
is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
|
||||
"Remote createAnswer does not change signaling state");
|
||||
ok(answer.sdp.contains("m=application"),
|
||||
"m=application is contained in the SDP");
|
||||
if (test.steeplechase) {
|
||||
send_message({"type":"answer",
|
||||
"answer": test.originalAnswer,
|
||||
"answer_constraints": test.pcRemote.constraints});
|
||||
test._remote_answer = test.pcRemote._last_answer;
|
||||
test._answer_constraints = test.pcRemote.constraints;
|
||||
}
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SETUP_DATA_CHANNEL_CALLBACK',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcLocal, function () {
|
||||
ok(true, test.pcLocal + " dataChannels[0] switched to 'open'");
|
||||
},
|
||||
// At this point a timeout failure will be of no value
|
||||
null);
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SETUP_DATA_CHANNEL_CALLBACK',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcRemote, function () {
|
||||
ok(true, test.pcRemote + " dataChannels[0] switched to 'open'");
|
||||
},
|
||||
// At this point a timeout failure will be of no value
|
||||
null);
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SET_LOCAL_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setLocalDescription(test.pcRemote, test.originalAnswer, STABLE,
|
||||
function () {
|
||||
is(test.pcRemote.signalingState, STABLE,
|
||||
"signalingState after remote setLocalDescription is 'stable'");
|
||||
test.next();
|
||||
}
|
||||
);
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_GET_ANSWER',
|
||||
function (test) {
|
||||
if (!test.steeplechase) {
|
||||
test._remote_answer = test.originalAnswer;
|
||||
test._answer_constraints = test.pcRemote.constraints;
|
||||
test.next();
|
||||
} else {
|
||||
test.getSignalingMessage("answer", function (message) {
|
||||
ok("answer" in message, "Got an answer message");
|
||||
test._remote_answer = new mozRTCSessionDescription(message.answer);
|
||||
test._answer_constraints = message.answer_constraints;
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SET_REMOTE_DESCRIPTION',
|
||||
function (test) {
|
||||
test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE,
|
||||
function () {
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
"signalingState after local setRemoteDescription is 'stable'");
|
||||
test.next();
|
||||
}
|
||||
);
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_SANE_LOCAL_SDP',
|
||||
function (test) {
|
||||
test.pcRemote.verifySdp(test._remote_answer, "answer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcRemote.localRequiresTrickleIce = trickle;
|
||||
});
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_SANE_REMOTE_SDP',
|
||||
function (test) {
|
||||
test.pcLocal.verifySdp(test._remote_answer, "answer",
|
||||
test._offer_constraints, test._offer_options,
|
||||
function (trickle) {
|
||||
test.pcLocal.remoteRequiresTrickleIce = trickle;
|
||||
});
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_WAIT_FOR_ICE_CONNECTED',
|
||||
function (test) {
|
||||
var myTest = test;
|
||||
var myPc = myTest.pcLocal;
|
||||
|
||||
function onIceConnectedSuccess () {
|
||||
info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
|
||||
ok(true, "pc_local: ICE switched to 'connected' state");
|
||||
myTest.next();
|
||||
};
|
||||
function onIceConnectedFailed () {
|
||||
dumpSdp(myTest);
|
||||
ok(false, "pc_local: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
|
||||
myTest.next();
|
||||
};
|
||||
|
||||
if (myPc.isIceConnected()) {
|
||||
info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
|
||||
ok(true, "pc_local: ICE is in connected state");
|
||||
myTest.next();
|
||||
} else if (myPc.isIceConnectionPending()) {
|
||||
myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
|
||||
} else {
|
||||
dumpSdp(myTest);
|
||||
ok(false, "pc_local: ICE is already in bad state: " + myPc.iceConnectionState);
|
||||
myTest.next();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_VERIFY_ICE_GATHERING',
|
||||
function (test) {
|
||||
if (test.pcLocal.localRequiresTrickleIce) {
|
||||
ok(test.pcLocal._local_ice_candidates.length > 0, "Received local trickle ICE candidates");
|
||||
}
|
||||
isnot(test.pcLocal._pc.iceGatheringState, GATH_NEW, "ICE gathering state is not 'new'");
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_WAIT_FOR_ICE_CONNECTED',
|
||||
function (test) {
|
||||
var myTest = test;
|
||||
var myPc = myTest.pcRemote;
|
||||
|
||||
function onIceConnectedSuccess () {
|
||||
info("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog);
|
||||
ok(true, "pc_remote: ICE switched to 'connected' state");
|
||||
myTest.next();
|
||||
};
|
||||
function onIceConnectedFailed () {
|
||||
dumpSdp(myTest);
|
||||
ok(false, "pc_remote: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
|
||||
myTest.next();
|
||||
};
|
||||
|
||||
if (myPc.isIceConnected()) {
|
||||
info("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog);
|
||||
ok(true, "pc_remote: ICE is in connected state");
|
||||
myTest.next();
|
||||
} else if (myPc.isIceConnectionPending()) {
|
||||
myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
|
||||
} else {
|
||||
dumpSdp(myTest);
|
||||
ok(false, "pc_remote: ICE is already in bad state: " + myPc.iceConnectionState);
|
||||
myTest.next();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_VERIFY_ICE_GATHERING',
|
||||
function (test) {
|
||||
if (test.pcRemote.localRequiresTrickleIce) {
|
||||
ok(test.pcRemote._local_ice_candidates.length > 0, "Received local trickle ICE candidates");
|
||||
}
|
||||
isnot(test.pcRemote._pc.iceGatheringState, GATH_NEW, "ICE gathering state is not 'new'");
|
||||
test.next();
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_VERIFY_DATA_CHANNEL_STATE',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcLocal, function() {
|
||||
test.next();
|
||||
}, function() {
|
||||
ok(false, test.pcLocal + " initial dataChannels[0] failed to switch to 'open'");
|
||||
//TODO: use stopAndExit() once bug 1019323 has landed
|
||||
unexpectedEventAndFinish(this, 'timeout')
|
||||
// to prevent test framework timeouts
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_VERIFY_DATA_CHANNEL_STATE',
|
||||
function (test) {
|
||||
test.waitForInitialDataChannel(test.pcRemote, function() {
|
||||
test.next();
|
||||
}, function() {
|
||||
ok(false, test.pcRemote + " initial dataChannels[0] failed to switch to 'open'");
|
||||
//TODO: use stopAndExit() once bug 1019323 has landed
|
||||
unexpectedEventAndFinish(this, 'timeout');
|
||||
// to prevent test framework timeouts
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_MEDIA_TRACKS',
|
||||
function (test) {
|
||||
test.pcLocal.checkMediaTracks(test._answer_constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CHECK_MEDIA_TRACKS',
|
||||
function (test) {
|
||||
test.pcRemote.checkMediaTracks(test._offer_constraints, function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_MEDIA_FLOW_PRESENT',
|
||||
function (test) {
|
||||
test.pcLocal.checkMediaFlowPresent(function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT',
|
||||
function (test) {
|
||||
test.pcRemote.checkMediaFlowPresent(function () {
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_LOCAL_CHECK_ICE_CONNECTIONS',
|
||||
function (test) {
|
||||
test.pcLocal.getStats(null, function(stats) {
|
||||
test.pcLocal.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
1,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'PC_REMOTE_CHECK_ICE_CONNECTIONS',
|
||||
function (test) {
|
||||
test.pcRemote.getStats(null, function(stats) {
|
||||
test.pcRemote.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
1,
|
||||
test.originalAnswer);
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE',
|
||||
function (test) {
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(data, message, "Message correctly transmitted from pcLocal to pcRemote.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_BLOB',
|
||||
function (test) {
|
||||
var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
|
||||
var blob = new Blob(contents, { "type" : "text/plain" });
|
||||
|
||||
test.send(blob, function (channel, data) {
|
||||
ok(data instanceof Blob, "Received data is of instance Blob");
|
||||
is(data.size, blob.size, "Received data has the correct size.");
|
||||
|
||||
getBlobContent(data, function (recv_contents) {
|
||||
is(recv_contents, contents, "Received data has the correct content.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'CREATE_SECOND_DATA_CHANNEL',
|
||||
function (test) {
|
||||
test.createDataChannel({ }, function (sourceChannel, targetChannel) {
|
||||
is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
|
||||
is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
|
||||
|
||||
is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
|
||||
is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL',
|
||||
function (test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(channels.indexOf(channel), channels.length - 1, "Last channel used");
|
||||
is(data, message, "Received message has the correct content.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_THROUGH_FIRST_CHANNEL',
|
||||
function (test) {
|
||||
var message = "Message through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcLocal.dataChannels[0],
|
||||
targetChannel: test.pcRemote.dataChannels[0]
|
||||
};
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(test.pcRemote.dataChannels.indexOf(channel), 0, "1st channel used");
|
||||
is(data, message, "Received message has the correct content.");
|
||||
|
||||
test.next();
|
||||
}, options);
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL',
|
||||
function (test) {
|
||||
var message = "Return a message also through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcRemote.dataChannels[0],
|
||||
targetChannel: test.pcLocal.dataChannels[0]
|
||||
};
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(test.pcLocal.dataChannels.indexOf(channel), 0, "1st channel used");
|
||||
is(data, message, "Return message has the correct content.");
|
||||
|
||||
test.next();
|
||||
}, options);
|
||||
}
|
||||
],
|
||||
[
|
||||
'CREATE_NEGOTIATED_DATA_CHANNEL',
|
||||
function (test) {
|
||||
var options = {negotiated:true, id: 5, protocol:"foo/bar", ordered:false,
|
||||
maxRetransmits:500};
|
||||
test.createDataChannel(options, function (sourceChannel2, targetChannel2) {
|
||||
is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
|
||||
is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
|
||||
|
||||
is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
|
||||
is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
|
||||
|
||||
if (options.id != undefined) {
|
||||
is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
|
||||
}
|
||||
else {
|
||||
options.id = sourceChannel2.id;
|
||||
}
|
||||
var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
|
||||
is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
|
||||
is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
|
||||
is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
|
||||
sourceChannel2.maxRetransmits);
|
||||
is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
|
||||
sourceChannel2.maxRetransmitTime);
|
||||
*/
|
||||
|
||||
is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
|
||||
is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
|
||||
is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
|
||||
is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
|
||||
targetChannel2.maxRetransmits);
|
||||
is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
|
||||
targetChannel2.maxRetransmitTime);
|
||||
*/
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2',
|
||||
function (test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
test.send(message, function (channel, data) {
|
||||
is(channels.indexOf(channel), channels.length - 1, "Last channel used");
|
||||
is(data, message, "Received message has the correct content.");
|
||||
|
||||
test.next();
|
||||
});
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="dataChannel.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
@ -17,8 +18,9 @@
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new DataChannelTest();
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addInitialDataChannel(test.chain);
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="dataChannel.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
@ -17,8 +18,9 @@
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new DataChannelTest();
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addInitialDataChannel(test.chain);
|
||||
test.setMediaConstraints([{audio: true}, {video: true}],
|
||||
[{audio: true}, {video: true}]);
|
||||
test.run();
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="dataChannel.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
@ -17,8 +18,9 @@
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new DataChannelTest();
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addInitialDataChannel(test.chain);
|
||||
test.setMediaConstraints([{audio: true, video: true}],
|
||||
[{audio: true, video: true}]);
|
||||
test.run();
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="dataChannel.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
@ -11,8 +12,6 @@
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
SimpleTest.requestFlakyTimeout("untriaged");
|
||||
|
||||
createHTML({
|
||||
bug: "1016476",
|
||||
title: "Basic data channel audio/video connection without bundle"
|
||||
@ -20,9 +19,8 @@
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new DataChannelTest();
|
||||
test.setMediaConstraints([{audio: true}, {video: true}],
|
||||
[{audio: true}, {video: true}]);
|
||||
test = new PeerConnectionTest();
|
||||
addInitialDataChannel(test.chain);
|
||||
test.chain.insertAfter("PC_LOCAL_CREATE_OFFER",
|
||||
[[
|
||||
'PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER',
|
||||
@ -35,6 +33,8 @@
|
||||
}
|
||||
]]
|
||||
);
|
||||
test.setMediaConstraints([{audio: true}, {video: true}],
|
||||
[{audio: true}, {video: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="dataChannel.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
@ -17,8 +18,9 @@
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new DataChannelTest();
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addInitialDataChannel(test.chain);
|
||||
test.run();
|
||||
});
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="dataChannel.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
@ -17,8 +18,9 @@
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new DataChannelTest();
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addInitialDataChannel(test.chain);
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="dataChannel.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
<script type="application/javascript" src="templates.js"></script>
|
||||
@ -17,8 +18,9 @@
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function () {
|
||||
test = new DataChannelTest();
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addInitialDataChannel(test.chain);
|
||||
var sld = test.chain.remove("PC_REMOTE_SET_LOCAL_DESCRIPTION");
|
||||
test.chain.insertAfter("PC_LOCAL_SET_REMOTE_DESCRIPTION", sld);
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
|
@ -260,7 +260,7 @@ anp_audio_newTrack(uint32_t sampleRate, // sampling rate in Hz
|
||||
|
||||
if (autoFrame.CheckForException() || obj == nullptr) {
|
||||
jenv->DeleteGlobalRef(s->at_class);
|
||||
free(s);
|
||||
delete s;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -268,7 +268,7 @@ anp_audio_newTrack(uint32_t sampleRate, // sampling rate in Hz
|
||||
|
||||
if (autoFrame.CheckForException() || state == STATE_UNINITIALIZED) {
|
||||
jenv->DeleteGlobalRef(s->at_class);
|
||||
free(s);
|
||||
delete s;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -310,7 +310,7 @@ anp_audio_start(ANPAudioTrack* s)
|
||||
|
||||
if (autoFrame.CheckForException()) {
|
||||
jenv->DeleteGlobalRef(s->at_class);
|
||||
free(s);
|
||||
delete s;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,10 @@ BrowserStreamChild::StreamConstructed(
|
||||
&mStream, seekable, stype);
|
||||
if (rv != NPERR_NO_ERROR) {
|
||||
mState = DELETING;
|
||||
mStreamNotify = nullptr;
|
||||
if (mStreamNotify) {
|
||||
mStreamNotify->SetAssociatedStream(nullptr);
|
||||
mStreamNotify = nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mState = ALIVE;
|
||||
|
@ -2440,7 +2440,6 @@ StreamNotifyChild::ActorDestroy(ActorDestroyReason why)
|
||||
void
|
||||
StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs)
|
||||
{
|
||||
NS_ASSERTION(bs, "Shouldn't be null");
|
||||
NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?");
|
||||
|
||||
mBrowserStream = bs;
|
||||
|
@ -35,8 +35,9 @@
|
||||
#include "nsPluginTags.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "PluginHangUIParent.h"
|
||||
#include "mozilla/widget/AudioSession.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "PluginHangUIParent.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
@ -2481,7 +2482,7 @@ PluginModuleChromeParent::InitializeInjector()
|
||||
return;
|
||||
|
||||
TimeStamp th32Start = TimeStamp::Now();
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
nsAutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
|
||||
if (INVALID_HANDLE_VALUE == snapshot)
|
||||
return;
|
||||
TimeStamp th32End = TimeStamp::Now();
|
||||
|
@ -444,7 +444,7 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost)
|
||||
}
|
||||
// path can begin with "/" but not "//"
|
||||
// see http://tools.ietf.org/html/rfc3986#section-3.3
|
||||
if (!hostChar()) {
|
||||
if (peek(SLASH)) {
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
|
||||
params, ArrayLength(params));
|
||||
|
@ -826,13 +826,16 @@ void NetworkUtils::startTethering(CommandChain* aChain,
|
||||
if (aResult.mResultReason.Find("started") != kNotFound) {
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
|
||||
} else {
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s", GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp));
|
||||
|
||||
// If usbStartIp/usbEndIp is not valid, don't append them since
|
||||
// the trailing white spaces will be parsed to extra empty args
|
||||
// See: http://androidxref.com/4.3_r2.1/xref/system/core/libsysutils/src/FrameworkListener.cpp#78
|
||||
if (!GET_FIELD(mUsbStartIp).IsEmpty() && !GET_FIELD(mUsbEndIp).IsEmpty()) {
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "%s %s %s", command, GET_CHAR(mUsbStartIp), GET_CHAR(mUsbEndIp));
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s %s %s",
|
||||
GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp),
|
||||
GET_CHAR(mUsbStartIp), GET_CHAR(mUsbEndIp));
|
||||
} else {
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s",
|
||||
GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ support-files =
|
||||
[test_custom_element_callback_innerhtml.html]
|
||||
[test_custom_element_clone_callbacks.html]
|
||||
[test_custom_element_clone_callbacks_extended.html]
|
||||
[test_custom_element_import_node_created_callback.html]
|
||||
[test_nested_content_element.html]
|
||||
[test_dest_insertion_points.html]
|
||||
[test_dest_insertion_points_shadow.html]
|
||||
|
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1093680
|
||||
-->
|
||||
<head>
|
||||
<title>Test created callback order for imported custom element.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<template id="template"><x-foo><span></span></x-foo></template>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1093680">Bug 1093680</a>
|
||||
<script>
|
||||
|
||||
var fooProtoCreatedCallbackCalled = false;
|
||||
var fooProto = Object.create(HTMLElement.prototype);
|
||||
fooProto.createdCallback = function() {
|
||||
ok(this.firstElementChild, "When the created callback is called, the element should already have a child because the callback should only be called after cloning all the contents.");
|
||||
fooProtoCreatedCallbackCalled = true;
|
||||
};
|
||||
|
||||
document.registerElement("x-foo", { prototype: fooProto });
|
||||
|
||||
var template = document.getElementById("template");
|
||||
|
||||
// Importing node will implicityly clone the conent in the main document.
|
||||
var adoptedFoo = document.importNode(template.content, true);
|
||||
|
||||
ok(fooProtoCreatedCallbackCalled, "Created callback should be called after importing custom element into document");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-applet-element
|
||||
[NeedResolve]
|
||||
[NeedResolve, UnsafeInPrerendering]
|
||||
interface HTMLAppletElement : HTMLElement {
|
||||
[Pure, SetterThrows]
|
||||
attribute DOMString align;
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-object-element
|
||||
[NeedResolve]
|
||||
[NeedResolve, UnsafeInPrerendering]
|
||||
interface HTMLObjectElement : HTMLElement {
|
||||
[Pure, SetterThrows]
|
||||
attribute DOMString data;
|
||||
|
@ -73,7 +73,8 @@ interface MozNFCManager {
|
||||
NavigatorProperty="mozNfc",
|
||||
Func="Navigator::HasNFCSupport",
|
||||
CheckPermissions="nfc nfc-share",
|
||||
AvailableIn="PrivilegedApps"]
|
||||
AvailableIn="PrivilegedApps",
|
||||
UnsafeInPrerendering]
|
||||
interface MozNFC : EventTarget {
|
||||
/**
|
||||
* Indicate if NFC is enabled.
|
||||
|
@ -126,7 +126,8 @@ dictionary IPConfiguration {
|
||||
|
||||
[JSImplementation="@mozilla.org/wifimanager;1",
|
||||
NavigatorProperty="mozWifiManager",
|
||||
Func="Navigator::HasWifiManagerSupport"]
|
||||
Func="Navigator::HasWifiManagerSupport",
|
||||
UnsafeInPrerendering]
|
||||
interface MozWifiManager : EventTarget {
|
||||
/**
|
||||
* Turn on/off wifi functionality.
|
||||
|
@ -193,7 +193,7 @@ partial interface Navigator {
|
||||
readonly attribute boolean cookieEnabled;
|
||||
[Throws]
|
||||
readonly attribute DOMString buildID;
|
||||
[Throws, CheckPermissions="power"]
|
||||
[Throws, CheckPermissions="power", UnsafeInPrerendering]
|
||||
readonly attribute MozPowerManager mozPower;
|
||||
|
||||
// WebKit/Blink/Trident/Presto support this.
|
||||
@ -240,7 +240,7 @@ partial interface Navigator {
|
||||
*
|
||||
* @param aTopic resource name
|
||||
*/
|
||||
[Throws, Pref="dom.wakelock.enabled", Func="Navigator::HasWakeLockSupport"]
|
||||
[Throws, Pref="dom.wakelock.enabled", Func="Navigator::HasWakeLockSupport", UnsafeInPrerendering]
|
||||
MozWakeLock requestWakeLock(DOMString aTopic);
|
||||
};
|
||||
|
||||
@ -344,7 +344,7 @@ partial interface Navigator {
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
// nsIDOMMozNavigatorTime
|
||||
partial interface Navigator {
|
||||
[Throws, CheckPermissions="time"]
|
||||
[Throws, CheckPermissions="time", UnsafeInPrerendering]
|
||||
readonly attribute MozTimeManager mozTime;
|
||||
};
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
|
@ -122,6 +122,9 @@ interface MozFrameLoaderOwner {
|
||||
[ChromeOnly]
|
||||
readonly attribute MozFrameLoader? frameLoader;
|
||||
|
||||
[ChromeOnly]
|
||||
void setIsPrerendered();
|
||||
|
||||
[ChromeOnly, Throws]
|
||||
void swapFrameLoaders(XULElement aOtherOwner);
|
||||
};
|
||||
|
@ -13,7 +13,6 @@ using namespace mozilla::dom;
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
#define COMMAND_SIZE 256
|
||||
#define PROPERTY_VALUE_MAX 80
|
||||
|
||||
// Intentionally not trying to dlclose() this handle. That's playing
|
||||
// Russian roulette with security bugs.
|
||||
@ -43,7 +42,7 @@ GetWifiP2pSupported()
|
||||
return (0 == strcmp(propP2pSupported, "1"));
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
hex2num(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
@ -55,7 +54,7 @@ hex2num(char c)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
hex2byte(const char* hex)
|
||||
{
|
||||
int a, b;
|
||||
@ -71,7 +70,7 @@ hex2byte(const char* hex)
|
||||
// This function is equivalent to printf_decode() at src/utils/common.c in
|
||||
// the supplicant.
|
||||
|
||||
uint32_t
|
||||
static uint32_t
|
||||
convertToBytes(char* buf, uint32_t maxlen, const char* str)
|
||||
{
|
||||
const char *pos = str;
|
||||
@ -156,7 +155,8 @@ convertToBytes(char* buf, uint32_t maxlen, const char* str)
|
||||
|
||||
static const uint32_t REPLACE_UTF8 = 0xFFFD;
|
||||
|
||||
void LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aOut)
|
||||
static void
|
||||
LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aOut)
|
||||
{
|
||||
JS::UTF8Chars src(aInput, aLength);
|
||||
|
||||
|
@ -5702,13 +5702,7 @@ WorkerPrivate::SetTimeout(JSContext* aCx,
|
||||
newInfo->mTargetTime = TimeStamp::Now() + newInfo->mInterval;
|
||||
|
||||
if (!newInfo->mTimeoutString.IsEmpty()) {
|
||||
const char* filenameChars;
|
||||
uint32_t lineNumber;
|
||||
if (nsJSUtils::GetCallingLocation(aCx, &filenameChars, &lineNumber)) {
|
||||
newInfo->mFilename = filenameChars;
|
||||
newInfo->mLineNumber = lineNumber;
|
||||
}
|
||||
else {
|
||||
if (!nsJSUtils::GetCallingLocation(aCx, newInfo->mFilename, &newInfo->mLineNumber)) {
|
||||
NS_WARNING("Failed to get calling location!");
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "txXPathOptimizer.h"
|
||||
#include "txExprResult.h"
|
||||
#include "nsIAtom.h"
|
||||
@ -23,18 +24,15 @@ public:
|
||||
nsresult getVariable(int32_t aNamespace, nsIAtom* aLName,
|
||||
txAExprResult*& aResult)
|
||||
{
|
||||
NS_NOTREACHED("shouldn't depend on this context");
|
||||
return NS_ERROR_FAILURE;
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
bool isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
{
|
||||
NS_NOTREACHED("shouldn't depend on this context");
|
||||
return false;
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
void* getPrivateContext()
|
||||
{
|
||||
NS_NOTREACHED("shouldn't depend on this context");
|
||||
return nullptr;
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
txResultRecycler* recycler()
|
||||
{
|
||||
@ -45,22 +43,15 @@ public:
|
||||
}
|
||||
const txXPathNode& getContextNode()
|
||||
{
|
||||
NS_NOTREACHED("shouldn't depend on this context");
|
||||
|
||||
// This will return an invalid node, but we should never
|
||||
// get here so that's fine.
|
||||
|
||||
return *static_cast<txXPathNode*>(nullptr);
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
uint32_t size()
|
||||
{
|
||||
NS_NOTREACHED("shouldn't depend on this context");
|
||||
return 1;
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
uint32_t position()
|
||||
{
|
||||
NS_NOTREACHED("shouldn't depend on this context");
|
||||
return 1;
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1603,6 +1603,12 @@ nsXULElement::LoadSrc()
|
||||
// Usually xul elements are used in chrome, which doesn't have
|
||||
// session history at all.
|
||||
slots->mFrameLoader = nsFrameLoader::Create(this, false);
|
||||
if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::prerendered,
|
||||
NS_LITERAL_STRING("true"), eIgnoreCase)) {
|
||||
nsresult rv = slots->mFrameLoader->SetIsPrerendered();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
|
||||
}
|
||||
|
||||
@ -1627,6 +1633,13 @@ nsXULElement::GetFrameLoader()
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULElement::SetIsPrerendered()
|
||||
{
|
||||
return SetAttr(kNameSpaceID_None, nsGkAtoms::prerendered, nullptr,
|
||||
NS_LITERAL_STRING("true"), true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
|
||||
{
|
||||
|
@ -440,6 +440,7 @@ public:
|
||||
virtual mozilla::EventStates IntrinsicState() const MOZ_OVERRIDE;
|
||||
|
||||
nsresult GetFrameLoader(nsIFrameLoader** aFrameLoader);
|
||||
nsresult SetIsPrerendered();
|
||||
nsresult SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner);
|
||||
|
||||
virtual void RecompileScriptEventListeners() MOZ_OVERRIDE;
|
||||
|
8
dom/xul/test/1061864.html
Normal file
8
dom/xul/test/1061864.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
</script>
|
||||
<iframe id="childiframe" src="data:text/html,Test">
|
||||
</iframe>
|
||||
</body>
|
||||
</html>
|
@ -7,6 +7,7 @@ support-files =
|
||||
overlay2_bug335375.xul
|
||||
window_bug583948.xul
|
||||
window_bug757137.xul
|
||||
1061864.html
|
||||
|
||||
[test_bug199692.xul]
|
||||
[test_bug233643.xul]
|
||||
@ -26,5 +27,7 @@ support-files =
|
||||
[test_bug640158_overlay_persist.xul]
|
||||
[test_bug757137.xul]
|
||||
[test_bug775972.xul]
|
||||
[test_bug1061864_1.xul]
|
||||
[test_bug1061864_2.xul]
|
||||
[test_bug1070049_throw_from_script.xul]
|
||||
[test_import_xul_to_content.xul]
|
||||
|
50
dom/xul/test/test_bug1061864_1.xul
Normal file
50
dom/xul/test/test_bug1061864_1.xul
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1061864
|
||||
-->
|
||||
<window title="Mozilla Bug 1061864"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="RunTest();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
/** Test for Bug 1061864 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function RunTest()
|
||||
{
|
||||
// Test that the docshell belonging to a prerendered frame loader will
|
||||
// be created with the correct prerendered flag.
|
||||
test(false, function() {
|
||||
test(true, function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test(prerendered, callback) {
|
||||
var parentIframe = document.createElement("iframe");
|
||||
if (prerendered) {
|
||||
parentIframe.setIsPrerendered();
|
||||
}
|
||||
parentIframe.onload = function() {
|
||||
var docShell = parentIframe.frameLoader.docShell;
|
||||
is(docShell.isPrerendered, prerendered, "The docshell is" + (prerendered ? "" : " not") + " prerendered");
|
||||
callback();
|
||||
}
|
||||
document.documentElement.appendChild(parentIframe);
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061864"
|
||||
target="_blank">Mozilla Bug 1061864</a>
|
||||
</body>
|
||||
</window>
|
52
dom/xul/test/test_bug1061864_2.xul
Normal file
52
dom/xul/test/test_bug1061864_2.xul
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1061864
|
||||
-->
|
||||
<window title="Mozilla Bug 1061864"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="RunTest();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
/** Test for Bug 1061864 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function RunTest()
|
||||
{
|
||||
// Test that the docshell prerendered flag will be correctly inherited in
|
||||
// prerendered documents.
|
||||
test(false, function() {
|
||||
test(true, function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test(prerendered, callback) {
|
||||
var parentIframe = document.createElement("iframe");
|
||||
if (prerendered) {
|
||||
parentIframe.setIsPrerendered();
|
||||
}
|
||||
parentIframe.setAttribute("src", "1061864.html");
|
||||
parentIframe.onload = function() {
|
||||
var childIframe = parentIframe.contentDocument.getElementById("childiframe");
|
||||
var childDocShell = childIframe.frameLoader.docShell;
|
||||
is(childDocShell.isPrerendered, prerendered, "The docshell is" + (prerendered ? "" : " not") + " prerendered");
|
||||
callback();
|
||||
}
|
||||
document.documentElement.appendChild(parentIframe);
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061864"
|
||||
target="_blank">Mozilla Bug 1061864</a>
|
||||
</body>
|
||||
</window>
|
@ -525,11 +525,18 @@ GLScreenBuffer::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
|
||||
}
|
||||
|
||||
{
|
||||
// Even though we're reading. We're doing it on
|
||||
// the producer side. So we call ProducerAcquire
|
||||
// instead of ConsumerAcquire.
|
||||
src->ProducerAcquire();
|
||||
|
||||
UniquePtr<ReadBuffer> buffer = CreateRead(src);
|
||||
MOZ_ASSERT(buffer);
|
||||
|
||||
ScopedBindFramebuffer autoFB(mGL, buffer->mFB);
|
||||
ReadPixelsIntoDataSurface(mGL, dest);
|
||||
|
||||
src->ProducerRelease();
|
||||
}
|
||||
|
||||
if (needsSwap) {
|
||||
|
@ -102,8 +102,6 @@ SharedSurface_IOSurface::SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioS
|
||||
size,
|
||||
hasAlpha)
|
||||
, mIOSurf(ioSurf)
|
||||
, mCurConsGL(nullptr)
|
||||
, mConsTex(0)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
mProdTex = 0;
|
||||
@ -111,31 +109,12 @@ SharedSurface_IOSurface::SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioS
|
||||
BackTextureWithIOSurf(gl, mProdTex, mIOSurf);
|
||||
}
|
||||
|
||||
GLuint
|
||||
SharedSurface_IOSurface::ConsTexture(GLContext* consGL)
|
||||
{
|
||||
if (!mCurConsGL) {
|
||||
mCurConsGL = consGL;
|
||||
}
|
||||
MOZ_ASSERT(consGL == mCurConsGL);
|
||||
|
||||
if (!mConsTex) {
|
||||
consGL->MakeCurrent();
|
||||
mConsTex = 0;
|
||||
consGL->fGenTextures(1, &mConsTex);
|
||||
BackTextureWithIOSurf(consGL, mConsTex, mIOSurf);
|
||||
}
|
||||
|
||||
return mConsTex;
|
||||
}
|
||||
|
||||
SharedSurface_IOSurface::~SharedSurface_IOSurface()
|
||||
{
|
||||
if (mProdTex) {
|
||||
DebugOnly<bool> success = mGL->MakeCurrent();
|
||||
MOZ_ASSERT(success);
|
||||
mGL->fDeleteTextures(1, &mProdTex);
|
||||
mGL->fDeleteTextures(1, &mConsTex); // This will work if we're shared.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,12 +46,6 @@ public:
|
||||
return static_cast<SharedSurface_IOSurface*>(surf);
|
||||
}
|
||||
|
||||
GLuint ConsTexture(GLContext* consGL);
|
||||
|
||||
GLenum ConsTextureTarget() const {
|
||||
return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
|
||||
}
|
||||
|
||||
MacIOSurface* GetIOSurface() const {
|
||||
return mIOSurf;
|
||||
}
|
||||
@ -67,8 +61,6 @@ private:
|
||||
|
||||
RefPtr<MacIOSurface> mIOSurf;
|
||||
GLuint mProdTex;
|
||||
const GLContext* mCurConsGL;
|
||||
GLuint mConsTex;
|
||||
};
|
||||
|
||||
class SurfaceFactory_IOSurface : public SurfaceFactory
|
||||
|
@ -165,8 +165,6 @@ enum SurfaceInitMode
|
||||
* construct an EffectChain for the quad,
|
||||
* call DrawQuad,
|
||||
* call EndFrame.
|
||||
* If the user has to stop compositing at any point before EndFrame, call
|
||||
* AbortFrame.
|
||||
* If the compositor is usually used for compositing but compositing is
|
||||
* temporarily done without the compositor, call EndFrameForExternalComposition
|
||||
* after compositing each frame so the compositor can remain internally
|
||||
@ -355,11 +353,6 @@ public:
|
||||
*/
|
||||
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) = 0;
|
||||
|
||||
/**
|
||||
* Tidy up if BeginFrame has been called, but EndFrame won't be.
|
||||
*/
|
||||
virtual void AbortFrame() = 0;
|
||||
|
||||
/**
|
||||
* Setup the viewport and projection matrix for rendering to a target of the
|
||||
* given dimensions. The size and transform here will override those set in
|
||||
|
@ -501,14 +501,5 @@ BasicCompositor::EndFrame()
|
||||
mRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BasicCompositor::AbortFrame()
|
||||
{
|
||||
mRenderTarget->mDrawTarget->PopClip();
|
||||
mRenderTarget->mDrawTarget->PopClip();
|
||||
mDrawTarget = nullptr;
|
||||
mRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,6 @@ public:
|
||||
{
|
||||
NS_RUNTIMEABORT("We shouldn't ever hit this");
|
||||
}
|
||||
virtual void AbortFrame() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
|
||||
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE { return true; }
|
||||
|
6
gfx/layers/composite/ContainerLayerComposite.cpp
Normal file → Executable file
6
gfx/layers/composite/ContainerLayerComposite.cpp
Normal file → Executable file
@ -292,6 +292,11 @@ ContainerPrepare(ContainerT* aContainer,
|
||||
* Setup our temporary surface for rendering the contents of this container.
|
||||
*/
|
||||
|
||||
gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
|
||||
if (surfaceRect.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool surfaceCopyNeeded;
|
||||
// DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
|
||||
aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
|
||||
@ -300,7 +305,6 @@ ContainerPrepare(ContainerT* aContainer,
|
||||
RefPtr<CompositingRenderTarget> surface = nullptr;
|
||||
|
||||
RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
|
||||
gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
|
||||
if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
|
||||
surface = lastSurf;
|
||||
}
|
||||
|
@ -304,6 +304,8 @@ ImageLayerD3D10::RenderLayer()
|
||||
(float)yuvImage->GetData()->mPicSize.width / yuvImage->GetData()->mYSize.width,
|
||||
(float)yuvImage->GetData()->mPicSize.height / yuvImage->GetData()->mYSize.height)
|
||||
);
|
||||
} else {
|
||||
MOZ_CRASH("unexpected image format");
|
||||
}
|
||||
|
||||
bool resetTexCoords = image->GetFormat() == ImageFormat::PLANAR_YCBCR;
|
||||
|
@ -124,11 +124,6 @@ public:
|
||||
*/
|
||||
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE {}
|
||||
|
||||
/**
|
||||
* Tidy up if BeginFrame has been called, but EndFrame won't be
|
||||
*/
|
||||
virtual void AbortFrame() MOZ_OVERRIDE {}
|
||||
|
||||
/**
|
||||
* Setup the viewport and projection matrix for rendering
|
||||
* to a window of the given dimensions.
|
||||
|
@ -69,8 +69,6 @@ public:
|
||||
|
||||
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE {}
|
||||
|
||||
virtual void AbortFrame() MOZ_OVERRIDE {}
|
||||
|
||||
virtual void PrepareViewport(const gfx::IntSize& aSize) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE{ return true; }
|
||||
|
@ -199,6 +199,7 @@ static void SetThreadPriority()
|
||||
CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget)
|
||||
: mNeedsComposite(false)
|
||||
, mIsObservingVsync(false)
|
||||
, mVsyncNotificationsSkipped(0)
|
||||
, mCompositorParent(aCompositorParent)
|
||||
, mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
|
||||
, mCurrentCompositeTask(nullptr)
|
||||
@ -285,6 +286,9 @@ CompositorVsyncObserver::Composite(TimeStamp aVsyncTimestamp)
|
||||
if (mNeedsComposite && mCompositorParent) {
|
||||
mNeedsComposite = false;
|
||||
mCompositorParent->CompositeCallback(aVsyncTimestamp);
|
||||
mVsyncNotificationsSkipped = 0;
|
||||
} else if (mVsyncNotificationsSkipped++ > gfxPrefs::CompositorUnobserveCount()) {
|
||||
UnobserveVsync();
|
||||
}
|
||||
|
||||
DispatchTouchEvents(aVsyncTimestamp);
|
||||
|
@ -117,6 +117,7 @@ private:
|
||||
|
||||
bool mNeedsComposite;
|
||||
bool mIsObservingVsync;
|
||||
int32_t mVsyncNotificationsSkipped;
|
||||
nsRefPtr<CompositorParent> mCompositorParent;
|
||||
nsRefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
|
||||
|
||||
|
@ -576,7 +576,7 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
PROFILER_LABEL("CompositorOGL", "BeginFrame",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
|
||||
MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
|
||||
|
||||
mFrameInProgress = true;
|
||||
gfx::Rect rect;
|
||||
@ -1322,18 +1322,6 @@ CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::AbortFrame()
|
||||
{
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
mFrameInProgress = false;
|
||||
mCurrentRenderTarget = nullptr;
|
||||
|
||||
if (mTexturePool) {
|
||||
mTexturePool->EndFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
|
||||
{
|
||||
|
@ -239,7 +239,6 @@ public:
|
||||
virtual void SetFBAcquireFence(Layer* aLayer) MOZ_OVERRIDE;
|
||||
virtual FenceHandle GetReleaseFence() MOZ_OVERRIDE;
|
||||
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE;
|
||||
virtual void AbortFrame() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE;
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nsStringGlue.h" // for nsCString
|
||||
#include "xpcom-config.h" // for CPP_THROW_NEW
|
||||
#include "mozilla/TypedEnum.h" // for the VisitEdges typed enum
|
||||
#include "mozilla/Move.h" // for mozilla::Move
|
||||
|
||||
class nsIntRegion;
|
||||
class gfx3DMatrix;
|
||||
@ -61,6 +62,13 @@ public:
|
||||
aRect.width,
|
||||
aRect.height); }
|
||||
nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
|
||||
nsRegion (nsRegion&& aRegion) { mImpl = aRegion.mImpl; pixman_region32_init(&aRegion.mImpl); }
|
||||
nsRegion& operator = (nsRegion&& aRegion) {
|
||||
pixman_region32_fini(&mImpl);
|
||||
mImpl = aRegion.mImpl;
|
||||
pixman_region32_init(&aRegion.mImpl);
|
||||
return *this;
|
||||
}
|
||||
~nsRegion () { pixman_region32_fini(&mImpl); }
|
||||
nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
|
||||
nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
|
||||
@ -461,8 +469,10 @@ public:
|
||||
nsIntRegion () {}
|
||||
MOZ_IMPLICIT nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
|
||||
nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
|
||||
nsIntRegion (nsIntRegion&& aRegion) : mImpl (mozilla::Move(aRegion.mImpl)) {}
|
||||
nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
|
||||
nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
|
||||
nsIntRegion& operator = (nsIntRegion&& aRegion) { mImpl = mozilla::Move(aRegion.mImpl); return *this; }
|
||||
|
||||
bool operator==(const nsIntRegion& aRgn) const
|
||||
{
|
||||
|
@ -219,6 +219,9 @@ private:
|
||||
// Use vsync events generated by hardware
|
||||
DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled", HardwareVsyncEnabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.vsync.compositor", VsyncAlignedCompositor, bool, false);
|
||||
// On b2g, in really bad cases, I've seen up to 80 ms delays between touch events and the main thread
|
||||
// processing them. So 80 ms / 16 = 5 vsync events. Double it up just to be on the safe side, so 10.
|
||||
DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count", CompositorUnobserveCount, int32_t, 10);
|
||||
DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false);
|
||||
// These times should be in milliseconds
|
||||
DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict", TouchResampleMaxPredict, int32_t, 8);
|
||||
|
@ -438,7 +438,6 @@ HandleFault(PEXCEPTION_POINTERS exception)
|
||||
|
||||
uint8_t **ppc = ContextToPC(context);
|
||||
uint8_t *pc = *ppc;
|
||||
MOZ_ASSERT(pc == record->ExceptionAddress);
|
||||
|
||||
if (record->NumberParameters < 2)
|
||||
return false;
|
||||
@ -453,11 +452,9 @@ HandleFault(PEXCEPTION_POINTERS exception)
|
||||
if (!activation)
|
||||
return false;
|
||||
|
||||
const AsmJSModule &module = activation->module();
|
||||
if (!module.containsFunctionPC(pc))
|
||||
return false;
|
||||
|
||||
# if defined(JS_CODEGEN_X64)
|
||||
const AsmJSModule &module = activation->module();
|
||||
|
||||
// These checks aren't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
void *faultingAddress = (void*)record->ExceptionInformation[1];
|
||||
@ -468,6 +465,25 @@ HandleFault(PEXCEPTION_POINTERS exception)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!module.containsFunctionPC(pc)) {
|
||||
// On Windows, it is possible for InterruptRunningCode to execute
|
||||
// between a faulting heap access and the handling of the fault due
|
||||
// to InterruptRunningCode's use of SuspendThread. When this happens,
|
||||
// after ResumeThread, the exception handler is called with pc equal to
|
||||
// module.interruptExit, which is logically wrong. The Right Thing would
|
||||
// be for the OS to make fault-handling atomic (so that CONTEXT.pc was
|
||||
// always the logically-faulting pc). Fortunately, we can detect this
|
||||
// case and silence the exception ourselves (the exception will
|
||||
// retrigger after the interrupt jumps back to resumePC).
|
||||
if (pc == module.interruptExit() &&
|
||||
module.containsFunctionPC(activation->resumePC()) &&
|
||||
module.lookupHeapAccess(activation->resumePC()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
|
||||
if (!heapAccess)
|
||||
return false;
|
||||
|
@ -2,6 +2,47 @@
|
||||
* 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/. */
|
||||
|
||||
// ES6 draft rev30 (2014/12/24) 22.2.3.7 %TypedArray%.prototype.every(callbackfn[, thisArg]).
|
||||
function TypedArrayEvery(callbackfn, thisArg = undefined) {
|
||||
// This function is not generic.
|
||||
if (!IsObject(this) || !IsTypedArray(this)) {
|
||||
return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
|
||||
"TypedArrayEvery");
|
||||
}
|
||||
|
||||
// Steps 1-2.
|
||||
var O = this;
|
||||
|
||||
// Steps 3-5.
|
||||
var len = TypedArrayLength(O);
|
||||
|
||||
// Step 6.
|
||||
if (arguments.length === 0)
|
||||
ThrowError(JSMSG_MISSING_FUN_ARG, 0, "%TypedArray%.prototype.every");
|
||||
if (!IsCallable(callbackfn))
|
||||
ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
|
||||
|
||||
// Step 7.
|
||||
var T = thisArg;
|
||||
|
||||
// Steps 8-9.
|
||||
// Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
|
||||
for (var k = 0; k < len; k++) {
|
||||
// Steps 9.d.i-9.d.ii.
|
||||
var kValue = O[k];
|
||||
|
||||
// Steps 9.d.iii-9.d.iv.
|
||||
var testResult = callFunction(callbackfn, T, kValue, k, O);
|
||||
|
||||
// Step 9.d.v.
|
||||
if (!testResult)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 10.
|
||||
return true;
|
||||
}
|
||||
|
||||
// ES6 draft rev29 (2014/12/06) 22.2.3.8 %TypedArray%.prototype.fill(value [, start [, end ]])
|
||||
function TypedArrayFill(value, start = 0, end = undefined) {
|
||||
// This function is not generic.
|
||||
@ -283,6 +324,47 @@ function TypedArrayReverse() {
|
||||
return O;
|
||||
}
|
||||
|
||||
// ES6 draft rev30 (2014/12/24) 22.2.3.25 %TypedArray%.prototype.some(callbackfn[, thisArg]).
|
||||
function TypedArraySome(callbackfn, thisArg = undefined) {
|
||||
// This function is not generic.
|
||||
if (!IsObject(this) || !IsTypedArray(this)) {
|
||||
return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
|
||||
"TypedArraySome");
|
||||
}
|
||||
|
||||
// Steps 1-2.
|
||||
var O = this;
|
||||
|
||||
// Steps 3-5.
|
||||
var len = TypedArrayLength(O);
|
||||
|
||||
// Step 6.
|
||||
if (arguments.length === 0)
|
||||
ThrowError(JSMSG_MISSING_FUN_ARG, 0, "%TypedArray%.prototype.some");
|
||||
if (!IsCallable(callbackfn))
|
||||
ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
|
||||
|
||||
// Step 7.
|
||||
var T = thisArg;
|
||||
|
||||
// Steps 8-9.
|
||||
// Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
|
||||
for (var k = 0; k < len; k++) {
|
||||
// Steps 9.d.i-9.d.ii.
|
||||
var kValue = O[k];
|
||||
|
||||
// Steps 9.d.iii-9.d.iv.
|
||||
var testResult = callFunction(callbackfn, T, kValue, k, O);
|
||||
|
||||
// Step 9.d.v.
|
||||
if (testResult)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 10.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Proposed for ES7:
|
||||
// https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
|
||||
function TypedArrayIncludes(searchElement, fromIndex = 0) {
|
||||
|
@ -120,11 +120,13 @@ MarkExactStackRootsAcrossTypes(T context, JSTracer *trc)
|
||||
MarkExactStackRootList<PropDesc, MarkPropDescRoot>(trc, context, "PropDesc");
|
||||
}
|
||||
|
||||
#ifdef JSGC_FJGENERATIONAL
|
||||
static void
|
||||
MarkExactStackRoots(ThreadSafeContext* cx, JSTracer *trc)
|
||||
{
|
||||
MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx, trc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
|
||||
|
@ -297,7 +297,7 @@ struct ExtraPhaseInfo
|
||||
|
||||
// Index into the set of parallel arrays of timing data, for parents with
|
||||
// at least one multi-parented child
|
||||
int dagSlot;
|
||||
size_t dagSlot;
|
||||
};
|
||||
|
||||
static const Phase PHASE_NO_PARENT = PHASE_LIMIT;
|
||||
@ -382,7 +382,7 @@ static const PhaseInfo phases[] = {
|
||||
{ PHASE_LIMIT, nullptr, PHASE_NO_PARENT }
|
||||
};
|
||||
|
||||
ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
|
||||
static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
|
||||
|
||||
// Mapping from all nodes with a multi-parented child to a Vector of all
|
||||
// multi-parented children and their descendants. (Single-parented children will
|
||||
|
@ -82,7 +82,7 @@ static const int kSurrogateRangeCount = ArrayLength(kSurrogateRanges);
|
||||
static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E,
|
||||
0x2028, 0x202A, 0x10000 };
|
||||
static const int kLineTerminatorRangeCount = ArrayLength(kLineTerminatorRanges);
|
||||
static const unsigned kMaxOneByteCharCode = 0xff;
|
||||
static const int kMaxOneByteCharCode = 0xff;
|
||||
static const int kMaxUtf16CodeUnit = 0xffff;
|
||||
|
||||
static char16_t
|
||||
@ -3180,7 +3180,7 @@ SplitSearchSpace(RangeBoundaryVector &ranges,
|
||||
// range with a single not-taken branch, speeding up this important
|
||||
// character range (even non-ASCII charset-based text has spaces and
|
||||
// punctuation).
|
||||
if (*border - 1 > (int) kMaxOneByteCharCode && // ASCII case.
|
||||
if (*border - 1 > kMaxOneByteCharCode && // ASCII case.
|
||||
end_index - start_index > (*new_start_index - start_index) * 2 &&
|
||||
last - first > kSize * 2 &&
|
||||
binary_chop_index > *new_start_index &&
|
||||
|
@ -518,7 +518,7 @@ RegExpParser<CharT>::ScanForCaptures()
|
||||
Advance();
|
||||
break;
|
||||
case '[': {
|
||||
int c;
|
||||
widechar c;
|
||||
while ((c = current()) != kEndMarker) {
|
||||
Advance();
|
||||
if (c == '\\') {
|
||||
|
8
js/src/jit-test/tests/asm.js/testBug1117235.js
Normal file
8
js/src/jit-test/tests/asm.js/testBug1117235.js
Normal file
@ -0,0 +1,8 @@
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
if (helperThreadCount() === 0)
|
||||
quit(0);
|
||||
|
||||
options('werror');
|
||||
offThreadCompileScript("function f() {'use asm'}");
|
||||
assertThrowsInstanceOf(()=>runOffThreadScript(), TypeError);
|
14
js/src/jit-test/tests/asm.js/testBug1117255.js
Normal file
14
js/src/jit-test/tests/asm.js/testBug1117255.js
Normal file
@ -0,0 +1,14 @@
|
||||
function f(stdlib, foreign, buffer) {
|
||||
"use asm";
|
||||
var i32 = new stdlib.Int32Array(buffer);
|
||||
function g(i) {
|
||||
i=i|0;
|
||||
var j=0;
|
||||
for (; (j>>>0) < 100000; j=(j+1)|0)
|
||||
i32[i>>2] = j;
|
||||
}
|
||||
return g
|
||||
}
|
||||
var g = f(this, null, new ArrayBuffer(1<<16));
|
||||
timeout(.1, function cb() { return true });
|
||||
g(1<<16);
|
24
js/src/jit-test/tests/collections/iterator-noSuchMethod.js
Normal file
24
js/src/jit-test/tests/collections/iterator-noSuchMethod.js
Normal file
@ -0,0 +1,24 @@
|
||||
// __noSuchMethod__ is totally non-standard and evil, but in this one weird case
|
||||
// below we don't actually use it. So this test is bog-standard ES6, not
|
||||
// SpiderMonkey-specific.
|
||||
//
|
||||
// In ES6:
|
||||
// Accessing 1[Symbol.iterator]() throws a TypeError calling |undefined|.
|
||||
// In SpiderMonkey:
|
||||
// Accessing 1[Symbol.iterator]() does *not* invoke __noSuchMethod__ looked up
|
||||
// on 1 (or on an implicitly boxed 1), because 1 is a primitive value.
|
||||
// SpiderMonkey then does exactly the ES6 thing here and throws a TypeError
|
||||
// calling |undefined|.
|
||||
|
||||
Object.prototype.__noSuchMethod__ = {};
|
||||
|
||||
try
|
||||
{
|
||||
var [x] = 1;
|
||||
throw new Error("didn't throw");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"expected TypeError, got " + e);
|
||||
}
|
11
js/src/jit-test/tests/debug/bug1116103.js
Normal file
11
js/src/jit-test/tests/debug/bug1116103.js
Normal file
@ -0,0 +1,11 @@
|
||||
// |jit-test| error: ReferenceError
|
||||
|
||||
evaluate(`
|
||||
var g = newGlobal();
|
||||
g.parent = this;
|
||||
g.eval('new Debugger(parent).onExceptionUnwind = function() {};');
|
||||
`)
|
||||
{
|
||||
while (x && 0) {}
|
||||
let x
|
||||
}
|
9
js/src/jit-test/tests/ion/bug1113139.js
Normal file
9
js/src/jit-test/tests/ion/bug1113139.js
Normal file
@ -0,0 +1,9 @@
|
||||
var lfcode = new Array();
|
||||
lfcode.push = function(x) { eval("(function() { " + x + " })();"); };
|
||||
lfcode.push("\
|
||||
function error(str) { try { eval(str); } catch (e) { return e; } }\
|
||||
const YIELD_PAREN = error('(function*(){(for (y of (yield 1, 2)) y)})').message;\
|
||||
const GENEXP_YIELD = error('(function*(){(for (x of yield 1) x)})').message;\
|
||||
const GENERIC = error('(for)').message;\
|
||||
const eval = [];\
|
||||
");
|
14
js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js
Normal file
14
js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js
Normal file
@ -0,0 +1,14 @@
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
// Make sure that a proxy only has a [[Construct]] if the target does
|
||||
|
||||
var handler = {};
|
||||
var p = new Proxy(Math.sin, handler);
|
||||
var r = Proxy.revocable(Math.sin, handler).proxy;
|
||||
|
||||
assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
|
||||
assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
|
||||
// Better throw regardless of whether we have a handler trap.
|
||||
handler.construct = (() => ({}));
|
||||
assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
|
||||
assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
|
@ -205,22 +205,21 @@ CollectJitStackScripts(JSContext *cx, const Debugger::ExecutionObservableSet &ob
|
||||
return false;
|
||||
} else {
|
||||
uint8_t *retAddr = iter.returnAddressToFp();
|
||||
ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr);
|
||||
if (icEntry) {
|
||||
// Normally, the frame is settled on a pc with an ICEntry.
|
||||
if (!entries.append(DebugModeOSREntry(script, *icEntry)))
|
||||
return false;
|
||||
} else {
|
||||
// Otherwise, we are in the middle of handling an
|
||||
// exception. This happens since we could have bailed out
|
||||
// in place from Ion after a throw, settling on the pc
|
||||
// which may have no ICEntry (e.g., Ion is free to insert
|
||||
// resume points after non-effectful ops for better
|
||||
// register allocation).
|
||||
MOZ_ASSERT(iter.baselineFrame()->isDebuggerHandlingException());
|
||||
if (iter.baselineFrame()->isDebuggerHandlingException()) {
|
||||
// We are in the middle of handling an exception. This
|
||||
// happens since we could have bailed out in place from
|
||||
// Ion after a throw, settling on the pc which may have no
|
||||
// ICEntry (e.g., Ion is free to insert resume points
|
||||
// after non-effectful ops for better register
|
||||
// allocation).
|
||||
jsbytecode *pc = script->baselineScript()->pcForNativeAddress(script, retAddr);
|
||||
if (!entries.append(DebugModeOSREntry(script, script->pcToOffset(pc))))
|
||||
return false;
|
||||
} else {
|
||||
// Normally, the frame is settled on a pc with an ICEntry.
|
||||
ICEntry &icEntry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
|
||||
if (!entries.append(DebugModeOSREntry(script, icEntry)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1069,7 +1069,7 @@ TypeAnalyzer::adjustPhiInputs(MPhi *phi)
|
||||
// the original box.
|
||||
phi->replaceOperand(i, in->toUnbox()->input());
|
||||
} else {
|
||||
MDefinition *box = BoxInputsPolicy::alwaysBoxAt(alloc(), in->block()->lastIns(), in);
|
||||
MDefinition *box = AlwaysBoxAt(alloc(), in->block()->lastIns(), in);
|
||||
phi->replaceOperand(i, box);
|
||||
}
|
||||
}
|
||||
|
@ -4389,6 +4389,15 @@ NameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
|
||||
if (!LookupName(cx, name, scopeChain, &obj, &holder, &shape))
|
||||
return false;
|
||||
|
||||
// Look first. Don't generate cache entries if the lookup fails.
|
||||
if (cache.isTypeOf()) {
|
||||
if (!FetchName<true>(cx, obj, holder, name, shape, vp))
|
||||
return false;
|
||||
} else {
|
||||
if (!FetchName<false>(cx, obj, holder, name, shape, vp))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cache.canAttachStub()) {
|
||||
if (IsCacheableNameReadSlot(scopeChain, obj, holder, shape, pc, cache.outputReg())) {
|
||||
if (!cache.attachReadSlot(cx, outerScript, ion, scopeChain, obj,
|
||||
@ -4402,14 +4411,6 @@ NameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.isTypeOf()) {
|
||||
if (!FetchName<true>(cx, obj, holder, name, shape, vp))
|
||||
return false;
|
||||
} else {
|
||||
if (!FetchName<false>(cx, obj, holder, name, shape, vp))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Monitor changes to cache entry.
|
||||
types::TypeScript::Monitor(cx, script, pc, vp);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user