Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-01-06 10:52:47 -05:00
commit 9d3617e4b7
229 changed files with 3789 additions and 2135 deletions

View File

@ -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);

View File

@ -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);

View File

@ -877,6 +877,7 @@ protected:
bool mAllowKeywordFixup;
bool mIsOffScreenBrowser;
bool mIsActive;
bool mIsPrerendered;
bool mIsAppTab;
bool mUseGlobalHistory;
bool mInPrivateBrowsing;

View File

@ -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.
*/

View File

@ -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

View File

@ -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>

View File

@ -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]

View File

@ -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,

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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()
{

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

@ -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")

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -1199,6 +1199,12 @@ nsObjectLoadingContent::GetFrameLoader()
return loader.forget();
}
NS_IMETHODIMP
nsObjectLoadingContent::SetIsPrerendered()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsObjectLoadingContent::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoader)
{

View File

@ -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",

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -148,6 +148,8 @@ private:
// Register MediaRecorder into Document to listen the activity changes.
void RegisterActivityObserver();
void UnRegisterActivityObserver();
bool Check3gppPermission();
};
}

View File

@ -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)

View File

@ -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;

View 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();
});
}
]
]);
}

View File

@ -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

View File

@ -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");

View File

@ -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();
});
}
]
];

View File

@ -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();
});

View File

@ -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();

View File

@ -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();

View File

@ -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();
});

View File

@ -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();
});

View File

@ -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();
});

View File

@ -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}]);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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));

View File

@ -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));
}
}

View File

@ -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]

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -122,6 +122,9 @@ interface MozFrameLoaderOwner {
[ChromeOnly]
readonly attribute MozFrameLoader? frameLoader;
[ChromeOnly]
void setIsPrerendered();
[ChromeOnly, Throws]
void swapFrameLoaders(XULElement aOtherOwner);
};

View File

@ -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);

View File

@ -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!");
}
}

View File

@ -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:

View File

@ -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)
{

View File

@ -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;

View File

@ -0,0 +1,8 @@
<html>
<body>
<script>
</script>
<iframe id="childiframe" src="data:text/html,Test">
</iframe>
</body>
</html>

View File

@ -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]

View 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>

View 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>

View File

@ -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) {

View File

@ -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.
}
}

View File

@ -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

View File

@ -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

View File

@ -501,14 +501,5 @@ BasicCompositor::EndFrame()
mRenderTarget = nullptr;
}
void
BasicCompositor::AbortFrame()
{
mRenderTarget->mDrawTarget->PopClip();
mRenderTarget->mDrawTarget->PopClip();
mDrawTarget = nullptr;
mRenderTarget = nullptr;
}
}
}

View File

@ -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
View 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;
}

View File

@ -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;

View File

@ -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.

View File

@ -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; }

View File

@ -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);

View File

@ -117,6 +117,7 @@ private:
bool mNeedsComposite;
bool mIsObservingVsync;
int32_t mVsyncNotificationsSkipped;
nsRefPtr<CompositorParent> mCompositorParent;
nsRefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;

View File

@ -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)
{

View File

@ -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;

View File

@ -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
{

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -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)

View File

@ -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

View File

@ -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 &&

View File

@ -518,7 +518,7 @@ RegExpParser<CharT>::ScanForCaptures()
Advance();
break;
case '[': {
int c;
widechar c;
while ((c = current()) != kEndMarker) {
Advance();
if (c == '\\') {

View File

@ -0,0 +1,8 @@
load(libdir + "asserts.js");
if (helperThreadCount() === 0)
quit(0);
options('werror');
offThreadCompileScript("function f() {'use asm'}");
assertThrowsInstanceOf(()=>runOffThreadScript(), TypeError);

View 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);

View 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);
}

View 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
}

View 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 = [];\
");

View 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");

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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