зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team, a=merge
MozReview-Commit-ID: FyYG71q4yxf
This commit is contained in:
Коммит
a80b3e7f67
|
@ -44,7 +44,6 @@ testing/**
|
|||
tools/**
|
||||
uriloader/**
|
||||
view/**
|
||||
webapprt/**
|
||||
widget/**
|
||||
xpcom/**
|
||||
xpfe/**
|
||||
|
|
1
.hgtags
1
.hgtags
|
@ -124,3 +124,4 @@ fcef8ded82219c89298b4e376cfbdfba79a1d35a FIREFOX_AURORA_43_BASE
|
|||
67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
|
||||
99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
|
||||
67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
|
||||
68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# you are either running lldb from the top level source directory, the objdir,
|
||||
# or the dist/bin directory. (.lldbinit files in the objdir and dist/bin set
|
||||
# topsrcdir appropriately.)
|
||||
script topsrcdir = topsrcdir if locals().has_key("topsrcdir") else "."; sys.path.append(os.path.join(topsrcdir, "python/lldbutils")); import lldbutils; lldbutils.init()
|
||||
script topsrcdir = topsrcdir if locals().has_key("topsrcdir") else os.getcwd(); sys.path.append(os.path.join(topsrcdir, "python/lldbutils")); import lldbutils; lldbutils.init()
|
||||
|
||||
# Mozilla's use of UNIFIED_SOURCES to include multiple source files into a
|
||||
# single compiled file breaks lldb breakpoint setting. This works around that.
|
||||
|
|
3
CLOBBER
3
CLOBBER
|
@ -22,5 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1246756 - Update Skia to m49 branch.
|
||||
|
||||
Bug 1250297 - Doesn't actually need a clobber, but updating the tree to an older changeset does.
|
||||
|
|
|
@ -24,7 +24,8 @@ TreeWalker::
|
|||
TreeWalker(Accessible* aContext) :
|
||||
mDoc(aContext->Document()), mContext(aContext), mAnchorNode(nullptr),
|
||||
mARIAOwnsIdx(0),
|
||||
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0)
|
||||
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0),
|
||||
mPhase(eAtStart)
|
||||
{
|
||||
mChildFilter |= mContext->NoXBLKids() ?
|
||||
nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
||||
|
@ -32,10 +33,6 @@ TreeWalker::
|
|||
mAnchorNode = mContext->IsDoc() ?
|
||||
mDoc->DocumentNode()->GetRootElement() : mContext->GetContent();
|
||||
|
||||
if (mAnchorNode) {
|
||||
PushState(mAnchorNode);
|
||||
}
|
||||
|
||||
MOZ_COUNT_CTOR(TreeWalker);
|
||||
}
|
||||
|
||||
|
@ -43,7 +40,8 @@ TreeWalker::
|
|||
TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) :
|
||||
mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode),
|
||||
mARIAOwnsIdx(0),
|
||||
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags)
|
||||
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags),
|
||||
mPhase(eAtStart)
|
||||
{
|
||||
MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
|
||||
MOZ_ASSERT(mDoc->GetAccessibleOrContainer(aAnchorNode) == mContext,
|
||||
|
@ -52,8 +50,6 @@ TreeWalker::
|
|||
mChildFilter |= mContext->NoXBLKids() ?
|
||||
nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
||||
|
||||
PushState(aAnchorNode);
|
||||
|
||||
MOZ_COUNT_CTOR(TreeWalker);
|
||||
}
|
||||
|
||||
|
@ -62,14 +58,84 @@ TreeWalker::~TreeWalker()
|
|||
MOZ_COUNT_DTOR(TreeWalker);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TreeWalker: private
|
||||
bool
|
||||
TreeWalker::Seek(nsIContent* aChildNode)
|
||||
{
|
||||
MOZ_ASSERT(aChildNode, "Child cannot be null");
|
||||
|
||||
mPhase = eAtStart;
|
||||
mStateStack.Clear();
|
||||
mARIAOwnsIdx = 0;
|
||||
|
||||
nsIContent* childNode = nullptr;
|
||||
nsINode* parentNode = aChildNode;
|
||||
do {
|
||||
childNode = parentNode->AsContent();
|
||||
parentNode = childNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) &&
|
||||
(mChildFilter & nsIContent::eAllButXBL) ?
|
||||
childNode->GetParentNode() : childNode->GetFlattenedTreeParent();
|
||||
|
||||
if (!parentNode || !parentNode->IsElement()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If ARIA owned child.
|
||||
Accessible* child = mDoc->GetAccessible(childNode);
|
||||
if (child && child->IsRelocated()) {
|
||||
if (child->Parent() != mContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Accessible* ownedChild = nullptr;
|
||||
while ((ownedChild = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++)) &&
|
||||
ownedChild != child);
|
||||
|
||||
MOZ_ASSERT(ownedChild, "A child has to be in ARIA owned elements");
|
||||
mPhase = eAtARIAOwns;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look in DOM.
|
||||
dom::AllChildrenIterator* iter = PrependState(parentNode->AsElement(), true);
|
||||
if (!iter->Seek(childNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parentNode == mAnchorNode) {
|
||||
mPhase = eAtDOM;
|
||||
return true;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Accessible*
|
||||
TreeWalker::Next()
|
||||
{
|
||||
if (mStateStack.IsEmpty()) {
|
||||
return mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++);
|
||||
if (mPhase == eAtEnd) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mPhase == eAtDOM || mPhase == eAtARIAOwns) {
|
||||
mPhase = eAtARIAOwns;
|
||||
Accessible* child = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx);
|
||||
if (child) {
|
||||
mARIAOwnsIdx++;
|
||||
return child;
|
||||
}
|
||||
mPhase = eAtEnd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mAnchorNode) {
|
||||
mPhase = eAtEnd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mPhase = eAtDOM;
|
||||
PushState(mAnchorNode, true);
|
||||
}
|
||||
|
||||
dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
|
||||
|
@ -96,7 +162,7 @@ TreeWalker::Next()
|
|||
|
||||
// Walk down into subtree to find accessibles.
|
||||
if (!skipSubtree && childNode->IsElement()) {
|
||||
top = PushState(childNode);
|
||||
top = PushState(childNode, true);
|
||||
}
|
||||
}
|
||||
top = PopState();
|
||||
|
@ -114,7 +180,7 @@ TreeWalker::Next()
|
|||
return nullptr;
|
||||
|
||||
nsIContent* parent = parentNode->AsElement();
|
||||
top = PushState(parent);
|
||||
top = PushState(parent, true);
|
||||
if (top->Seek(mAnchorNode)) {
|
||||
mAnchorNode = parent;
|
||||
return Next();
|
||||
|
@ -130,6 +196,88 @@ TreeWalker::Next()
|
|||
return Next();
|
||||
}
|
||||
|
||||
Accessible*
|
||||
TreeWalker::Prev()
|
||||
{
|
||||
if (mStateStack.IsEmpty()) {
|
||||
if (mPhase == eAtStart || mPhase == eAtDOM) {
|
||||
mPhase = eAtStart;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mPhase == eAtEnd) {
|
||||
mARIAOwnsIdx = mDoc->ARIAOwnedCount(mContext);
|
||||
mPhase = eAtARIAOwns;
|
||||
}
|
||||
|
||||
if (mPhase == eAtARIAOwns) {
|
||||
if (mARIAOwnsIdx > 0) {
|
||||
return mDoc->ARIAOwnedAt(mContext, --mARIAOwnsIdx);
|
||||
}
|
||||
|
||||
if (!mAnchorNode) {
|
||||
mPhase = eAtStart;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mPhase = eAtDOM;
|
||||
PushState(mAnchorNode, false);
|
||||
}
|
||||
}
|
||||
|
||||
dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
|
||||
while (top) {
|
||||
while (nsIContent* childNode = top->GetPreviousChild()) {
|
||||
bool skipSubtree = false;
|
||||
|
||||
// No accessible creation on the way back.
|
||||
Accessible* child = mDoc->GetAccessible(childNode);
|
||||
|
||||
// Ignore the accessible and its subtree if it was repositioned by means of
|
||||
// aria-owns.
|
||||
if (child) {
|
||||
if (child->IsRelocated()) {
|
||||
continue;
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
// Walk down into subtree to find accessibles.
|
||||
if (!skipSubtree && childNode->IsElement()) {
|
||||
top = PushState(childNode, true);
|
||||
}
|
||||
}
|
||||
top = PopState();
|
||||
}
|
||||
|
||||
// Move to a previous node relative the anchor node within the context
|
||||
// subtree if asked.
|
||||
if (mFlags != eWalkContextTree) {
|
||||
mPhase = eAtStart;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsINode* contextNode = mContext->GetNode();
|
||||
while (mAnchorNode != contextNode) {
|
||||
nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
|
||||
if (!parentNode || !parentNode->IsElement()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent* parent = parentNode->AsElement();
|
||||
top = PushState(parent, true);
|
||||
if (top->Seek(mAnchorNode)) {
|
||||
mAnchorNode = parent;
|
||||
return Prev();
|
||||
}
|
||||
|
||||
mAnchorNode = parent;
|
||||
}
|
||||
|
||||
mPhase = eAtStart;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dom::AllChildrenIterator*
|
||||
TreeWalker::PopState()
|
||||
{
|
||||
|
|
|
@ -50,13 +50,23 @@ public:
|
|||
~TreeWalker();
|
||||
|
||||
/**
|
||||
* Return the next accessible.
|
||||
* Clears the tree walker state and resets it to the given child within
|
||||
* the anchor.
|
||||
*/
|
||||
bool Seek(nsIContent* aChildNode);
|
||||
|
||||
/**
|
||||
* Return the next/prev accessible.
|
||||
*
|
||||
* @note Returned accessible is bound to the document, if the accessible is
|
||||
* rejected during tree creation then the caller should be unbind it
|
||||
* from the document.
|
||||
*/
|
||||
Accessible* Next();
|
||||
Accessible* Prev();
|
||||
|
||||
Accessible* Context() const { return mContext; }
|
||||
DocAccessible* Document() const { return mDoc; }
|
||||
|
||||
private:
|
||||
TreeWalker();
|
||||
|
@ -64,15 +74,23 @@ private:
|
|||
TreeWalker& operator =(const TreeWalker&);
|
||||
|
||||
/**
|
||||
* Create new state for the given node and push it on top of stack.
|
||||
* Create new state for the given node and push it on top of stack / at bottom
|
||||
* of stack.
|
||||
*
|
||||
* @note State stack is used to navigate up/down the DOM subtree during
|
||||
* accessible children search.
|
||||
*/
|
||||
dom::AllChildrenIterator* PushState(nsIContent* aContent)
|
||||
dom::AllChildrenIterator* PushState(nsIContent* aContent,
|
||||
bool aStartAtBeginning)
|
||||
{
|
||||
return mStateStack.AppendElement(
|
||||
dom::AllChildrenIterator(aContent, mChildFilter));
|
||||
dom::AllChildrenIterator(aContent, mChildFilter, aStartAtBeginning));
|
||||
}
|
||||
dom::AllChildrenIterator* PrependState(nsIContent* aContent,
|
||||
bool aStartAtBeginning)
|
||||
{
|
||||
return mStateStack.InsertElementAt(0,
|
||||
dom::AllChildrenIterator(aContent, mChildFilter, aStartAtBeginning));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,6 +107,14 @@ private:
|
|||
|
||||
int32_t mChildFilter;
|
||||
uint32_t mFlags;
|
||||
|
||||
enum Phase {
|
||||
eAtStart,
|
||||
eAtDOM,
|
||||
eAtARIAOwns,
|
||||
eAtEnd
|
||||
};
|
||||
Phase mPhase;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
|
|
@ -291,6 +291,11 @@ public:
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t ARIAOwnedCount(Accessible* aParent) const
|
||||
{
|
||||
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(aParent);
|
||||
return children ? children->Length() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given ID is referred by relation attribute.
|
||||
|
|
|
@ -26,7 +26,6 @@ builtin(include, build/autoconf/arch.m4)dnl
|
|||
builtin(include, build/autoconf/android.m4)dnl
|
||||
builtin(include, build/autoconf/zlib.m4)dnl
|
||||
builtin(include, build/autoconf/linux.m4)dnl
|
||||
builtin(include, build/autoconf/python-virtualenv.m4)dnl
|
||||
builtin(include, build/autoconf/winsdk.m4)dnl
|
||||
builtin(include, build/autoconf/icu.m4)dnl
|
||||
builtin(include, build/autoconf/ffi.m4)dnl
|
||||
|
|
|
@ -10,9 +10,6 @@ if CONFIG['MOZ_EXTENSIONS']:
|
|||
|
||||
DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
|
||||
|
||||
if CONFIG['MOZ_WEBAPP_RUNTIME']:
|
||||
DIRS += ['/webapprt']
|
||||
|
||||
DIRS += [
|
||||
'/b2g/chrome',
|
||||
'/b2g/components',
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 80164520,
|
||||
"digest": "26fd5301aaf6174a0e4f2ac3a8d19f39573f78a051aa78e876c065d60421b2b62207c11fbf1f20f92ba61acc4b9ce58d05409bf5af886943891b04c3d22f5e04",
|
||||
"size": 89319524,
|
||||
"digest": "5383d843c9f28abf0a6d254e9d975d96972d2c86d627ca836fa8e272a5d53230603b387d7d1499c49df7f84b1bb946946e800a85c88d968bdbe81c755fcb02e1",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
|
|
@ -10,9 +10,6 @@ if CONFIG['MOZ_EXTENSIONS']:
|
|||
|
||||
DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
|
||||
|
||||
if CONFIG['MOZ_WEBAPP_RUNTIME']:
|
||||
DIRS += ['/webapprt']
|
||||
|
||||
# Never add dirs after browser because they apparently won't get
|
||||
# packaged properly on Mac.
|
||||
DIRS += ['/browser']
|
||||
|
|
|
@ -678,8 +678,6 @@
|
|||
aria-label="&urlbar.loginFillNotificationAnchor.label;"/>
|
||||
<image id="password-notification-icon" class="notification-anchor-icon" role="button"
|
||||
aria-label="&urlbar.passwordNotificationAnchor.label;"/>
|
||||
<image id="webapps-notification-icon" class="notification-anchor-icon" role="button"
|
||||
aria-label="&urlbar.webappsNotificationAnchor.label;"/>
|
||||
<image id="plugins-notification-icon" class="notification-anchor-icon" role="button"
|
||||
aria-label="&urlbar.pluginsNotificationAnchor.label;"/>
|
||||
<image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"
|
||||
|
|
|
@ -39,10 +39,6 @@
|
|||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
<popupnotification id="webapps-install-progress-notification" hidden="true">
|
||||
<popupnotificationcontent id="webapps-install-progress-content" orient="vertical" align="start"/>
|
||||
</popupnotification>
|
||||
|
||||
<popupnotification id="servicesInstall-notification" hidden="true">
|
||||
<popupnotificationcontent orient="vertical" align="start">
|
||||
<!-- XXX bug 974146, tests are looking for this, can't remove yet. -->
|
||||
|
|
|
@ -278,16 +278,39 @@ Sanitizer.prototype = {
|
|||
}
|
||||
|
||||
// Clear plugin data.
|
||||
// As evidenced in bug 1253204, clearing plugin data can sometimes be
|
||||
// very, very long, for mysterious reasons. Unfortunately, this is not
|
||||
// something actionable by Mozilla, so crashing here serves no purpose.
|
||||
//
|
||||
// For this reason, instead of waiting for sanitization to always
|
||||
// complete, we introduce a soft timeout. Once this timeout has
|
||||
// elapsed, we proceed with the shutdown of Firefox.
|
||||
let promiseClearPluginCookies;
|
||||
TelemetryStopwatch.start("FX_SANITIZE_PLUGINS", refObj);
|
||||
try {
|
||||
yield this.promiseClearPluginCookies(range);
|
||||
// We don't want to wait for this operation to complete...
|
||||
promiseClearPluginCookies = this.promiseClearPluginCookies(range);
|
||||
|
||||
//... at least, not for more than 10 seconds.
|
||||
yield Promise.race([
|
||||
promiseClearPluginCookies,
|
||||
new Promise(resolve => setTimeout(resolve, 10000 /* 10 seconds */))
|
||||
]);
|
||||
} catch (ex) {
|
||||
seenException = ex;
|
||||
} finally {
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS", refObj);
|
||||
}
|
||||
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_COOKIES", refObj);
|
||||
// Detach waiting for plugin cookies to be cleared.
|
||||
promiseClearPluginCookies.catch(() => {
|
||||
// If this exception is raised before the soft timeout, it
|
||||
// will appear in `seenException`. Otherwise, it's too late
|
||||
// to do anything about it.
|
||||
}).then(() => {
|
||||
// Finally, update statistics.
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS", refObj);
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_COOKIES", refObj);
|
||||
});
|
||||
|
||||
if (seenException) {
|
||||
throw seenException;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
[DEFAULT]
|
||||
skip-if = buildapp == "mulet"
|
||||
support-files =
|
||||
empty_file.html
|
||||
file_reflect_cookie_into_title.html
|
||||
|
||||
[browser_usercontext.js]
|
||||
[browser_windowName.js]
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
"work",
|
||||
];
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/browser/components/"
|
||||
+ "contextualidentity/test/browser/empty_file.html";
|
||||
|
||||
add_task(function* setup() {
|
||||
// make sure userContext is enabled.
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
["browser.link.open_newwindow", 3],
|
||||
]});
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
// make sure we don't leave any prefs set for the next tests
|
||||
registerCleanupFunction(function() {
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test() {
|
||||
info("Creating first tab...");
|
||||
let tab1 = gBrowser.addTab(BASE_URI + '?old', {userContextId: 1});
|
||||
let browser1 = gBrowser.getBrowserForTab(tab1);
|
||||
yield BrowserTestUtils.browserLoaded(browser1);
|
||||
yield ContentTask.spawn(browser1, null, function(opts) {
|
||||
content.window.name = 'tab-1';
|
||||
});
|
||||
|
||||
info("Creating second tab...");
|
||||
let tab2 = gBrowser.addTab(BASE_URI + '?old', {userContextId: 2});
|
||||
let browser2 = gBrowser.getBrowserForTab(tab2);
|
||||
yield BrowserTestUtils.browserLoaded(browser2);
|
||||
yield ContentTask.spawn(browser2, null, function(opts) {
|
||||
content.window.name = 'tab-2';
|
||||
});
|
||||
|
||||
// Let's try to open a window from tab1 with a name 'tab-2'.
|
||||
info("Opening a window from the first tab...");
|
||||
yield ContentTask.spawn(browser1, { url: BASE_URI + '?new' }, function(opts) {
|
||||
yield (new content.window.wrappedJSObject.Promise(resolve => {
|
||||
let w = content.window.wrappedJSObject.open(opts.url, 'tab-2');
|
||||
w.onload = function() { resolve(); }
|
||||
}));
|
||||
});
|
||||
|
||||
is(browser1.contentDocument.title, '?old', "Tab1 title must be 'old'");
|
||||
is(browser1.contentDocument.nodePrincipal.userContextId, 1, "Tab1 UCI must be 1");
|
||||
|
||||
is(browser2.contentDocument.title, '?old', "Tab2 title must be 'old'");
|
||||
is(browser2.contentDocument.nodePrincipal.userContextId, 2, "Tab2 UCI must be 2");
|
||||
|
||||
let found = false;
|
||||
for (let i = 0; i < gBrowser.tabContainer.childNodes.length; ++i) {
|
||||
let tab = gBrowser.tabContainer.childNodes[i];
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
if (browser.contentDocument.title == '?new') {
|
||||
is(browser.contentDocument.nodePrincipal.userContextId, 1, "Tab3 UCI must be 1");
|
||||
isnot(browser, browser1, "Tab3 is not browser 1");
|
||||
isnot(browser, browser2, "Tab3 is not browser 2");
|
||||
gBrowser.removeTab(tab);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ok(found, "We have tab3");
|
||||
|
||||
gBrowser.removeTab(tab1);
|
||||
gBrowser.removeTab(tab2);
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
<html><body>
|
||||
<script>
|
||||
document.title = window.location.search;
|
||||
</script>
|
||||
</body></html>
|
|
@ -52,9 +52,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkJSONUtils",
|
||||
"resource://gre/modules/BookmarkJSONUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebappManager",
|
||||
"resource:///modules/WebappManager.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
|
||||
"resource://gre/modules/PageThumbs.jsm");
|
||||
|
||||
|
@ -742,7 +739,6 @@ BrowserGlue.prototype = {
|
|||
// handle any UI migration
|
||||
this._migrateUI();
|
||||
|
||||
WebappManager.init();
|
||||
PageThumbs.init();
|
||||
webrtcUI.init();
|
||||
AboutHome.init();
|
||||
|
@ -1057,9 +1053,6 @@ BrowserGlue.prototype = {
|
|||
}
|
||||
|
||||
SelfSupportBackend.uninit();
|
||||
|
||||
WebappManager.uninit();
|
||||
|
||||
NewTabPrefsProvider.prefs.uninit();
|
||||
AboutNewTab.uninit();
|
||||
webrtcUI.uninit();
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
|
||||
. "$topsrcdir/build/mozconfig.win-common"
|
||||
. "$topsrcdir/browser/config/mozconfigs/common"
|
||||
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-dmd
|
||||
|
||||
ac_add_options --enable-clang-plugin
|
||||
|
||||
. $topsrcdir/build/win32/mozconfig.vs2013-win64
|
||||
|
||||
# Treat warnings as errors (modulo ALLOW_COMPILER_WARNINGS).
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
||||
. "$topsrcdir/build/mozconfig.rust"
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
. "$topsrcdir/build/mozconfig.clang-cl"
|
|
@ -15,8 +15,8 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 80164520,
|
||||
"digest": "26fd5301aaf6174a0e4f2ac3a8d19f39573f78a051aa78e876c065d60421b2b62207c11fbf1f20f92ba61acc4b9ce58d05409bf5af886943891b04c3d22f5e04",
|
||||
"size": 89319524,
|
||||
"digest": "5383d843c9f28abf0a6d254e9d975d96972d2c86d627ca836fa8e272a5d53230603b387d7d1499c49df7f84b1bb946946e800a85c88d968bdbe81c755fcb02e1",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"size": 80513610,
|
||||
"digest": "a388df6ce743be521ba688132d06ba86d225673b53f71f9c7c0d3189adf16f553088d8d359f583f958e886583de9583df53873c85c34abf33b2d55ee7d807206",
|
||||
"size": 78886322,
|
||||
"digest": "9c2c40637de27a0852aa1166f2a08159908b23f7a55855c933087c541461bbb2a1ec9e0522df0d2b9da2b2c343b673dbb5a2fa8d30216fe8acee1eb1383336ea",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc-nightly-i686-pc-windows-msvc.tar.bz2",
|
||||
"filename": "rustc-beta-i686-pc-windows-msvc.tar.bz2",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"size": 72442063,
|
||||
"digest": "899da5af9b322ba63ec04de06f92b5bb82a2700f9fe03001e75fdc6f678a435cd66a474190fd93863327456270aef5649d3788aa50d852121059ced99a6004db",
|
||||
"size": 80157273,
|
||||
"digest": "c4704dcc6774b9f3baaa9313192d26e36bfba2d4380d0518ee7cb89153d9adfe63f228f0ac29848f02948eb1ab7e6624ba71210f0121196d2b54ecebd640d1e6",
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "rustc.tar.bz2",
|
||||
|
|
|
@ -1 +1 @@
|
|||
47.0a1
|
||||
48.0a1
|
||||
|
|
|
@ -1 +1 @@
|
|||
47.0a1
|
||||
48.0a1
|
||||
|
|
|
@ -53,7 +53,6 @@ ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
|
|||
MAR_CHANNEL_ID=firefox-mozilla-central
|
||||
MOZ_PROFILE_MIGRATOR=1
|
||||
MOZ_APP_STATIC_INI=1
|
||||
MOZ_WEBAPP_RUNTIME=1
|
||||
MOZ_MEDIA_NAVIGATOR=1
|
||||
MOZ_WEBGL_CONFORMANT=1
|
||||
# Enable navigator.mozPay
|
||||
|
|
|
@ -836,31 +836,6 @@ bin/libfreebl_32int64_3.so
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBAPP_RUNTIME
|
||||
[WebappRuntime]
|
||||
#ifdef XP_WIN
|
||||
@BINPATH@/webapp-uninstaller@BIN_SUFFIX@
|
||||
#endif
|
||||
@RESPATH@/webapprt-stub@BIN_SUFFIX@
|
||||
@RESPATH@/webapprt/webapprt.ini
|
||||
@RESPATH@/webapprt/chrome.manifest
|
||||
@RESPATH@/webapprt/chrome/webapprt@JAREXT@
|
||||
@RESPATH@/webapprt/chrome/webapprt.manifest
|
||||
@RESPATH@/webapprt/chrome/@AB_CD@@JAREXT@
|
||||
@RESPATH@/webapprt/chrome/@AB_CD@.manifest
|
||||
@RESPATH@/webapprt/components/CommandLineHandler.js
|
||||
@RESPATH@/webapprt/components/ContentPermission.js
|
||||
@RESPATH@/webapprt/components/DirectoryProvider.js
|
||||
@RESPATH@/webapprt/components/PaymentUIGlue.js
|
||||
@RESPATH@/webapprt/components/components.manifest
|
||||
@RESPATH@/webapprt/defaults/preferences/prefs.js
|
||||
@RESPATH@/webapprt/modules/DownloadView.jsm
|
||||
@RESPATH@/webapprt/modules/Startup.jsm
|
||||
@RESPATH@/webapprt/modules/WebappRT.jsm
|
||||
@RESPATH@/webapprt/modules/WebappManager.jsm
|
||||
@RESPATH@/webapprt/modules/WebRTCHandler.jsm
|
||||
#endif
|
||||
|
||||
@RESPATH@/components/DataStore.manifest
|
||||
@RESPATH@/components/DataStoreImpl.js
|
||||
@RESPATH@/components/dom_datastore.xpt
|
||||
|
|
|
@ -100,9 +100,6 @@ libs-%:
|
|||
$(NSINSTALL) -D $(DIST)/install
|
||||
@$(MAKE) -C ../../toolkit/locales libs-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
|
||||
@$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$*
|
||||
ifdef MOZ_WEBAPP_RUNTIME
|
||||
@$(MAKE) -C ../../webapprt/locales AB_CD=$* XPI_NAME=locale-$*
|
||||
endif
|
||||
@$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
|
||||
@$(MAKE) -C ../extensions/pocket/locales AB_CD=$* XPI_NAME=locale-$*
|
||||
@$(MAKE) -C ../extensions/loop/chrome/locale AB_CD=$* XPI_NAME=locale-$*
|
||||
|
@ -138,14 +135,11 @@ endif
|
|||
clobber-zip:
|
||||
$(RM) $(STAGEDIST)/chrome/$(AB_CD).jar \
|
||||
$(STAGEDIST)/chrome/$(AB_CD).manifest \
|
||||
$(STAGEDIST)/webapprt/chrome/$(AB_CD).jar \
|
||||
$(STAGEDIST)/webapprt/chrome/$(AB_CD).manifest \
|
||||
$(STAGEDIST)/$(PREF_DIR)/firefox-l10n.js
|
||||
$(RM) -rf $(STAGEDIST)/dictionaries \
|
||||
$(STAGEDIST)/hyphenation \
|
||||
$(STAGEDIST)/defaults/profile \
|
||||
$(STAGEDIST)/chrome/$(AB_CD) \
|
||||
$(STAGEDIST)/webapprt/chrome/$(AB_CD)
|
||||
$(STAGEDIST)/chrome/$(AB_CD)
|
||||
|
||||
|
||||
langpack: langpack-$(AB_CD)
|
||||
|
|
|
@ -197,7 +197,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||
<!ENTITY urlbar.indexedDBNotificationAnchor.label "View the app-offline storage message">
|
||||
<!ENTITY urlbar.loginFillNotificationAnchor.label "Manage your login information">
|
||||
<!ENTITY urlbar.passwordNotificationAnchor.label "Check if you want to save your password">
|
||||
<!ENTITY urlbar.webappsNotificationAnchor.label "View the app install message">
|
||||
<!ENTITY urlbar.pluginsNotificationAnchor.label "Manage plugin usage on this page">
|
||||
<!ENTITY urlbar.webNotsNotificationAnchor3.label "Change whether you can receive notifications from the site">
|
||||
|
||||
|
|
|
@ -473,20 +473,6 @@ processHang.button_wait.accessKey = W
|
|||
processHang.button_debug.label = Debug Script
|
||||
processHang.button_debug.accessKey = D
|
||||
|
||||
# Webapps notification popup
|
||||
webapps.install = Install
|
||||
webapps.install.accesskey = I
|
||||
#LOCALIZATION NOTE (webapps.requestInstall2) %S is the web app name
|
||||
webapps.requestInstall2 = Do you want to install “%S” from this site?
|
||||
webapps.install.success = Application Installed
|
||||
webapps.install.inprogress = Installation in progress
|
||||
webapps.uninstall = Uninstall
|
||||
webapps.uninstall.accesskey = U
|
||||
webapps.doNotUninstall = Don't Uninstall
|
||||
webapps.doNotUninstall.accesskey = D
|
||||
#LOCALIZATION NOTE (webapps.requestUninstall) %1$S is the web app name
|
||||
webapps.requestUninstall = Do you want to uninstall “%1$S”?
|
||||
|
||||
# LOCALIZATION NOTE (fullscreenButton.tooltip): %S is the keyboard shortcut for full screen
|
||||
fullscreenButton.tooltip=Display the window in full screen (%S)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ def test(mod, path, entity = None):
|
|||
# ignore anything but Firefox
|
||||
if mod not in ("netwerk", "dom", "toolkit", "security/manager",
|
||||
"devtools/client", "devtools/shared",
|
||||
"browser", "webapprt",
|
||||
"browser",
|
||||
"extensions/reporter", "extensions/spellcheck",
|
||||
"other-licenses/branding/firefox",
|
||||
"browser/branding/official",
|
||||
|
|
|
@ -19,7 +19,6 @@ dirs = browser
|
|||
# RFE: that needs to be supported by compare-locales, too, though
|
||||
toolkit = toolkit/locales/l10n.ini
|
||||
services_sync = services/sync/locales/l10n.ini
|
||||
webapprt = webapprt/locales/l10n.ini
|
||||
|
||||
[extras]
|
||||
dirs = extensions/spellcheck
|
||||
|
|
|
@ -1,335 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["WebappManager"];
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Webapps.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
|
||||
"resource://gre/modules/NativeApp.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
|
||||
"resource://gre/modules/WebappOSUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
this.WebappManager = {
|
||||
// List of promises for in-progress installations
|
||||
installations: {},
|
||||
|
||||
init: function() {
|
||||
Services.obs.addObserver(this, "webapps-ask-install", false);
|
||||
Services.obs.addObserver(this, "webapps-ask-uninstall", false);
|
||||
Services.obs.addObserver(this, "webapps-launch", false);
|
||||
Services.obs.addObserver(this, "webapps-uninstall", false);
|
||||
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
|
||||
{ messages: ["Webapps:Install:Return:OK",
|
||||
"Webapps:Install:Return:KO",
|
||||
"Webapps:UpdateState"]});
|
||||
cpmm.addMessageListener("Webapps:Install:Return:OK", this);
|
||||
cpmm.addMessageListener("Webapps:Install:Return:KO", this);
|
||||
cpmm.addMessageListener("Webapps:UpdateState", this);
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
Services.obs.removeObserver(this, "webapps-ask-install");
|
||||
Services.obs.removeObserver(this, "webapps-ask-uninstall");
|
||||
Services.obs.removeObserver(this, "webapps-launch");
|
||||
Services.obs.removeObserver(this, "webapps-uninstall");
|
||||
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
|
||||
["Webapps:Install:Return:OK",
|
||||
"Webapps:Install:Return:KO",
|
||||
"Webapps:UpdateState"]);
|
||||
cpmm.removeMessageListener("Webapps:Install:Return:OK", this);
|
||||
cpmm.removeMessageListener("Webapps:Install:Return:KO", this);
|
||||
cpmm.removeMessageListener("Webapps:UpdateState", this);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
let data = aMessage.data;
|
||||
|
||||
let manifestURL = data.manifestURL ||
|
||||
(data.app && data.app.manifestURL) ||
|
||||
data.manifest;
|
||||
|
||||
if (!this.installations[manifestURL]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aMessage.name == "Webapps:UpdateState") {
|
||||
if (data.error) {
|
||||
this.installations[manifestURL].reject(data.error);
|
||||
} else if (data.app.installState == "installed") {
|
||||
this.installations[manifestURL].resolve();
|
||||
}
|
||||
} else if (aMessage.name == "Webapps:Install:Return:OK" &&
|
||||
!data.isPackage) {
|
||||
let manifest = new ManifestHelper(data.app.manifest,
|
||||
data.app.origin,
|
||||
data.app.manifestURL);
|
||||
if (!manifest.appcache_path) {
|
||||
this.installations[manifestURL].resolve();
|
||||
}
|
||||
} else if (aMessage.name == "Webapps:Install:Return:KO") {
|
||||
this.installations[manifestURL].reject(data.error);
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
let data = JSON.parse(aData);
|
||||
data.mm = aSubject;
|
||||
|
||||
let browser;
|
||||
switch(aTopic) {
|
||||
case "webapps-ask-install":
|
||||
browser = this._getBrowserForId(data.topId);
|
||||
if (browser) {
|
||||
this.doInstall(data, browser);
|
||||
}
|
||||
break;
|
||||
case "webapps-ask-uninstall":
|
||||
browser = this._getBrowserForId(data.topId);
|
||||
if (browser) {
|
||||
this.doUninstall(data, browser);
|
||||
}
|
||||
break;
|
||||
case "webapps-launch":
|
||||
WebappOSUtils.launch(data);
|
||||
break;
|
||||
case "webapps-uninstall":
|
||||
WebappOSUtils.uninstall(data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_getBrowserForId: function(aId) {
|
||||
let windows = Services.wm.getEnumerator("navigator:browser");
|
||||
while (windows.hasMoreElements()) {
|
||||
let window = windows.getNext();
|
||||
let tabbrowser = window.gBrowser;
|
||||
let foundBrowser = tabbrowser.getBrowserForOuterWindowID(aId);
|
||||
if (foundBrowser) {
|
||||
return foundBrowser;
|
||||
}
|
||||
}
|
||||
let foundWindow = Services.wm.getOuterWindowWithId(aId);
|
||||
if (foundWindow) {
|
||||
return foundWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
doInstall: function(aData, aBrowser) {
|
||||
let chromeDoc = aBrowser.ownerDocument;
|
||||
let chromeWin = chromeDoc.defaultView;
|
||||
let popupProgressContent =
|
||||
chromeDoc.getElementById("webapps-install-progress-content");
|
||||
|
||||
let bundle = chromeWin.gNavigatorBundle;
|
||||
|
||||
let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
|
||||
|
||||
let notification;
|
||||
|
||||
let mainAction = {
|
||||
label: bundle.getString("webapps.install"),
|
||||
accessKey: bundle.getString("webapps.install.accesskey"),
|
||||
callback: () => {
|
||||
notification.remove();
|
||||
|
||||
notification = chromeWin.PopupNotifications.
|
||||
show(aBrowser,
|
||||
"webapps-install-progress",
|
||||
bundle.getString("webapps.install.inprogress"),
|
||||
"webapps-notification-icon");
|
||||
|
||||
let progressMeter = chromeDoc.createElement("progressmeter");
|
||||
progressMeter.setAttribute("mode", "undetermined");
|
||||
popupProgressContent.appendChild(progressMeter);
|
||||
|
||||
let manifestURL = aData.app.manifestURL;
|
||||
|
||||
let nativeApp = new NativeApp(aData.app, jsonManifest,
|
||||
aData.app.categories);
|
||||
|
||||
this.installations[manifestURL] = Promise.defer();
|
||||
this.installations[manifestURL].promise.then(() => {
|
||||
notifyInstallSuccess(aData.app, nativeApp, bundle,
|
||||
PrivateBrowsingUtils.isBrowserPrivate(aBrowser));
|
||||
}, (error) => {
|
||||
Cu.reportError("Error installing webapp: " + error);
|
||||
}).then(() => {
|
||||
popupProgressContent.removeChild(progressMeter);
|
||||
delete this.installations[manifestURL];
|
||||
if (Object.getOwnPropertyNames(this.installations).length == 0) {
|
||||
notification.remove();
|
||||
}
|
||||
});
|
||||
|
||||
let localDir;
|
||||
try {
|
||||
localDir = nativeApp.createProfile();
|
||||
} catch (ex) {
|
||||
DOMApplicationRegistry.denyInstall(aData);
|
||||
return;
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(aData, localDir,
|
||||
Task.async(function*(aApp, aManifest, aZipPath) {
|
||||
try {
|
||||
yield nativeApp.install(aApp, aManifest, aZipPath);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error installing webapp: " + ex);
|
||||
throw ex;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let requestingURI = chromeWin.makeURI(aData.from);
|
||||
let app = aData.app;
|
||||
let manifest = new ManifestHelper(jsonManifest, app.origin, app.manifestURL);
|
||||
|
||||
let options = {
|
||||
displayURI: requestingURI,
|
||||
};
|
||||
|
||||
let message = bundle.getFormattedString("webapps.requestInstall2",
|
||||
[manifest.name]);
|
||||
|
||||
let gBrowser = chromeWin.gBrowser;
|
||||
if (gBrowser) {
|
||||
let windowID = aData.oid;
|
||||
|
||||
let listener = {
|
||||
onLocationChange(webProgress) {
|
||||
if (webProgress.DOMWindowID == windowID) {
|
||||
notification.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
gBrowser.addProgressListener(listener);
|
||||
|
||||
options.eventCallback = event => {
|
||||
if (event != "removed") {
|
||||
return;
|
||||
}
|
||||
// The notification was removed, so we should
|
||||
// remove our listener.
|
||||
gBrowser.removeProgressListener(listener);
|
||||
};
|
||||
}
|
||||
|
||||
notification = chromeWin.PopupNotifications.show(aBrowser,
|
||||
"webapps-install",
|
||||
message,
|
||||
"webapps-notification-icon",
|
||||
mainAction, [],
|
||||
options);
|
||||
},
|
||||
|
||||
doUninstall: function(aData, aBrowser) {
|
||||
let chromeDoc = aBrowser.ownerDocument;
|
||||
let chromeWin = chromeDoc.defaultView;
|
||||
|
||||
let bundle = chromeWin.gNavigatorBundle;
|
||||
let jsonManifest = aData.app.manifest;
|
||||
|
||||
let notification;
|
||||
|
||||
let mainAction = {
|
||||
label: bundle.getString("webapps.uninstall"),
|
||||
accessKey: bundle.getString("webapps.uninstall.accesskey"),
|
||||
callback: () => {
|
||||
notification.remove();
|
||||
DOMApplicationRegistry.confirmUninstall(aData);
|
||||
}
|
||||
};
|
||||
|
||||
let secondaryAction = {
|
||||
label: bundle.getString("webapps.doNotUninstall"),
|
||||
accessKey: bundle.getString("webapps.doNotUninstall.accesskey"),
|
||||
callback: () => {
|
||||
notification.remove();
|
||||
DOMApplicationRegistry.denyUninstall(aData, "USER_DECLINED");
|
||||
}
|
||||
};
|
||||
|
||||
let manifest = new ManifestHelper(jsonManifest, aData.app.origin,
|
||||
aData.app.manifestURL);
|
||||
|
||||
let message = bundle.getFormattedString("webapps.requestUninstall",
|
||||
[manifest.name]);
|
||||
|
||||
|
||||
let options = {};
|
||||
let gBrowser = chromeWin.gBrowser;
|
||||
if (gBrowser) {
|
||||
let windowID = aData.oid;
|
||||
|
||||
let listener = {
|
||||
onLocationChange(webProgress) {
|
||||
if (webProgress.DOMWindowID == windowID) {
|
||||
notification.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
gBrowser.addProgressListener(listener);
|
||||
|
||||
options.eventCallback = event => {
|
||||
if (event != "removed") {
|
||||
return;
|
||||
}
|
||||
// The notification was removed, so we should
|
||||
// remove our listener.
|
||||
gBrowser.removeProgressListener(listener);
|
||||
};
|
||||
}
|
||||
|
||||
notification = chromeWin.PopupNotifications.show(
|
||||
aBrowser, "webapps-uninstall", message,
|
||||
"webapps-notification-icon",
|
||||
mainAction, [secondaryAction],
|
||||
options);
|
||||
}
|
||||
}
|
||||
|
||||
function notifyInstallSuccess(aApp, aNativeApp, aBundle, aInPrivateBrowsing) {
|
||||
let launcher = {
|
||||
observe: function(aSubject, aTopic) {
|
||||
if (aTopic == "alertclickcallback") {
|
||||
WebappOSUtils.launch(aApp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
let notifier = Cc["@mozilla.org/alerts-service;1"].
|
||||
getService(Ci.nsIAlertsService);
|
||||
|
||||
notifier.showAlertNotification(aNativeApp.iconURI.spec,
|
||||
aBundle.getString("webapps.install.success"),
|
||||
aNativeApp.appNameAsFilename,
|
||||
true, null, launcher, "", "", "", "", null,
|
||||
aInPrivateBrowsing);
|
||||
} catch (ex) {}
|
||||
}
|
|
@ -44,7 +44,6 @@ EXTRA_JS_MODULES += [
|
|||
'TabGroupsMigrator.jsm',
|
||||
'TransientPrefs.jsm',
|
||||
'UserContextUI.jsm',
|
||||
'WebappManager.jsm',
|
||||
'webrtcUI.jsm',
|
||||
]
|
||||
|
||||
|
|
|
@ -62,11 +62,6 @@
|
|||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install-progress"],
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
|
@ -159,11 +154,6 @@
|
|||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.webapps-notification-icon,
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,15 @@ dnl MOZ_ARG_WITH_STRING( NAME, HELP, IF-SET [, ELSE])
|
|||
dnl MOZ_ARG_HEADER(Comment)
|
||||
dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file
|
||||
|
||||
define([MOZ_DIVERSION_ARGS], 12)
|
||||
|
||||
AC_DEFUN([MOZ_ARG],[dnl
|
||||
AC_DIVERT_PUSH(MOZ_DIVERSION_ARGS)dnl
|
||||
'$1',
|
||||
AC_DIVERT_POP()dnl
|
||||
])
|
||||
AC_DEFUN([MOZ_AC_ARG_ENABLE],[MOZ_ARG([--enable-]translit([$1],[_],[-]))AC_ARG_ENABLE([$1], [$2], [$3], [$4])])
|
||||
AC_DEFUN([MOZ_AC_ARG_WITH],[MOZ_ARG([--with-]translit([$1],[_],[-]))AC_ARG_WITH([$1], [$2], [$3], [$4])])
|
||||
|
||||
dnl MOZ_TWO_STRING_TEST(NAME, VAL, STR1, IF-STR1, STR2, IF-STR2 [, ELSE])
|
||||
AC_DEFUN([MOZ_TWO_STRING_TEST],
|
||||
|
@ -35,19 +44,19 @@ AC_DEFUN([MOZ_TWO_STRING_TEST],
|
|||
|
||||
dnl MOZ_ARG_ENABLE_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE]])
|
||||
AC_DEFUN([MOZ_ARG_ENABLE_BOOL],
|
||||
[AC_ARG_ENABLE([$1], [$2],
|
||||
[MOZ_AC_ARG_ENABLE([$1], [$2],
|
||||
[MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4])],
|
||||
[$5])])
|
||||
|
||||
dnl MOZ_ARG_DISABLE_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE]])
|
||||
AC_DEFUN([MOZ_ARG_DISABLE_BOOL],
|
||||
[AC_ARG_ENABLE([$1], [$2],
|
||||
[MOZ_AC_ARG_ENABLE([$1], [$2],
|
||||
[MOZ_TWO_STRING_TEST([$1], [$enableval], no, [$3], yes, [$4])],
|
||||
[$5])])
|
||||
|
||||
dnl MOZ_ARG_ENABLE_STRING(NAME, HELP, IF-SET [, ELSE])
|
||||
AC_DEFUN([MOZ_ARG_ENABLE_STRING],
|
||||
[AC_ARG_ENABLE([$1], [$2], [$3], [$4])])
|
||||
[MOZ_AC_ARG_ENABLE([$1], [$2], [$3], [$4])])
|
||||
|
||||
dnl MOZ_ARG_ENABLE_BOOL_OR_STRING(NAME, HELP, IF-YES, IF-NO, IF-SET[, ELSE]]])
|
||||
AC_DEFUN([MOZ_ARG_ENABLE_BOOL_OR_STRING],
|
||||
|
@ -55,25 +64,25 @@ AC_DEFUN([MOZ_ARG_ENABLE_BOOL_OR_STRING],
|
|||
[errprint([Option, $1, needs an "IF-SET" argument.
|
||||
])
|
||||
m4exit(1)],
|
||||
[AC_ARG_ENABLE([$1], [$2],
|
||||
[MOZ_AC_ARG_ENABLE([$1], [$2],
|
||||
[MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4], [$5])],
|
||||
[$6])])])
|
||||
|
||||
dnl MOZ_ARG_WITH_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE])
|
||||
AC_DEFUN([MOZ_ARG_WITH_BOOL],
|
||||
[AC_ARG_WITH([$1], [$2],
|
||||
[MOZ_AC_ARG_WITH([$1], [$2],
|
||||
[MOZ_TWO_STRING_TEST([$1], [$withval], yes, [$3], no, [$4])],
|
||||
[$5])])
|
||||
|
||||
dnl MOZ_ARG_WITHOUT_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE])
|
||||
AC_DEFUN([MOZ_ARG_WITHOUT_BOOL],
|
||||
[AC_ARG_WITH([$1], [$2],
|
||||
[MOZ_AC_ARG_WITH([$1], [$2],
|
||||
[MOZ_TWO_STRING_TEST([$1], [$withval], no, [$3], yes, [$4])],
|
||||
[$5])])
|
||||
|
||||
dnl MOZ_ARG_WITH_STRING(NAME, HELP, IF-SET [, ELSE])
|
||||
AC_DEFUN([MOZ_ARG_WITH_STRING],
|
||||
[AC_ARG_WITH([$1], [$2], [$3], [$4])])
|
||||
[MOZ_AC_ARG_WITH([$1], [$2], [$3], [$4])])
|
||||
|
||||
dnl MOZ_ARG_HEADER(Comment)
|
||||
dnl This is used by webconfig to group options
|
||||
|
@ -82,42 +91,5 @@ define(MOZ_ARG_HEADER, [# $1])
|
|||
dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file
|
||||
AC_DEFUN([MOZ_READ_MOZCONFIG],
|
||||
[AC_REQUIRE([AC_INIT_BINSH])dnl
|
||||
inserted=
|
||||
dnl Shell is hard, so here is what the following does:
|
||||
dnl - Reset $@ (command line arguments)
|
||||
dnl - Add the configure options from mozconfig to $@ one by one
|
||||
dnl - Add the original command line arguments after that, one by one
|
||||
dnl
|
||||
dnl There are several tricks involved:
|
||||
dnl - It is not possible to preserve the whitespaces in $@ by assigning to
|
||||
dnl another variable, so the two first steps above need to happen in the first
|
||||
dnl iteration of the third step.
|
||||
dnl - We always want the configure options to be added, so the loop must be
|
||||
dnl iterated at least once, so we add a dummy argument first, and discard it.
|
||||
dnl - something | while read line ... makes the while run in a subshell, meaning
|
||||
dnl that anything it does is not propagated to the main shell, so we can't do
|
||||
dnl set -- foo there. As a consequence, what the while loop reading mach
|
||||
dnl environment output does is output a set of shell commands for the main shell
|
||||
dnl to eval.
|
||||
dnl - Extra care is due when lines from mach environment output contain special
|
||||
dnl shell characters, so we use ' for quoting and ensure no ' end up in between
|
||||
dnl the quoting mark unescaped.
|
||||
dnl Some of the above is directly done in mach environment --format=configure.
|
||||
failed_eval() {
|
||||
echo "Failed eval'ing the following:"
|
||||
$(dirname [$]0)/[$1]/mach environment --format=configure
|
||||
exit 1
|
||||
}
|
||||
|
||||
set -- dummy "[$]@"
|
||||
for ac_option
|
||||
do
|
||||
if test -z "$inserted"; then
|
||||
set --
|
||||
eval "$($(dirname [$]0)/[$1]/mach environment --format=configure)" || failed_eval
|
||||
inserted=1
|
||||
else
|
||||
set -- "[$]@" "$ac_option"
|
||||
fi
|
||||
done
|
||||
. ./old-configure.vars
|
||||
])
|
||||
|
|
|
@ -510,6 +510,7 @@ AC_DEFUN([MOZ_SET_WARNINGS_CXXFLAGS],
|
|||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wwrite-strings"
|
||||
|
||||
# -Wclass-varargs - catches objects passed by value to variadic functions.
|
||||
# -Wimplicit-fallthrough - catches unintentional switch case fallthroughs
|
||||
# -Wloop-analysis - catches issues around loops
|
||||
# -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
|
||||
# -Wthread-safety - catches inconsistent use of mutexes
|
||||
|
@ -528,6 +529,7 @@ AC_DEFUN([MOZ_SET_WARNINGS_CXXFLAGS],
|
|||
MOZ_CXX_SUPPORTS_WARNING(-W, c++14-compat-pedantic, ac_cxx_has_wcxx14_compat_pedantic)
|
||||
MOZ_CXX_SUPPORTS_WARNING(-W, c++1z-compat, ac_cxx_has_wcxx1z_compat)
|
||||
MOZ_CXX_SUPPORTS_WARNING(-W, class-varargs, ac_cxx_has_wclass_varargs)
|
||||
MOZ_CXX_SUPPORTS_WARNING(-W, implicit-fallthrough, ac_cxx_has_wimplicit_fallthrough)
|
||||
MOZ_CXX_SUPPORTS_WARNING(-W, loop-analysis, ac_cxx_has_wloop_analysis)
|
||||
|
||||
if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
|
||||
|
|
|
@ -83,11 +83,9 @@ dnl Replace AC_OUTPUT to create and call a python config.status
|
|||
define([MOZ_CREATE_CONFIG_STATUS],
|
||||
[dnl Top source directory in Windows format (as opposed to msys format).
|
||||
WIN_TOP_SRC=
|
||||
encoding=utf-8
|
||||
case "$host_os" in
|
||||
mingw*)
|
||||
WIN_TOP_SRC=`cd $srcdir; pwd -W`
|
||||
encoding=mbcs
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(WIN_TOP_SRC)
|
||||
|
@ -101,30 +99,13 @@ trap '' 1 2 15
|
|||
AC_CACHE_SAVE
|
||||
|
||||
trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
|
||||
: ${CONFIG_STATUS=./config.status}
|
||||
: ${CONFIG_STATUS=./config.data}
|
||||
|
||||
dnl We're going to need [ ] for python syntax.
|
||||
changequote(<<<, >>>)dnl
|
||||
echo creating $CONFIG_STATUS
|
||||
|
||||
extra_python_path=${COMM_BUILD:+"'mozilla', "}
|
||||
|
||||
cat > $CONFIG_STATUS <<EOF
|
||||
#!${PYTHON}
|
||||
# coding=$encoding
|
||||
|
||||
import os
|
||||
import types
|
||||
dnl topsrcdir is the top source directory in native form, as opposed to a
|
||||
dnl form suitable for make.
|
||||
topsrcdir = '''${WIN_TOP_SRC:-$srcdir}'''
|
||||
if not os.path.isabs(topsrcdir):
|
||||
rel = os.path.join(os.path.dirname(<<<__file__>>>), topsrcdir)
|
||||
topsrcdir = os.path.abspath(rel)
|
||||
topsrcdir = os.path.normpath(topsrcdir)
|
||||
|
||||
topobjdir = os.path.abspath(os.path.dirname(<<<__file__>>>))
|
||||
|
||||
def unique_list(l):
|
||||
result = []
|
||||
for i in l:
|
||||
|
@ -135,7 +116,7 @@ def unique_list(l):
|
|||
dnl All defines and substs are stored with an additional space at the beginning
|
||||
dnl and at the end of the string, to avoid any problem with values starting or
|
||||
dnl ending with quotes.
|
||||
defines = [(name[1:-1], value[1:-1]) for name, value in [
|
||||
defines = [
|
||||
EOF
|
||||
|
||||
dnl confdefs.pytmp contains AC_DEFINEs, in the expected format, but
|
||||
|
@ -144,9 +125,9 @@ sed 's/$/,/' confdefs.pytmp >> $CONFIG_STATUS
|
|||
rm confdefs.pytmp confdefs.h
|
||||
|
||||
cat >> $CONFIG_STATUS <<\EOF
|
||||
] ]
|
||||
]
|
||||
|
||||
substs = [(name[1:-1], value[1:-1] if isinstance(value, types.StringTypes) else value) for name, value in [
|
||||
substs = [
|
||||
EOF
|
||||
|
||||
dnl The MOZ_DIVERSION_SUBST output diversion contains AC_SUBSTs, in the
|
||||
|
@ -162,7 +143,7 @@ for ac_subst_arg in $_subconfigure_ac_subst_args; do
|
|||
done
|
||||
|
||||
cat >> $CONFIG_STATUS <<\EOF
|
||||
] ]
|
||||
]
|
||||
|
||||
dnl List of AC_DEFINEs that aren't to be exposed in ALLDEFINES
|
||||
non_global_defines = [
|
||||
|
@ -177,38 +158,12 @@ fi
|
|||
cat >> $CONFIG_STATUS <<EOF
|
||||
]
|
||||
|
||||
__all__ = ['topobjdir', 'topsrcdir', 'defines', 'non_global_defines', 'substs']
|
||||
flags = [
|
||||
undivert(MOZ_DIVERSION_ARGS)dnl
|
||||
]
|
||||
EOF
|
||||
|
||||
# We don't want js/src/config.status to do anything in gecko builds.
|
||||
if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
|
||||
|
||||
cat >> $CONFIG_STATUS <<EOF
|
||||
dnl Do the actual work
|
||||
if __name__ == '__main__':
|
||||
args = dict([(name, globals()[name]) for name in __all__])
|
||||
from mozbuild.config_status import config_status
|
||||
config_status(**args)
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
changequote([, ])
|
||||
|
||||
chmod +x $CONFIG_STATUS
|
||||
])
|
||||
|
||||
define([MOZ_RUN_CONFIG_STATUS],
|
||||
[
|
||||
|
||||
MOZ_RUN_ALL_SUBCONFIGURES()
|
||||
|
||||
rm -fr confdefs* $ac_clean_files
|
||||
dnl Execute config.status, unless --no-create was passed to configure.
|
||||
if test "$no_create" != yes && ! ${PYTHON} $CONFIG_STATUS; then
|
||||
trap '' EXIT
|
||||
exit 1
|
||||
fi
|
||||
])
|
||||
|
||||
define([m4_fatal],[
|
||||
|
@ -225,21 +180,3 @@ MOZ_RUN_CONFIG_STATUS()],
|
|||
define([AC_CONFIG_HEADER],
|
||||
[m4_fatal([Use CONFIGURE_DEFINE_FILES in moz.build files to produce header files.])
|
||||
])
|
||||
|
||||
define([MOZ_BUILD_BACKEND],
|
||||
[
|
||||
dnl For now, only enable the unified hybrid build system on artifact builds,
|
||||
dnl otherwise default to RecursiveMake /and/ FasterMake.
|
||||
if test -n "$MOZ_ARTIFACT_BUILDS"; then
|
||||
BUILD_BACKENDS="FasterMake+RecursiveMake"
|
||||
else
|
||||
BUILD_BACKENDS="RecursiveMake FasterMake"
|
||||
fi
|
||||
|
||||
MOZ_ARG_ENABLE_STRING(build-backend,
|
||||
[ --enable-build-backend={$($(dirname ]$[0)/$1/mach python -c "from mozbuild.backend import backends; print ','.join(sorted(backends))")}
|
||||
Enable additional build backends],
|
||||
[ BUILD_BACKENDS="$BUILD_BACKENDS `echo $enableval | sed 's/,/ /g'`"])
|
||||
|
||||
AC_SUBST_SET([BUILD_BACKENDS])
|
||||
])
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
dnl This Source Code Form is subject to the terms of the Mozilla Public
|
||||
dnl License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
AC_DEFUN([MOZ_PYTHON],
|
||||
[
|
||||
|
||||
dnl We honor the Python path defined in an environment variable. This is used
|
||||
dnl to pass the virtualenv's Python from the main configure to SpiderMonkey's
|
||||
dnl configure, for example.
|
||||
if test -z "$PYTHON"; then
|
||||
MOZ_PATH_PROGS(PYTHON, $PYTHON python2.7 python)
|
||||
if test -z "$PYTHON"; then
|
||||
AC_MSG_ERROR([python was not found in \$PATH])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([Using Python from environment variable \$PYTHON])
|
||||
fi
|
||||
|
||||
_virtualenv_topsrcdir=
|
||||
_virtualenv_populate_path=
|
||||
|
||||
dnl If this is a mozilla-central, we'll find the virtualenv in the top
|
||||
dnl source directory. If this is a SpiderMonkey build, we assume we're at
|
||||
dnl js/src and try to find the virtualenv from the mozilla-central root.
|
||||
for base in $MOZILLA_CENTRAL_PATH $_topsrcdir $_topsrcdir/../..; do
|
||||
possible=$base/python/mozbuild/mozbuild/virtualenv.py
|
||||
|
||||
if test -e $possible; then
|
||||
_virtualenv_topsrcdir=$base
|
||||
_virtualenv_populate_path=$possible
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -z $_virtualenv_populate_path; then
|
||||
AC_MSG_ERROR([Unable to find Virtualenv population script. In order
|
||||
to build, you will need mozilla-central's virtualenv.
|
||||
|
||||
If you are building from a mozilla-central checkout, you should never see this
|
||||
message. If you are building from a source archive, the source archive was
|
||||
likely not created properly (it is missing the virtualenv files).
|
||||
|
||||
If you have a copy of mozilla-central available, define the
|
||||
MOZILLA_CENTRAL_PATH environment variable to the top source directory of
|
||||
mozilla-central and relaunch configure.])
|
||||
|
||||
fi
|
||||
|
||||
if test -z $DONT_POPULATE_VIRTUALENV; then
|
||||
AC_MSG_RESULT([Creating Python environment])
|
||||
dnl This verifies our Python version is sane and ensures the Python
|
||||
dnl virtualenv is present and up to date. It sanitizes the environment
|
||||
dnl for us, so we don't need to clean anything out.
|
||||
$PYTHON $_virtualenv_populate_path \
|
||||
$_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv \
|
||||
$_virtualenv_topsrcdir/build/virtualenv_packages.txt || exit 1
|
||||
|
||||
case "$host_os" in
|
||||
mingw*)
|
||||
PYTHON=`cd $MOZ_BUILD_ROOT && pwd -W`/_virtualenv/Scripts/python.exe
|
||||
;;
|
||||
*)
|
||||
PYTHON=$MOZ_BUILD_ROOT/_virtualenv/bin/python
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_SUBST(PYTHON)
|
||||
|
||||
AC_MSG_CHECKING([Python environment is Mozilla virtualenv])
|
||||
$PYTHON -c "import mozbuild.base"
|
||||
if test "$?" != 0; then
|
||||
AC_MSG_ERROR([Python environment does not appear to be sane.])
|
||||
fi
|
||||
AC_MSG_RESULT([yes])
|
||||
|
||||
PYTHON_SITE_PACKAGES=`$PYTHON -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib()"`
|
||||
if test -z "$PYTHON_SITE_PACKAGES"; then
|
||||
AC_MSG_ERROR([Could not determine python site packages directory.])
|
||||
fi
|
||||
AC_SUBST([PYTHON_SITE_PACKAGES])
|
||||
|
||||
])
|
||||
|
|
@ -31,9 +31,6 @@ a11y.ini
|
|||
xpcshell.ini
|
||||
For *xpcshell* tests.
|
||||
|
||||
webapprt.ini
|
||||
For the *chrome* flavor of webapp runtime mochitests.
|
||||
|
||||
.. _manifestparser_manifests:
|
||||
|
||||
ManifestParser Manifests
|
||||
|
|
|
@ -12,7 +12,6 @@ ALL_HARNESSES = [
|
|||
'common', # Harnesses without a specific package will look here.
|
||||
'mochitest',
|
||||
'reftest',
|
||||
'webapprt',
|
||||
'xpcshell',
|
||||
'cppunittest',
|
||||
'jittest',
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include('util.configure')
|
||||
|
||||
option(env='DIST', nargs=1, help='DIST directory')
|
||||
|
||||
# Do not allow objdir == srcdir builds.
|
||||
# ==============================================================
|
||||
@depends('--help', 'DIST')
|
||||
def check_build_environment(help, dist):
|
||||
topobjdir = os.path.realpath(os.path.abspath('.'))
|
||||
topsrcdir = os.path.realpath(os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), '..', '..')))
|
||||
|
||||
set_config('TOPSRCDIR', topsrcdir)
|
||||
set_config('TOPOBJDIR', topobjdir)
|
||||
set_config('MOZ_BUILD_ROOT', topobjdir)
|
||||
if dist:
|
||||
set_config('DIST', normsep(dist[0]))
|
||||
else:
|
||||
set_config('DIST', os.path.join(topobjdir, 'dist'))
|
||||
|
||||
if help:
|
||||
return
|
||||
|
||||
if topsrcdir == topobjdir:
|
||||
error(
|
||||
' ***\n'
|
||||
' * Building directly in the main source directory is not allowed.\n'
|
||||
' *\n'
|
||||
' * To build, you must run configure from a separate directory\n'
|
||||
' * (referred to as an object directory).\n'
|
||||
' *\n'
|
||||
' * If you are building with a mozconfig, you will need to change your\n'
|
||||
' * mozconfig to point to a different object directory.\n'
|
||||
' ***'
|
||||
)
|
||||
|
||||
# Check for a couple representative files in the source tree
|
||||
conflict_files = [
|
||||
'* %s' % f for f in ('Makefile', 'config/autoconf.mk')
|
||||
if os.path.exists(os.path.join(topsrcdir, f))
|
||||
]
|
||||
if conflict_files:
|
||||
error(
|
||||
' ***\n'
|
||||
' * Your source tree contains these files:\n'
|
||||
' %s\n'
|
||||
' * This indicates that you previously built in the source tree.\n'
|
||||
' * A source tree build can confuse the separate objdir build.\n'
|
||||
' *\n'
|
||||
' * To clean up the source tree:\n'
|
||||
' * 1. cd %s\n'
|
||||
' * 2. gmake distclean\n'
|
||||
' ***'
|
||||
% ('\n '.join(conflict_files), topsrcdir)
|
||||
)
|
||||
|
||||
|
||||
option(env='MOZ_CURRENT_PROJECT', nargs=1, help='Current build project')
|
||||
option(env='MOZCONFIG', nargs=1, help='Mozconfig location')
|
||||
|
||||
# Read user mozconfig
|
||||
# ==============================================================
|
||||
# Note: the dependency on --help is only there to always read the mozconfig,
|
||||
# even when --help is passed. Without this dependency, the function wouldn't
|
||||
# be called when --help is passed, and the mozconfig wouldn't be read.
|
||||
@depends('MOZ_CURRENT_PROJECT', 'MOZCONFIG', check_build_environment, '--help')
|
||||
@advanced
|
||||
def mozconfig(current_project, mozconfig, build_env, help):
|
||||
from mozbuild.mozconfig import MozconfigLoader
|
||||
|
||||
# Don't read the mozconfig for the js configure (yay backwards
|
||||
# compatibility)
|
||||
if build_env['TOPOBJDIR'].endswith('/js/src'):
|
||||
return {'path': None}
|
||||
|
||||
loader = MozconfigLoader(build_env['TOPSRCDIR'])
|
||||
current_project = current_project[0] if current_project else None
|
||||
mozconfig = mozconfig[0] if mozconfig else None
|
||||
mozconfig = loader.find_mozconfig(env={'MOZCONFIG': mozconfig})
|
||||
mozconfig = loader.read_mozconfig(mozconfig, moz_build_app=current_project)
|
||||
|
||||
return mozconfig
|
||||
|
||||
|
||||
option(env='PYTHON', nargs=1, help='Python interpreter')
|
||||
|
||||
# Setup python virtualenv
|
||||
# ==============================================================
|
||||
@depends('PYTHON', check_build_environment, mozconfig)
|
||||
@advanced
|
||||
def virtualenv_python(env_python, build_env, mozconfig):
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from mozbuild.virtualenv import (
|
||||
VirtualenvManager,
|
||||
verify_python_version,
|
||||
)
|
||||
|
||||
python = env_python[0] if env_python else None
|
||||
|
||||
# Ideally we'd rely on the mozconfig injection from mozconfig_options,
|
||||
# but we'd rather avoid the verbosity when we need to reexecute with
|
||||
# a different python.
|
||||
if mozconfig['path']:
|
||||
if 'PYTHON' in mozconfig['env']['added']:
|
||||
python = mozconfig['env']['added']['PYTHON']
|
||||
elif 'PYTHON' in mozconfig['env']['modified']:
|
||||
python = mozconfig['env']['modified']['PYTHON'][1]
|
||||
elif 'PYTHON' in mozconfig['vars']['added']:
|
||||
python = mozconfig['vars']['added']['PYTHON']
|
||||
elif 'PYTHON' in mozconfig['vars']['modified']:
|
||||
python = mozconfig['vars']['modified']['PYTHON'][1]
|
||||
|
||||
verify_python_version(sys.stderr)
|
||||
topsrcdir, topobjdir = build_env['TOPSRCDIR'], build_env['TOPOBJDIR']
|
||||
if topobjdir.endswith('/js/src'):
|
||||
topobjdir = topobjdir[:-7]
|
||||
|
||||
manager = VirtualenvManager(
|
||||
topsrcdir, topobjdir,
|
||||
os.path.join(topobjdir, '_virtualenv'), sys.stdout,
|
||||
os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'))
|
||||
|
||||
if python:
|
||||
# If we're not in the virtualenv, we need the which module for
|
||||
# find_program.
|
||||
if normsep(sys.executable) != normsep(manager.python_path):
|
||||
sys.path.append(os.path.join(topsrcdir, 'python', 'which'))
|
||||
found_python = find_program(python)
|
||||
if not found_python:
|
||||
error('The PYTHON environment variable does not contain '
|
||||
'a valid path. Cannot find %s' % python)
|
||||
python = found_python
|
||||
else:
|
||||
python = sys.executable
|
||||
|
||||
if not manager.up_to_date(python):
|
||||
warn('Creating Python environment')
|
||||
manager.build(python)
|
||||
|
||||
python = normsep(manager.python_path)
|
||||
|
||||
if python != normsep(sys.executable):
|
||||
warn('Reexecuting in the virtualenv')
|
||||
if env_python:
|
||||
del os.environ['PYTHON']
|
||||
# One would prefer to use os.execl, but that's completely borked on
|
||||
# Windows.
|
||||
sys.exit(subprocess.call([python] + sys.argv))
|
||||
|
||||
# We are now in the virtualenv
|
||||
import distutils.sysconfig
|
||||
if not distutils.sysconfig.get_python_lib():
|
||||
error('Could not determine python site packages directory')
|
||||
|
||||
set_config('PYTHON', python)
|
||||
return python
|
||||
|
||||
|
||||
# Inject mozconfig options
|
||||
# ==============================================================
|
||||
@template
|
||||
@advanced
|
||||
def command_line_helper():
|
||||
# This escapes the sandbox. Don't copy this. This is only here because
|
||||
# it is a one off and because the required functionality doesn't need
|
||||
# to be exposed for other usecases.
|
||||
return depends.__self__._helper
|
||||
|
||||
|
||||
@depends(mozconfig)
|
||||
def mozconfig_options(mozconfig):
|
||||
if mozconfig['path']:
|
||||
helper = command_line_helper()
|
||||
warn('Adding configure options from %s' % mozconfig['path'])
|
||||
for arg in mozconfig['configure_args']:
|
||||
warn(' %s' % arg)
|
||||
# We could be using imply_option() here, but it has other
|
||||
# contraints that don't really apply to the command-line
|
||||
# emulation that mozconfig provides.
|
||||
helper.add(arg, origin='mozconfig', args=helper._args)
|
||||
|
||||
# Ideally we'd handle mozconfig['env'] and mozconfig['vars'] here,
|
||||
# but at the moment, moz.configure has no knowledge of the options
|
||||
# that may appear there. We'll opt-in when we move things from
|
||||
# old-configure.in, which will be tedious but necessary until we
|
||||
# can discriminate what old-configure.in supports.
|
||||
|
||||
del command_line_helper
|
||||
|
||||
|
||||
option(env='MOZILLABUILD', nargs=1,
|
||||
help='Path to Mozilla Build (Windows-only)')
|
|
@ -0,0 +1,402 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
# It feels dirty replicating this from python/mozbuild/mozbuild/mozconfig.py,
|
||||
# but the end goal being that the configure script would go away...
|
||||
@depends('MOZILLABUILD')
|
||||
@advanced
|
||||
def shell(mozillabuild):
|
||||
import sys
|
||||
|
||||
shell = 'sh'
|
||||
if mozillabuild:
|
||||
shell = mozillabuild[0] + '/msys/bin/sh'
|
||||
if sys.platform == 'win32':
|
||||
shell = shell + '.exe'
|
||||
return shell
|
||||
|
||||
|
||||
option(env='AUTOCONF', nargs=1, help='Path to autoconf 2.13')
|
||||
|
||||
@depends(mozconfig, 'AUTOCONF')
|
||||
@advanced
|
||||
def autoconf(mozconfig, autoconf):
|
||||
import re
|
||||
|
||||
mozconfig_autoconf = None
|
||||
if mozconfig['path']:
|
||||
make_extra = mozconfig['make_extra']
|
||||
if make_extra:
|
||||
for assignment in make_extra:
|
||||
m = re.match('(?:export\s+)?AUTOCONF\s*:?=\s*(.+)$',
|
||||
assignment)
|
||||
if m:
|
||||
mozconfig_autoconf = m.group(1)
|
||||
|
||||
autoconf = autoconf[0] if autoconf else None
|
||||
|
||||
for ac in (mozconfig_autoconf, autoconf, 'autoconf-2.13', 'autoconf2.13',
|
||||
'autoconf213'):
|
||||
if ac:
|
||||
autoconf = find_program(ac)
|
||||
if autoconf:
|
||||
break
|
||||
else:
|
||||
fink = find_program('fink')
|
||||
if find:
|
||||
autoconf = os.path.normpath(os.path.join(
|
||||
fink, '..', '..', 'lib', 'autoconf2.13', 'bin', 'autoconf'))
|
||||
|
||||
if not autoconf:
|
||||
error('Could not find autoconf 2.13')
|
||||
|
||||
set_config('AUTOCONF', autoconf)
|
||||
return autoconf
|
||||
|
||||
|
||||
option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script')
|
||||
|
||||
@depends('OLD_CONFIGURE', mozconfig, autoconf, check_build_environment, shell,
|
||||
virtualenv_python, compile_environment)
|
||||
@advanced
|
||||
def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
|
||||
python, compile_env):
|
||||
import glob
|
||||
import itertools
|
||||
import subprocess
|
||||
import sys
|
||||
# Import getmtime without overwriting the sandbox os.path.
|
||||
from os.path import getmtime
|
||||
|
||||
from mozbuild.shellutil import quote
|
||||
|
||||
if not old_configure:
|
||||
error('The OLD_CONFIGURE environment variable must be set')
|
||||
|
||||
# os.path.abspath in the sandbox will ensure forward slashes on Windows,
|
||||
# which is actually necessary because this path actually ends up literally
|
||||
# as $0, and backslashes there breaks autoconf's detection of the source
|
||||
# directory.
|
||||
old_configure = os.path.abspath(old_configure[0])
|
||||
|
||||
refresh = True
|
||||
if os.path.exists(old_configure):
|
||||
mtime = getmtime(old_configure)
|
||||
aclocal = os.path.join(build_env['TOPSRCDIR'], 'build', 'autoconf',
|
||||
'*.m4')
|
||||
for input in itertools.chain(
|
||||
(old_configure + '.in',
|
||||
os.path.join(os.path.dirname(old_configure), 'aclocal.m4')),
|
||||
glob.iglob(aclocal),
|
||||
):
|
||||
if getmtime(input) > mtime:
|
||||
break
|
||||
else:
|
||||
refresh = False
|
||||
|
||||
if refresh:
|
||||
warn('Refreshing %s with %s' % (old_configure, autoconf))
|
||||
with open(old_configure, 'wb') as fh:
|
||||
subprocess.check_call([
|
||||
shell, autoconf,
|
||||
'--localdir=%s' % os.path.dirname(old_configure),
|
||||
old_configure + '.in'], stdout=fh)
|
||||
|
||||
cmd = [shell, old_configure] + sys.argv[1:]
|
||||
with open('old-configure.vars', 'w') as out:
|
||||
if mozconfig['path']:
|
||||
if mozconfig['configure_args']:
|
||||
cmd += mozconfig['configure_args']
|
||||
|
||||
for key, value in mozconfig['env']['added'].items():
|
||||
print("export %s=%s" % (key, quote(value)), file=out)
|
||||
for key, (old, value) in mozconfig['env']['modified'].items():
|
||||
print("export %s=%s" % (key, quote(value)), file=out)
|
||||
for key, value in mozconfig['vars']['added'].items():
|
||||
print("%s=%s" % (key, quote(value)), file=out)
|
||||
for key, (old, value) in mozconfig['vars']['modified'].items():
|
||||
print("%s=%s" % (key, quote(value)), file=out)
|
||||
for t in ('env', 'vars'):
|
||||
for key in mozconfig[t]['removed'].keys():
|
||||
print("unset %s" % key, file=out)
|
||||
|
||||
print('PYTHON=%s' % quote(python), file=out)
|
||||
if compile_env:
|
||||
print('COMPILE_ENVIRONMENT=1', file=out)
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
@template
|
||||
def old_configure_options(*options):
|
||||
for opt in options:
|
||||
option(opt, nargs='*', help='Help missing for old configure options')
|
||||
|
||||
@depends('--help')
|
||||
def all_options(help):
|
||||
return set(options)
|
||||
|
||||
return depends(prepare_configure, all_options, *options)
|
||||
|
||||
|
||||
@old_configure_options(
|
||||
'--cache-file',
|
||||
'--enable-accessibility',
|
||||
'--enable-address-sanitizer',
|
||||
'--enable-alsa',
|
||||
'--enable-android-apz',
|
||||
'--enable-android-omx',
|
||||
'--enable-android-resource-constrained',
|
||||
'--enable-application',
|
||||
'--enable-approximate-location',
|
||||
'--enable-b2g-bt',
|
||||
'--enable-b2g-camera',
|
||||
'--enable-b2g-ril',
|
||||
'--enable-bundled-fonts',
|
||||
'--enable-callgrind',
|
||||
'--enable-chrome-format',
|
||||
'--enable-clang-plugin',
|
||||
'--enable-content-sandbox',
|
||||
'--enable-cookies',
|
||||
'--enable-cpp-rtti',
|
||||
'--enable-crashreporter',
|
||||
'--enable-ctypes',
|
||||
'--enable-dbm',
|
||||
'--enable-dbus',
|
||||
'--enable-debug',
|
||||
'--enable-debug-js-modules',
|
||||
'--enable-debug-symbols',
|
||||
'--enable-default-toolkit',
|
||||
'--enable-directshow',
|
||||
'--enable-dmd',
|
||||
'--enable-dtrace',
|
||||
'--enable-dump-painting',
|
||||
'--enable-elf-hack',
|
||||
'--enable-eme',
|
||||
'--enable-export-js',
|
||||
'--enable-extensions',
|
||||
'--enable-faststripe',
|
||||
'--enable-feeds',
|
||||
'--enable-ffmpeg',
|
||||
'--enable-fmp4',
|
||||
'--enable-gamepad',
|
||||
'--enable-gc-trace',
|
||||
'--enable-gconf',
|
||||
'--enable-gczeal',
|
||||
'--enable-gio',
|
||||
'--enable-gnomeui',
|
||||
'--enable-gold',
|
||||
'--enable-gps-debug',
|
||||
'--enable-hardware-aec-ns',
|
||||
'--enable-icf',
|
||||
'--enable-install-strip',
|
||||
'--enable-instruments',
|
||||
'--enable-ion',
|
||||
'--enable-ios-target',
|
||||
'--enable-ipdl-tests',
|
||||
'--enable-jemalloc',
|
||||
'--enable-jitspew',
|
||||
'--enable-jprof',
|
||||
'--enable-libjpeg-turbo',
|
||||
'--enable-libproxy',
|
||||
'--enable-llvm-hacks',
|
||||
'--enable-logrefcnt',
|
||||
'--enable-macos-target',
|
||||
'--enable-maintenance-service',
|
||||
'--enable-media-navigator',
|
||||
'--enable-memory-sanitizer',
|
||||
'--enable-mobile-optimize',
|
||||
'--enable-more-deterministic',
|
||||
'--enable-mozril-geoloc',
|
||||
'--enable-necko-protocols',
|
||||
'--enable-necko-wifi',
|
||||
'--enable-negotiateauth',
|
||||
'--enable-nfc',
|
||||
'--enable-nspr-build',
|
||||
'--enable-official-branding',
|
||||
'--enable-omx-plugin',
|
||||
'--enable-oom-breakpoint',
|
||||
'--enable-optimize',
|
||||
'--enable-parental-controls',
|
||||
'--enable-perf',
|
||||
'--enable-permissions',
|
||||
'--enable-pie',
|
||||
'--enable-png-arm-neon-support',
|
||||
'--enable-posix-nspr-emulation',
|
||||
'--enable-pref-extensions',
|
||||
'--enable-printing',
|
||||
'--enable-profilelocking',
|
||||
'--enable-profiling',
|
||||
'--enable-pulseaudio',
|
||||
'--enable-raw',
|
||||
'--enable-readline',
|
||||
'--enable-reflow-perf',
|
||||
'--enable-release',
|
||||
'--enable-replace-malloc',
|
||||
'--enable-require-all-d3dc-versions',
|
||||
'--enable-rust',
|
||||
'--enable-safe-browsing',
|
||||
'--enable-sandbox',
|
||||
'--enable-shared-js',
|
||||
'--enable-signmar',
|
||||
'--enable-simulator',
|
||||
'--enable-skia',
|
||||
'--enable-skia-gpu',
|
||||
'--enable-small-chunk-size',
|
||||
'--enable-startup-notification',
|
||||
'--enable-startupcache',
|
||||
'--enable-stdcxx-compat',
|
||||
'--enable-strip',
|
||||
'--enable-synth-pico',
|
||||
'--enable-synth-speechd',
|
||||
'--enable-system-cairo',
|
||||
'--enable-system-extension-dirs',
|
||||
'--enable-system-ffi',
|
||||
'--enable-system-hunspell',
|
||||
'--enable-system-pixman',
|
||||
'--enable-system-sqlite',
|
||||
'--enable-systrace',
|
||||
'--enable-tasktracer',
|
||||
'--enable-tests',
|
||||
'--enable-thread-sanitizer',
|
||||
'--enable-trace-logging',
|
||||
'--enable-tree-freetype',
|
||||
'--enable-ui-locale',
|
||||
'--enable-universalchardet',
|
||||
'--enable-update-channel',
|
||||
'--enable-update-packaging',
|
||||
'--enable-updater',
|
||||
'--enable-url-classifier',
|
||||
'--enable-valgrind',
|
||||
'--enable-verify-mar',
|
||||
'--enable-vtune',
|
||||
'--enable-warnings-as-errors',
|
||||
'--enable-webapp-runtime',
|
||||
'--enable-webrtc',
|
||||
'--enable-websms-backend',
|
||||
'--enable-webspeech',
|
||||
'--enable-webspeechtestbackend',
|
||||
'--enable-wmf',
|
||||
'--enable-xterm-updates',
|
||||
'--enable-xul',
|
||||
'--enable-zipwriter',
|
||||
'--host',
|
||||
'--no-create',
|
||||
'--prefix',
|
||||
'--target',
|
||||
'--with-adjust-sdk-keyfile',
|
||||
'--with-android-cxx-stl',
|
||||
'--with-android-distribution-directory',
|
||||
'--with-android-gnu-compiler-version',
|
||||
'--with-android-max-sdk',
|
||||
'--with-android-min-sdk',
|
||||
'--with-android-ndk',
|
||||
'--with-android-sdk',
|
||||
'--with-android-toolchain',
|
||||
'--with-android-version',
|
||||
'--with-app-basename',
|
||||
'--with-app-name',
|
||||
'--with-arch',
|
||||
'--with-arm-kuser',
|
||||
'--with-bing-api-keyfile',
|
||||
'--with-branding',
|
||||
'--with-ccache',
|
||||
'--with-compiler-wrapper',
|
||||
'--with-crashreporter-enable-percent',
|
||||
'--with-cross-lib',
|
||||
'--with-debug-label',
|
||||
'--with-default-mozilla-five-home',
|
||||
'--with-distribution-id',
|
||||
'--with-doc-include-dirs',
|
||||
'--with-doc-input-dirs',
|
||||
'--with-doc-output-dir',
|
||||
'--with-external-source-dir',
|
||||
'--with-float-abi',
|
||||
'--with-fpu',
|
||||
'--with-gl-provider',
|
||||
'--with-gonk',
|
||||
'--with-gonk-toolchain-prefix',
|
||||
'--with-google-api-keyfile',
|
||||
'--with-google-oauth-api-keyfile',
|
||||
'--with-gradle',
|
||||
'--with-intl-api',
|
||||
'--with-ios-sdk',
|
||||
'--with-java-bin-path',
|
||||
'--with-jitreport-granularity',
|
||||
'--with-l10n-base',
|
||||
'--with-libxul-sdk',
|
||||
'--with-linux-headers',
|
||||
'--with-macbundlename-prefix',
|
||||
'--with-macos-private-frameworks',
|
||||
'--with-macos-sdk',
|
||||
'--with-mozilla-api-keyfile',
|
||||
'--with-nspr-cflags',
|
||||
'--with-nspr-libs',
|
||||
'--with-pthreads',
|
||||
'--with-qemu-exe',
|
||||
'--with-qtdir',
|
||||
'--with-servo',
|
||||
'--with-sixgill',
|
||||
'--with-soft-float',
|
||||
'--with-system-bz2',
|
||||
'--with-system-icu',
|
||||
'--with-system-jpeg',
|
||||
'--with-system-libevent',
|
||||
'--with-system-libvpx',
|
||||
'--with-system-nspr',
|
||||
'--with-system-nss',
|
||||
'--with-system-png',
|
||||
'--with-system-zlib',
|
||||
'--with-thumb',
|
||||
'--with-thumb-interwork',
|
||||
'--with-unify-dist',
|
||||
'--with-user-appdir',
|
||||
'--with-windows-version',
|
||||
'--with-x',
|
||||
'--with-xulrunner-stub-name',
|
||||
'--x-includes',
|
||||
'--x-libraries',
|
||||
)
|
||||
@advanced
|
||||
def old_configure(prepare_configure, all_options, *options):
|
||||
import codecs
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import types
|
||||
|
||||
ret = subprocess.call(prepare_configure)
|
||||
if ret:
|
||||
sys.exit(ret)
|
||||
|
||||
raw_config = {}
|
||||
encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
|
||||
with codecs.open('config.data', 'r', encoding) as fh:
|
||||
code = compile(fh.read(), 'config.data', 'exec')
|
||||
# Every variation of the exec() function I tried led to:
|
||||
# SyntaxError: unqualified exec is not allowed in function 'main' it
|
||||
# contains a nested function with free variables
|
||||
exec code in raw_config
|
||||
|
||||
# Ensure all the flags known to old-configure appear in the
|
||||
# @old_configure_options above.
|
||||
for flag in raw_config['flags']:
|
||||
if flag not in all_options:
|
||||
error('Missing option in `@old_configure_options` in %s: %s'
|
||||
% (__file__, flag))
|
||||
|
||||
# If the code execution above fails, we want to keep the file around for
|
||||
# debugging.
|
||||
os.remove('config.data')
|
||||
|
||||
config = {}
|
||||
for k, v in raw_config['substs']:
|
||||
set_config(k[1:-1], v[1:-1] if isinstance(v, types.StringTypes) else v)
|
||||
|
||||
for k, v in dict(raw_config['defines']).iteritems():
|
||||
set_define(k[1:-1], v[1:-1])
|
||||
|
||||
set_config('non_global_defines', raw_config['non_global_defines'])
|
|
@ -0,0 +1,78 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
@template
|
||||
@advanced
|
||||
def warn(*args):
|
||||
import sys
|
||||
print(*args, file=sys.stderr)
|
||||
sys.stderr.flush()
|
||||
|
||||
|
||||
@template
|
||||
@advanced
|
||||
def error(*args):
|
||||
import sys
|
||||
print(*args, file=sys.stderr)
|
||||
sys.stderr.flush()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@template
|
||||
@advanced
|
||||
def is_absolute_or_relative(path):
|
||||
import os
|
||||
if os.altsep and os.altsep in path:
|
||||
return True
|
||||
return os.sep in path
|
||||
|
||||
|
||||
@template
|
||||
@advanced
|
||||
def normsep(path):
|
||||
import mozpack.path as mozpath
|
||||
return mozpath.normsep(path)
|
||||
|
||||
|
||||
@template
|
||||
@advanced
|
||||
def find_program(file):
|
||||
if is_absolute_or_relative(file):
|
||||
return os.path.abspath(file) if os.path.isfile(file) else None
|
||||
from which import which, WhichError
|
||||
try:
|
||||
return normsep(which(file))
|
||||
except WhichError:
|
||||
return None
|
||||
|
||||
|
||||
@depends('--help')
|
||||
def _defines(help):
|
||||
ret = {}
|
||||
set_config('DEFINES', ret)
|
||||
return ret
|
||||
|
||||
|
||||
@template
|
||||
def set_define(name, value):
|
||||
@depends(_defines)
|
||||
@advanced
|
||||
def _add_define(defines):
|
||||
from mozbuild.configure import ConfigureError
|
||||
if name in defines:
|
||||
raise ConfigureError("'%s' is already defined" % name)
|
||||
defines[name] = value
|
||||
|
||||
del _defines
|
||||
|
||||
|
||||
@template
|
||||
def unique_list(l):
|
||||
result = []
|
||||
for i in l:
|
||||
if l not in result:
|
||||
result.append(i)
|
||||
return result
|
|
@ -10,4 +10,4 @@
|
|||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
47.0a1
|
||||
48.0a1
|
||||
|
|
|
@ -1550,9 +1550,6 @@ libs export::
|
|||
$(CHECK_FROZEN_VARIABLES)
|
||||
|
||||
PURGECACHES_DIRS ?= $(DIST)/bin
|
||||
ifdef MOZ_WEBAPP_RUNTIME
|
||||
PURGECACHES_DIRS += $(DIST)/bin/webapprt
|
||||
endif
|
||||
|
||||
PURGECACHES_FILES = $(addsuffix /.purgecaches,$(PURGECACHES_DIRS))
|
||||
|
||||
|
|
156
configure.py
156
configure.py
|
@ -4,120 +4,70 @@
|
|||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import glob
|
||||
import itertools
|
||||
import codecs
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
|
||||
base_dir = os.path.dirname(__file__)
|
||||
sys.path.append(os.path.join(base_dir, 'python', 'which'))
|
||||
|
||||
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
sys.path.append(os.path.join(base_dir, 'python', 'mozbuild'))
|
||||
from which import which, WhichError
|
||||
from mozbuild.mozconfig import MozconfigLoader
|
||||
from mozbuild.configure import ConfigureSandbox
|
||||
|
||||
|
||||
# If feel dirty replicating this from python/mozbuild/mozbuild/mozconfig.py,
|
||||
# but the end goal being that the configure script would go away...
|
||||
shell = 'sh'
|
||||
if 'MOZILLABUILD' in os.environ:
|
||||
shell = os.environ['MOZILLABUILD'] + '/msys/bin/sh'
|
||||
if sys.platform == 'win32':
|
||||
shell = shell + '.exe'
|
||||
def main(argv):
|
||||
config = {}
|
||||
sandbox = ConfigureSandbox(config, os.environ, argv)
|
||||
sandbox.run(os.path.join(os.path.dirname(__file__), 'moz.configure'))
|
||||
|
||||
if sandbox._help:
|
||||
return 0
|
||||
|
||||
def is_absolute_or_relative(path):
|
||||
if os.altsep and os.altsep in path:
|
||||
return True
|
||||
return os.sep in path
|
||||
# Sanitize config data to feed config.status
|
||||
sanitized_config = {}
|
||||
sanitized_config['substs'] = {
|
||||
k: v for k, v in config.iteritems()
|
||||
if k not in ('DEFINES', 'non_global_defines', 'TOPSRCDIR', 'TOPOBJDIR')
|
||||
}
|
||||
sanitized_config['defines'] = config['DEFINES']
|
||||
sanitized_config['non_global_defines'] = config['non_global_defines']
|
||||
sanitized_config['topsrcdir'] = config['TOPSRCDIR']
|
||||
sanitized_config['topobjdir'] = config['TOPOBJDIR']
|
||||
|
||||
# Create config.status. Eventually, we'll want to just do the work it does
|
||||
# here, when we're able to skip configure tests/use cached results/not rely
|
||||
# on autoconf.
|
||||
print("Creating config.status", file=sys.stderr)
|
||||
encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
|
||||
with codecs.open('config.status', 'w', encoding) as fh:
|
||||
fh.write('#!%s\n' % config['PYTHON'])
|
||||
fh.write('# coding=%s\n' % encoding)
|
||||
for k, v in sanitized_config.iteritems():
|
||||
fh.write('%s = ' % k)
|
||||
json.dump(v, fh, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
fh.write('\n')
|
||||
fh.write("__all__ = ['topobjdir', 'topsrcdir', 'defines', "
|
||||
"'non_global_defines', 'substs']")
|
||||
|
||||
def find_program(file):
|
||||
if is_absolute_or_relative(file):
|
||||
return os.path.abspath(file) if os.path.isfile(file) else None
|
||||
try:
|
||||
return which(file)
|
||||
except WhichError:
|
||||
return None
|
||||
|
||||
|
||||
def autoconf_refresh(configure):
|
||||
if os.path.exists(configure):
|
||||
mtime = os.path.getmtime(configure)
|
||||
aclocal = os.path.join(base_dir, 'build', 'autoconf', '*.m4')
|
||||
for input in itertools.chain(
|
||||
(configure + '.in',
|
||||
os.path.join(os.path.dirname(configure), 'aclocal.m4')),
|
||||
glob.iglob(aclocal),
|
||||
):
|
||||
if os.path.getmtime(input) > mtime:
|
||||
break
|
||||
else:
|
||||
return
|
||||
|
||||
mozconfig_autoconf = None
|
||||
configure_dir = os.path.dirname(configure)
|
||||
# Don't read the mozconfig for the js configure (yay backwards
|
||||
# compatibility)
|
||||
if not configure_dir.replace(os.sep, '/').endswith('/js/src'):
|
||||
loader = MozconfigLoader(os.path.dirname(configure))
|
||||
project = os.environ.get('MOZ_CURRENT_PROJECT')
|
||||
mozconfig = loader.find_mozconfig(env=os.environ)
|
||||
mozconfig = loader.read_mozconfig(mozconfig, moz_build_app=project)
|
||||
make_extra = mozconfig['make_extra']
|
||||
if make_extra:
|
||||
for assignment in make_extra:
|
||||
m = re.match('(?:export\s+)?AUTOCONF\s*:?=\s*(.+)$',
|
||||
assignment)
|
||||
if m:
|
||||
mozconfig_autoconf = m.group(1)
|
||||
|
||||
for ac in (mozconfig_autoconf, os.environ.get('AUTOCONF'), 'autoconf-2.13',
|
||||
'autoconf2.13', 'autoconf213'):
|
||||
if ac:
|
||||
autoconf = find_program(ac)
|
||||
if autoconf:
|
||||
break
|
||||
else:
|
||||
fink = find_program('fink')
|
||||
if fink:
|
||||
autoconf = os.path.normpath(os.path.join(
|
||||
fink, '..', '..', 'lib', 'autoconf2.13', 'bin', 'autoconf'))
|
||||
|
||||
if not autoconf:
|
||||
raise RuntimeError('Could not find autoconf 2.13')
|
||||
|
||||
# Add or adjust AUTOCONF for subprocesses, especially the js/src configure
|
||||
os.environ['AUTOCONF'] = autoconf
|
||||
|
||||
print('Refreshing %s with %s' % (configure, autoconf), file=sys.stderr)
|
||||
|
||||
with open(configure, 'wb') as fh:
|
||||
subprocess.check_call([
|
||||
shell, autoconf, '--localdir=%s' % os.path.dirname(configure),
|
||||
configure + '.in'], stdout=fh)
|
||||
|
||||
|
||||
def main(args):
|
||||
old_configure = os.environ.get('OLD_CONFIGURE')
|
||||
|
||||
if not old_configure:
|
||||
raise Exception('The OLD_CONFIGURE environment variable must be set')
|
||||
|
||||
# We need to replace backslashes with forward slashes on Windows because
|
||||
# this path actually ends up literally as $0, which breaks autoconf's
|
||||
# detection of the source directory.
|
||||
old_configure = os.path.abspath(old_configure).replace(os.sep, '/')
|
||||
|
||||
try:
|
||||
autoconf_refresh(old_configure)
|
||||
except RuntimeError as e:
|
||||
print(e.message, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
return subprocess.call([shell, old_configure] + args)
|
||||
if not config.get('BUILDING_JS') or config.get('JS_STANDALONE'):
|
||||
fh.write('''
|
||||
if __name__ == '__main__':
|
||||
args = dict([(name, globals()[name]) for name in __all__])
|
||||
from mozbuild.config_status import config_status
|
||||
config_status(**args)
|
||||
''')
|
||||
|
||||
# Other things than us are going to run this file, so we need to give it
|
||||
# executable permissions.
|
||||
os.chmod('config.status', 0755)
|
||||
if not config.get('BUILDING_JS') or config.get('JS_STANDALONE'):
|
||||
if not config.get('JS_STANDALONE'):
|
||||
os.environ['WRITE_MOZINFO'] = '1'
|
||||
# Until we have access to the virtualenv from this script, execute
|
||||
# config.status externally, with the virtualenv python.
|
||||
return subprocess.call([config['PYTHON'], 'config.status'])
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
sys.exit(main(sys.argv))
|
||||
|
|
|
@ -888,7 +888,7 @@ WebConsoleActor.prototype =
|
|||
error.unsafeDereference();
|
||||
errorMessage = unsafeDereference && unsafeDereference.toString
|
||||
? unsafeDereference.toString()
|
||||
: "" + error;
|
||||
: String(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,12 +85,6 @@ function setup() {
|
|||
Components.utils.import('resource://gre/modules/Webapps.jsm');
|
||||
DOMApplicationRegistry.allAppsLaunchable = true;
|
||||
|
||||
// Mock WebappOSUtils
|
||||
Cu.import("resource://gre/modules/WebappOSUtils.jsm");
|
||||
WebappOSUtils.getPackagePath = function(aApp) {
|
||||
return aApp.basePath + "/" + aApp.id;
|
||||
}
|
||||
|
||||
// Enable launch/close method of the webapps actor
|
||||
let {WebappsActor} = require("devtools/server/actors/webapps");
|
||||
WebappsActor.prototype.supportsLaunch = true;
|
||||
|
|
|
@ -62,6 +62,21 @@ function onAttach(aState, aResponse)
|
|||
});
|
||||
});
|
||||
|
||||
let symbolTestValues = [
|
||||
["Symbol.iterator", "Symbol(Symbol.iterator)"],
|
||||
["Symbol('foo')", "Symbol(foo)"],
|
||||
["Symbol()", "Symbol()"],
|
||||
];
|
||||
symbolTestValues.forEach(function([expr, message]) {
|
||||
tests.push(function() {
|
||||
aState.client.evaluateJS("throw " + expr + ";", function(aResponse) {
|
||||
is(aResponse.exceptionMessage, message,
|
||||
"response.exception for throw " + expr);
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
runTests(tests, endTest.bind(null, aState));
|
||||
}
|
||||
|
||||
|
|
|
@ -3498,6 +3498,11 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes().mUserContextId !=
|
||||
static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes().mUserContextId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A private document can't access a non-private one, and vice versa.
|
||||
if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
|
||||
static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
|
||||
|
@ -14191,7 +14196,9 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
|
|||
if (aIsNonSubresourceRequest) {
|
||||
PrincipalOriginAttributes attrs;
|
||||
attrs.InheritFromDocShellToDoc(mOriginAttributes, aURI);
|
||||
*aShouldIntercept = swm->IsAvailable(attrs, aURI);
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
|
||||
*aShouldIntercept = swm->IsAvailable(principal, aURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,9 +68,9 @@ CSSPseudoElement::Animate(
|
|||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
// Bug 1241784: Implement this API.
|
||||
NS_NOTREACHED("CSSPseudoElement::Animate() is not implemented yet.");
|
||||
return nullptr;
|
||||
Nullable<ElementOrCSSPseudoElement> target;
|
||||
target.SetValue().SetAsCSSPseudoElement() = this;
|
||||
return Element::Animate(target, aContext, aFrames, aOptions, aError);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<CSSPseudoElement>
|
||||
|
|
|
@ -34,8 +34,8 @@ public:
|
|||
EffectSet()
|
||||
: mCascadeNeedsUpdate(false)
|
||||
, mAnimationGeneration(0)
|
||||
, mActiveIterators(0)
|
||||
#ifdef DEBUG
|
||||
, mActiveIterators(0)
|
||||
, mCalledPropertyDtor(false)
|
||||
#endif
|
||||
{
|
||||
|
@ -87,7 +87,9 @@ public:
|
|||
, mHashIterator(mozilla::Move(aEffectSet.mEffects.Iter()))
|
||||
, mIsEndIterator(false)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mEffectSet.mActiveIterators++;
|
||||
#endif
|
||||
}
|
||||
|
||||
Iterator(Iterator&& aOther)
|
||||
|
@ -95,7 +97,9 @@ public:
|
|||
, mHashIterator(mozilla::Move(aOther.mHashIterator))
|
||||
, mIsEndIterator(aOther.mIsEndIterator)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mEffectSet.mActiveIterators++;
|
||||
#endif
|
||||
}
|
||||
|
||||
static Iterator EndIterator(EffectSet& aEffectSet)
|
||||
|
@ -107,8 +111,10 @@ public:
|
|||
|
||||
~Iterator()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(mEffectSet.mActiveIterators > 0);
|
||||
mEffectSet.mActiveIterators--;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool operator!=(const Iterator& aOther) const {
|
||||
|
@ -221,11 +227,11 @@ private:
|
|||
// the animation manager.
|
||||
uint64_t mAnimationGeneration;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Track how many iterators are referencing this effect set when we are
|
||||
// destroyed, we can assert that nothing is still pointing to us.
|
||||
DebugOnly<uint64_t> mActiveIterators;
|
||||
uint64_t mActiveIterators;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mCalledPropertyDtor;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -16,9 +16,6 @@ Cu.import("resource://gre/modules/Promise.jsm");
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
|
||||
"resource://gre/modules/WebappOSUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
|
@ -385,7 +382,7 @@ this.AppsUtils = {
|
|||
"isCoreApp": isCoreApp };
|
||||
}
|
||||
|
||||
return { "path": WebappOSUtils.getPackagePath(app),
|
||||
return { "path": app.basePath + "/" + app.id,
|
||||
"isCoreApp": isCoreApp };
|
||||
},
|
||||
|
||||
|
|
|
@ -73,9 +73,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "OfflineCacheInstaller",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "SystemMessagePermissionsChecker",
|
||||
"resource://gre/modules/SystemMessagePermissionsChecker.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
|
||||
"resource://gre/modules/WebappOSUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
|
@ -135,9 +132,7 @@ function supportSystemMessages() {
|
|||
// Minimum delay between two progress events while downloading, in ms.
|
||||
const MIN_PROGRESS_EVENT_DELAY = 1500;
|
||||
|
||||
const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
|
||||
|
||||
const chromeWindowType = WEBAPP_RUNTIME ? "webapprt:webapp" : "navigator:browser";
|
||||
const chromeWindowType = "navigator:browser";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
|
@ -180,10 +175,8 @@ XPCOMUtils.defineLazyGetter(this, "permMgr", function() {
|
|||
#elifdef ANDROID
|
||||
const DIRECTORY_NAME = "webappsDir";
|
||||
#else
|
||||
// If we're executing in the context of the webapp runtime, the data files
|
||||
// are in a different directory (currently the Firefox profile that installed
|
||||
// the webapp); otherwise, they're in the current profile.
|
||||
const DIRECTORY_NAME = WEBAPP_RUNTIME ? "WebappRegD" : "ProfD";
|
||||
// Mulet, B2G Desktop, etc.
|
||||
const DIRECTORY_NAME = "ProfD";
|
||||
#endif
|
||||
|
||||
// We'll use this to identify privileged apps that have been preinstalled
|
||||
|
@ -2998,7 +2991,7 @@ this.DOMApplicationRegistry = {
|
|||
app.manifestHash = AppsUtils.computeHash(JSON.stringify(aUpdateManifest ||
|
||||
aManifest));
|
||||
|
||||
let zipFile = WebappOSUtils.getPackagePath(app);
|
||||
let zipFile = app.basePath + "/" + app.id;
|
||||
app.packageHash = yield this._computeFileHash(zipFile);
|
||||
|
||||
app.role = aManifest.role || "";
|
||||
|
@ -4811,10 +4804,7 @@ this.DOMApplicationRegistry = {
|
|||
},
|
||||
|
||||
_isLaunchable: function(aApp) {
|
||||
if (this.allAppsLaunchable)
|
||||
return true;
|
||||
|
||||
return WebappOSUtils.isLaunchable(aApp);
|
||||
return true;
|
||||
},
|
||||
|
||||
_notifyCategoryAndObservers: function(subject, topic, data, msg) {
|
||||
|
|
|
@ -19,19 +19,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
|||
const gSJS = gBaseURL + 'file_bug_945152.sjs';
|
||||
var gGenerator = runTest();
|
||||
|
||||
// When using SpecialPowers.autoConfirmAppInstall, it skips the local
|
||||
// installation, and we need this mock to get correct package path.
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/WebappOSUtils.jsm");
|
||||
var oldWebappOSUtils = WebappOSUtils;
|
||||
WebappOSUtils.getPackagePath = function(aApp) {
|
||||
return aApp.basePath + "/" + aApp.id;
|
||||
}
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
WebappOSUtils = oldWebappOSUtils;
|
||||
});
|
||||
|
||||
function go() {
|
||||
gGenerator.next();
|
||||
}
|
||||
|
|
|
@ -23,20 +23,12 @@ const gSJS = gBaseURL + 'asmjs_app.sjs';
|
|||
const gManifestURL = gSJS + '?getManifest=true';
|
||||
let gGenerator = runTest();
|
||||
|
||||
// Mock WebappOSUtils
|
||||
Cu.import("resource://gre/modules/WebappOSUtils.jsm");
|
||||
let oldWebappOSUtils = WebappOSUtils;
|
||||
WebappOSUtils.getPackagePath = function(aApp) {
|
||||
return aApp.basePath + "/" + aApp.id;
|
||||
}
|
||||
|
||||
// Enable the ScriptPreloader module
|
||||
Cu.import("resource://gre/modules/ScriptPreloader.jsm");
|
||||
let oldScriptPreloaderEnabled = ScriptPreloader._enabled;
|
||||
ScriptPreloader._enabled = true;
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
WebappOSUtils = oldWebappOSUtils;
|
||||
ScriptPreloader._enabled = oldScriptPreloaderEnabled;
|
||||
});
|
||||
|
||||
|
|
|
@ -137,13 +137,15 @@
|
|||
#include "nsITextControlElement.h"
|
||||
#include "nsITextControlFrame.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/dom/CSSPseudoElement.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/VRDevice.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -3307,7 +3309,31 @@ Element::Animate(JSContext* aContext,
|
|||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> ownerGlobal = GetOwnerGlobal();
|
||||
Nullable<ElementOrCSSPseudoElement> target;
|
||||
target.SetValue().SetAsElement() = this;
|
||||
return Animate(target, aContext, aFrames, aOptions, aError);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Animation>
|
||||
Element::Animate(const Nullable<ElementOrCSSPseudoElement>& aTarget,
|
||||
JSContext* aContext,
|
||||
JS::Handle<JSObject*> aFrames,
|
||||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(!aTarget.IsNull() &&
|
||||
(aTarget.Value().IsElement() ||
|
||||
aTarget.Value().IsCSSPseudoElement()),
|
||||
"aTarget should be initialized");
|
||||
|
||||
RefPtr<Element> referenceElement;
|
||||
if (aTarget.Value().IsElement()) {
|
||||
referenceElement = &aTarget.Value().GetAsElement();
|
||||
} else {
|
||||
referenceElement = aTarget.Value().GetAsCSSPseudoElement().ParentElement();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> ownerGlobal = referenceElement->GetOwnerGlobal();
|
||||
if (!ownerGlobal) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
|
@ -3327,17 +3353,16 @@ Element::Animate(JSContext* aContext,
|
|||
}
|
||||
}
|
||||
|
||||
Nullable<ElementOrCSSPseudoElement> target;
|
||||
target.SetValue().SetAsElement() = this;
|
||||
RefPtr<KeyframeEffect> effect =
|
||||
KeyframeEffect::Constructor(global, target, frames,
|
||||
TimingParams::FromOptionsUnion(aOptions, target), aError);
|
||||
KeyframeEffect::Constructor(global, aTarget, frames,
|
||||
TimingParams::FromOptionsUnion(aOptions, aTarget), aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Animation> animation =
|
||||
Animation::Constructor(global, effect, OwnerDoc()->Timeline(), aError);
|
||||
Animation::Constructor(global, effect,
|
||||
referenceElement->OwnerDoc()->Timeline(), aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "Units.h"
|
||||
|
||||
class nsIFrame;
|
||||
|
@ -56,6 +57,7 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
struct ScrollIntoViewOptions;
|
||||
struct ScrollToOptions;
|
||||
class ElementOrCSSPseudoElement;
|
||||
class UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -826,11 +828,20 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
already_AddRefed<Animation> Animate(
|
||||
JSContext* aContext,
|
||||
JS::Handle<JSObject*> aFrames,
|
||||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aError);
|
||||
already_AddRefed<Animation>
|
||||
Animate(JSContext* aContext,
|
||||
JS::Handle<JSObject*> aFrames,
|
||||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aError);
|
||||
|
||||
// A helper method that factors out the common functionality needed by
|
||||
// Element::Animate and CSSPseudoElement::Animate
|
||||
static already_AddRefed<Animation>
|
||||
Animate(const Nullable<ElementOrCSSPseudoElement>& aTarget,
|
||||
JSContext* aContext,
|
||||
JS::Handle<JSObject*> aFrames,
|
||||
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
|
||||
ErrorResult& aError);
|
||||
|
||||
// Note: GetAnimations will flush style while GetAnimationsUnsorted won't.
|
||||
void GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations);
|
||||
|
|
|
@ -104,8 +104,8 @@ SubtleCrypto::ImportKey(JSContext* cx,
|
|||
const Sequence<nsString>& keyUsages,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SUBTLECRYPTO_METHOD_BODY(ImportKey, aRv, cx, format, keyData, algorithm,
|
||||
extractable, keyUsages)
|
||||
SUBTLECRYPTO_METHOD_BODY(ImportKey, aRv, mParent, cx, format, keyData,
|
||||
algorithm, extractable, keyUsages)
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
|
@ -121,7 +121,8 @@ SubtleCrypto::GenerateKey(JSContext* cx, const ObjectOrString& algorithm,
|
|||
bool extractable, const Sequence<nsString>& keyUsages,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SUBTLECRYPTO_METHOD_BODY(GenerateKey, aRv, cx, algorithm, extractable, keyUsages)
|
||||
SUBTLECRYPTO_METHOD_BODY(GenerateKey, aRv, mParent, cx, algorithm,
|
||||
extractable, keyUsages)
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
|
@ -132,7 +133,7 @@ SubtleCrypto::DeriveKey(JSContext* cx,
|
|||
bool extractable, const Sequence<nsString>& keyUsages,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SUBTLECRYPTO_METHOD_BODY(DeriveKey, aRv, cx, algorithm, baseKey,
|
||||
SUBTLECRYPTO_METHOD_BODY(DeriveKey, aRv, mParent, cx, algorithm, baseKey,
|
||||
derivedKeyType, extractable, keyUsages)
|
||||
}
|
||||
|
||||
|
@ -168,9 +169,9 @@ SubtleCrypto::UnwrapKey(JSContext* cx,
|
|||
const Sequence<nsString>& keyUsages,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SUBTLECRYPTO_METHOD_BODY(UnwrapKey, aRv, cx, format, wrappedKey, unwrappingKey,
|
||||
unwrapAlgorithm, unwrappedKeyAlgorithm,
|
||||
extractable, keyUsages)
|
||||
SUBTLECRYPTO_METHOD_BODY(UnwrapKey, aRv, mParent, cx, format, wrappedKey,
|
||||
unwrappingKey, unwrapAlgorithm,
|
||||
unwrappedKeyAlgorithm, extractable, keyUsages)
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -486,7 +486,7 @@ public:
|
|||
*
|
||||
* https://dom.spec.whatwg.org/#dom-node-ownerdocument
|
||||
*
|
||||
* For all other cases GetOwnerDoc and GetOwnerDocument behave identically.
|
||||
* For all other cases OwnerDoc and GetOwnerDocument behave identically.
|
||||
*/
|
||||
nsIDocument *OwnerDoc() const
|
||||
{
|
||||
|
|
|
@ -261,6 +261,7 @@ support-files =
|
|||
file_bug1250148.sjs
|
||||
mozbrowser_api_utils.js
|
||||
websocket_helpers.js
|
||||
websocket_tests.js
|
||||
|
||||
[test_anonymousContent_api.html]
|
||||
[test_anonymousContent_append_after_reflow.html]
|
||||
|
|
|
@ -5,242 +5,12 @@
|
|||
<title>WebSocket test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="websocket_helpers.js"></script>
|
||||
<script type="text/javascript" src="websocket_tests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="testWebSocket()">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function test1() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var ws = CreateTestWS("http://mochi.test:8888/tests/dom/base/test/file_websocket");
|
||||
ok(false, "test1 failed");
|
||||
} catch (e) {
|
||||
ok(true, "test1 failed");
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
// this test expects that the serialization list to connect to the proxy
|
||||
// is empty.
|
||||
function test2() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var waitTest2Part1 = true;
|
||||
var waitTest2Part2 = true;
|
||||
|
||||
var ws1 = CreateTestWS("ws://sub2.test2.example.com/tests/dom/base/test/file_websocket", "test-2.1");
|
||||
var ws2 = CreateTestWS("ws://sub2.test2.example.com/tests/dom/base/test/file_websocket", "test-2.2");
|
||||
|
||||
var ws2CanConnect = false;
|
||||
|
||||
function maybeFinished() {
|
||||
if (!waitTest2Part1 && !waitTest2Part2) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
ws1.onopen = function() {
|
||||
ok(true, "ws1 open in test 2");
|
||||
ws2CanConnect = true;
|
||||
ws1.close();
|
||||
}
|
||||
|
||||
ws1.onclose = function(e) {
|
||||
waitTest2Part1 = false;
|
||||
maybeFinished();
|
||||
}
|
||||
|
||||
ws2.onopen = function() {
|
||||
ok(ws2CanConnect, "shouldn't connect yet in test-2!");
|
||||
ws2.close();
|
||||
}
|
||||
|
||||
ws2.onclose = function(e) {
|
||||
waitTest2Part2 = false;
|
||||
maybeFinished();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test3() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var hasError = false;
|
||||
var ws = CreateTestWS("ws://this.websocket.server.probably.does.not.exist");
|
||||
|
||||
ws.onopen = shouldNotOpen;
|
||||
|
||||
ws.onerror = function (e) {
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseNotCleanly(e);
|
||||
ok(hasError, "rcvd onerror event");
|
||||
is(e.code, 1006, "test-3 close code should be 1006 but is:" + e.code);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test4() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var ws = CreateTestWS("file_websocket");
|
||||
ok(false, "test-4 failed");
|
||||
} catch (e) {
|
||||
ok(true, "test-4 failed");
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function test5() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "");
|
||||
ok(false, "couldn't accept an empty string in the protocol parameter");
|
||||
} catch (e) {
|
||||
ok(true, "couldn't accept an empty string in the protocol parameter");
|
||||
}
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "\n");
|
||||
ok(false, "couldn't accept any not printable ASCII character in the protocol parameter");
|
||||
} catch (e) {
|
||||
ok(true, "couldn't accept any not printable ASCII character in the protocol parameter");
|
||||
}
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test 5");
|
||||
ok(false, "U+0020 not acceptable in protocol parameter");
|
||||
} catch (e) {
|
||||
ok(true, "U+0020 not acceptable in protocol parameter");
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function test6() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-6");
|
||||
var counter = 1;
|
||||
|
||||
ws.onopen = function() {
|
||||
ws.send(counter);
|
||||
}
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
if (counter == 5) {
|
||||
is(e.data, "あいうえお", "test-6 counter 5 data ok");
|
||||
ws.close();
|
||||
} else {
|
||||
is(parseInt(e.data), counter+1, "bad counter");
|
||||
counter += 2;
|
||||
ws.send(counter);
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test7() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://sub2.test2.example.org/tests/dom/base/test/file_websocket", "test-7");
|
||||
var gotmsg = false;
|
||||
|
||||
ws.onopen = function() {
|
||||
ok(true, "test 7 open");
|
||||
}
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
ok(true, "test 7 message");
|
||||
is(e.origin, "ws://sub2.test2.example.org", "onmessage origin set to ws:// host");
|
||||
gotmsg = true;
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(gotmsg, "recvd message in test 7 before close");
|
||||
shouldCloseCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test8() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-8");
|
||||
|
||||
ws.onopen = function() {
|
||||
is(ws.protocol, "test-8", "test-8 subprotocol selection");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseCleanly(e);
|
||||
// We called close() with no close code: so pywebsocket will also send no
|
||||
// close code, which translates to code 1005
|
||||
is(e.code, 1005, "test-8 close code has wrong value:" + e.code);
|
||||
is(e.reason, "", "test-8 close reason has wrong value:" + e.reason);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test9() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://test2.example.org/tests/dom/base/test/file_websocket", "test-9");
|
||||
|
||||
ws._receivedErrorEvent = false;
|
||||
|
||||
ws.onopen = shouldNotOpen;
|
||||
|
||||
ws.onerror = function(e) {
|
||||
ws._receivedErrorEvent = true;
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(ws._receivedErrorEvent, "Didn't received the error event in test 9.");
|
||||
shouldCloseNotCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
|
||||
ws.close();
|
||||
});
|
||||
}
|
||||
|
||||
function test10() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://sub1.test1.example.com/tests/dom/base/test/file_websocket", "test-10");
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
|
||||
try {
|
||||
ws.send("client data");
|
||||
ok(false, "Couldn't send data before connecting!");
|
||||
} catch (e) {
|
||||
ok(true, "Couldn't send data before connecting!");
|
||||
}
|
||||
|
||||
ws.onopen = function()
|
||||
{
|
||||
ok(true, "test 10 opened");
|
||||
ws.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test1, // client tries to connect to a http scheme location;
|
||||
test2, // assure serialization of the connections;
|
||||
|
@ -259,6 +29,10 @@ function testWebSocket() {
|
|||
doTest();
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
|
||||
"Expect all sorts of flakiness in this test...");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
<div id="feedback">
|
||||
|
|
|
@ -5,244 +5,12 @@
|
|||
<title>WebSocket test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="websocket_helpers.js"></script>
|
||||
<script type="text/javascript" src="websocket_tests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="testWebSocket()">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function test11() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-11");
|
||||
is(ws.readyState, 0, "create bad readyState in test-11!");
|
||||
|
||||
ws.onopen = function() {
|
||||
is(ws.readyState, 1, "open bad readyState in test-11!");
|
||||
ws.send("client data");
|
||||
}
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
is(e.data, "server data", "bad received message in test-11!");
|
||||
ws.close(1000, "Have a nice day");
|
||||
|
||||
// this ok() is disabled due to a race condition - it state may have
|
||||
// advanced through 2 (closing) and into 3 (closed) before it is evald
|
||||
// ok(ws.readyState == 2, "onmessage bad readyState in test-11!");
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.readyState, 3, "onclose bad readyState in test-11!");
|
||||
shouldCloseCleanly(e);
|
||||
is(e.code, 1000, "test 11 got wrong close code: " + e.code);
|
||||
is(e.reason, "Have a nice day", "test 11 got wrong close reason: " + e.reason);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test12() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-12");
|
||||
|
||||
ws.onopen = function() {
|
||||
try {
|
||||
// send an unpaired surrogate
|
||||
ws._gotMessage = false;
|
||||
ws.send("a\ud800b");
|
||||
ok(true, "ok to send an unpaired surrogate");
|
||||
} catch (e) {
|
||||
ok(false, "shouldn't fail any more when sending an unpaired surrogate!");
|
||||
}
|
||||
}
|
||||
|
||||
ws.onmessage = function(msg) {
|
||||
is(msg.data, "SUCCESS", "Unpaired surrogate in UTF-16 not converted in test-12");
|
||||
ws._gotMessage = true;
|
||||
// Must support unpaired surrogates in close reason, too
|
||||
ws.close(1000, "a\ud800b");
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.readyState, 3, "onclose bad readyState in test-12!");
|
||||
ok(ws._gotMessage, "didn't receive message!");
|
||||
shouldCloseCleanly(e);
|
||||
is(e.code, 1000, "test 12 got wrong close code: " + e.code);
|
||||
is(e.reason, "a\ufffdb", "test 11 didn't get replacement char in close reason: " + e.reason);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test13() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
// previous versions of this test counted the number of protocol errors
|
||||
// returned, but the protocol stack typically closes down after reporting a
|
||||
// protocol level error - trying to resync is too dangerous
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-13");
|
||||
ws._timesCalledOnError = 0;
|
||||
|
||||
ws.onerror = function() {
|
||||
ws._timesCalledOnError++;
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(ws._timesCalledOnError > 0, "no error events");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test14() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-14");
|
||||
|
||||
ws.onmessage = function() {
|
||||
ok(false, "shouldn't received message after the server sent the close frame");
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseCleanly(e);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function test15() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
/*
|
||||
* DISABLED: see comments for test-15 case in file_websocket_wsh.py
|
||||
*/
|
||||
resolve();
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-15");
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseNotCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
|
||||
// termination of the connection might cause an error event if it happens in OPEN
|
||||
ws.onerror = function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test16() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-16");
|
||||
|
||||
ws.onopen = function() {
|
||||
ws.close();
|
||||
ok(!ws.send("client data"), "shouldn't send message after calling close()");
|
||||
}
|
||||
|
||||
ws.onmessage = function() {
|
||||
ok(false, "shouldn't send message after calling close()");
|
||||
}
|
||||
|
||||
ws.onerror = function() {
|
||||
}
|
||||
|
||||
ws.onclose = function() {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test17() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var status_test17 = "not started";
|
||||
|
||||
var test17func = function() {
|
||||
var local_ws = new WebSocket("ws://sub1.test2.example.org/tests/dom/base/test/file_websocket", "test-17");
|
||||
status_test17 = "started";
|
||||
|
||||
local_ws.onopen = function(e) {
|
||||
status_test17 = "opened";
|
||||
e.target.send("client data");
|
||||
forcegc();
|
||||
};
|
||||
|
||||
local_ws.onerror = function() {
|
||||
ok(false, "onerror called on test " + current_test + "!");
|
||||
};
|
||||
|
||||
local_ws.onmessage = function(e) {
|
||||
ok(e.data == "server data", "Bad message in test-17");
|
||||
status_test17 = "got message";
|
||||
forcegc();
|
||||
};
|
||||
|
||||
local_ws.onclose = function(e) {
|
||||
ok(status_test17 == "got message", "Didn't got message in test-17!");
|
||||
shouldCloseCleanly(e);
|
||||
status_test17 = "closed";
|
||||
forcegc();
|
||||
resolve();
|
||||
};
|
||||
|
||||
window._test17 = null;
|
||||
forcegc();
|
||||
}
|
||||
|
||||
window._test17 = test17func;
|
||||
window._test17();
|
||||
});
|
||||
}
|
||||
|
||||
// The tests that expects that their websockets neither open nor close MUST
|
||||
// be in the end of the tests, i.e. HERE, in order to prevent blocking the other
|
||||
// tests.
|
||||
|
||||
function test18() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket_http_resource.txt");
|
||||
ws.onopen = shouldNotOpen;
|
||||
ws.onerror = ignoreError;
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
shouldCloseNotCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test19() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-19");
|
||||
ws.onopen = shouldNotOpen;
|
||||
ws.onerror = ignoreError;
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
shouldCloseNotCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test20() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var test20func = function() {
|
||||
var local_ws = new WebSocket("ws://sub1.test1.example.org/tests/dom/base/test/file_websocket", "test-20");
|
||||
|
||||
local_ws.onerror = function() {
|
||||
ok(false, "onerror called on test " + current_test + "!");
|
||||
}
|
||||
|
||||
local_ws.onclose = function(e) {
|
||||
ok(true, "test 20 closed despite gc");
|
||||
resolve();
|
||||
}
|
||||
|
||||
local_ws = null;
|
||||
window._test20 = null;
|
||||
forcegc();
|
||||
}
|
||||
|
||||
window._test20 = test20func;
|
||||
window._test20();
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test11, // a simple hello echo;
|
||||
test12, // client sends a message containing unpaired surrogates
|
||||
|
@ -263,6 +31,10 @@ function testWebSocket() {
|
|||
doTest();
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
|
||||
"Expect all sorts of flakiness in this test...");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
<div id="feedback">
|
||||
|
|
|
@ -5,197 +5,12 @@
|
|||
<title>WebSocket test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="websocket_helpers.js"></script>
|
||||
<script type="text/javascript" src="websocket_tests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="testWebSocket()">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function test21() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var test21func = function() {
|
||||
var local_ws = new WebSocket("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-21");
|
||||
var received_message = false;
|
||||
|
||||
local_ws.onopen = function(e) {
|
||||
e.target.send("client data");
|
||||
forcegc();
|
||||
e.target.onopen = null;
|
||||
forcegc();
|
||||
}
|
||||
|
||||
local_ws.onerror = function() {
|
||||
ok(false, "onerror called on test " + current_test + "!");
|
||||
}
|
||||
|
||||
local_ws.onmessage = function(e) {
|
||||
is(e.data, "server data", "Bad message in test-21");
|
||||
received_message = true;
|
||||
forcegc();
|
||||
e.target.onmessage = null;
|
||||
forcegc();
|
||||
}
|
||||
|
||||
local_ws.onclose = function(e) {
|
||||
shouldCloseCleanly(e);
|
||||
ok(received_message, "close transitioned through onmessage");
|
||||
resolve();
|
||||
}
|
||||
|
||||
local_ws = null;
|
||||
window._test21 = null;
|
||||
forcegc();
|
||||
}
|
||||
|
||||
window._test21 = test21func;
|
||||
window._test21();
|
||||
});
|
||||
}
|
||||
|
||||
function test22() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const pref_open = "network.websocket.timeout.open";
|
||||
SpecialPowers.setIntPref(pref_open, 5);
|
||||
|
||||
var ws = CreateTestWS("ws://sub2.test2.example.org/tests/dom/base/test/file_websocket", "test-22");
|
||||
|
||||
ws.onopen = shouldNotOpen;
|
||||
ws.onerror = ignoreError;
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseNotCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
|
||||
SpecialPowers.clearUserPref(pref_open);
|
||||
});
|
||||
}
|
||||
|
||||
function test23() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
ok("WebSocket" in window, "WebSocket should be available on window object");
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function test24() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-does-not-exist");
|
||||
|
||||
ws.onopen = shouldNotOpen;
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseNotCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
|
||||
ws.onerror = function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test25() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=[];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
// This test errors because the server requires a sub-protocol, but
|
||||
// the test just wants to ensure that the ctor doesn't generate an
|
||||
// exception
|
||||
ws.onerror = ignoreError;
|
||||
ws.onopen = shouldNotOpen;
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.protocol, "", "test25 subprotocol selection");
|
||||
ok(true, "test 25 protocol array close");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test26() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=[""];
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
ok(false, "testing empty element sub protocol array");
|
||||
} catch (e) {
|
||||
ok(true, "testing empty sub element protocol array");
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function test27() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test27", ""];
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
ok(false, "testing empty element mixed sub protocol array");
|
||||
} catch (e) {
|
||||
ok(true, "testing empty element mixed sub protocol array");
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function test28() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test28"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 28 protocol array open");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.protocol, "test28", "test28 subprotocol selection");
|
||||
ok(true, "test 28 protocol array close");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test29() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test29a", "test29b"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 29 protocol array open");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 29 protocol array close");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test30() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-does-not-exist"];
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = shouldNotOpen;
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseNotCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
|
||||
ws.onerror = function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test21, // see bug 572975 - same as test 17, but delete strong event listeners
|
||||
// when receiving the message event;
|
||||
|
@ -216,6 +31,10 @@ function testWebSocket() {
|
|||
doTest();
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
|
||||
"Expect all sorts of flakiness in this test...");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
<div id="feedback">
|
||||
|
|
|
@ -5,264 +5,12 @@
|
|||
<title>WebSocket test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="websocket_helpers.js"></script>
|
||||
<script type="text/javascript" src="websocket_tests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="testWebSocket()">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function test31() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-does-not-exist", "test31"];
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 31 protocol array open");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.protocol, "test31", "test31 subprotocol selection");
|
||||
ok(true, "test 31 protocol array close");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test32() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test32","test32"];
|
||||
|
||||
try {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
ok(false, "testing duplicated element sub protocol array");
|
||||
} catch (e) {
|
||||
ok(true, "testing duplicated sub element protocol array");
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function test33() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test33"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 33 open");
|
||||
ws.close(3131); // pass code but not reason
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 33 close");
|
||||
shouldCloseCleanly(e);
|
||||
is(e.code, 3131, "test 33 got wrong close code: " + e.code);
|
||||
is(e.reason, "", "test 33 got wrong close reason: " + e.reason);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test34() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-34"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 34 open");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e)
|
||||
{
|
||||
ok(true, "test 34 close");
|
||||
ok(e.wasClean, "test 34 closed cleanly");
|
||||
is(e.code, 1001, "test 34 custom server code");
|
||||
is(e.reason, "going away now", "test 34 custom server reason");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test35() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-35a");
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 35a open");
|
||||
ws.close(3500, "my code");
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 35a close");
|
||||
ok(e.wasClean, "test 35a closed cleanly");
|
||||
var wsb = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-35b");
|
||||
|
||||
wsb.onopen = function(e) {
|
||||
ok(true, "test 35b open");
|
||||
wsb.close();
|
||||
}
|
||||
|
||||
wsb.onclose = function(e) {
|
||||
ok(true, "test 35b close");
|
||||
ok(e.wasClean, "test 35b closed cleanly");
|
||||
is(e.code, 3501, "test 35 custom server code");
|
||||
is(e.reason, "my code", "test 35 custom server reason");
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test36() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-36"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 36 open");
|
||||
|
||||
try {
|
||||
ws.close(13200);
|
||||
ok(false, "testing custom close code out of range");
|
||||
} catch (e) {
|
||||
ok(true, "testing custom close code out of range");
|
||||
ws.close(3200);
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 36 close");
|
||||
ok(e.wasClean, "test 36 closed cleanly");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test37() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-37"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 37 open");
|
||||
|
||||
try {
|
||||
ws.close(3100,"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123");
|
||||
ok(false, "testing custom close reason out of range");
|
||||
} catch (e) {
|
||||
ok(true, "testing custom close reason out of range");
|
||||
ws.close(3100,"012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012");
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 37 close");
|
||||
ok(e.wasClean, "test 37 closed cleanly");
|
||||
|
||||
var wsb = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-37b");
|
||||
|
||||
wsb.onopen = function(e) {
|
||||
// now test that a rejected close code and reason dont persist
|
||||
ok(true, "test 37b open");
|
||||
try {
|
||||
wsb.close(3101,"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123");
|
||||
ok(false, "testing custom close reason out of range 37b");
|
||||
} catch (e) {
|
||||
ok(true, "testing custom close reason out of range 37b");
|
||||
wsb.close();
|
||||
}
|
||||
}
|
||||
|
||||
wsb.onclose = function(e) {
|
||||
ok(true, "test 37b close");
|
||||
ok(e.wasClean, "test 37b closed cleanly");
|
||||
|
||||
var wsc = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-37c");
|
||||
|
||||
wsc.onopen = function(e) {
|
||||
ok(true, "test 37c open");
|
||||
wsc.close();
|
||||
}
|
||||
|
||||
wsc.onclose = function(e) {
|
||||
isnot(e.code, 3101, "test 37c custom server code not present");
|
||||
is(e.reason, "", "test 37c custom server reason not present");
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test38() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-38"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 38 open");
|
||||
isnot(ws.extensions, undefined, "extensions attribute defined");
|
||||
// is(ws.extensions, "deflate-stream", "extensions attribute deflate-stream");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 38 close");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test39() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-39"];
|
||||
|
||||
var ws = CreateTestWS("wss://example.com/tests/dom/base/test/file_websocket", prots);
|
||||
status_test39 = "started";
|
||||
|
||||
ws.onopen = function(e) {
|
||||
status_test39 = "opened";
|
||||
ok(true, "test 39 open");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 39 close");
|
||||
is(status_test39, "opened", "test 39 did open");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test40() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-40"];
|
||||
|
||||
var ws = CreateTestWS("wss://nocert.example.com/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
status_test40 = "started";
|
||||
ws.onerror = ignoreError;
|
||||
|
||||
ws.onopen = function(e) {
|
||||
status_test40 = "opened";
|
||||
ok(false, "test 40 open");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 40 close");
|
||||
is(status_test40, "started", "test 40 did not open");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test31, // ctor using valid 2 element sub-protocol array with 1 element server
|
||||
// will reject and one server will accept
|
||||
|
@ -281,6 +29,10 @@ function testWebSocket() {
|
|||
doTest();
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
|
||||
"Expect all sorts of flakiness in this test...");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
<div id="feedback">
|
||||
|
|
|
@ -5,271 +5,12 @@
|
|||
<title>WebSocket test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="websocket_helpers.js"></script>
|
||||
<script type="text/javascript" src="websocket_tests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="testWebSocket()">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function test41() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://example.com/tests/dom/base/test/file_websocket", "test-41a", 1);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 41a open");
|
||||
is(ws.url, "ws://example.com/tests/dom/base/test/file_websocket",
|
||||
"test 41a initial ws should not be redirected");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 41a close");
|
||||
|
||||
// establish a hsts policy for example.com
|
||||
var wsb = CreateTestWS("wss://example.com/tests/dom/base/test/file_websocket", "test-41b", 1);
|
||||
|
||||
wsb.onopen = function(e) {
|
||||
ok(true, "test 41b open");
|
||||
wsb.close();
|
||||
}
|
||||
|
||||
wsb.onclose = function(e) {
|
||||
ok(true, "test 41b close");
|
||||
|
||||
// try ws:// again, it should be done over wss:// now due to hsts
|
||||
var wsc = CreateTestWS("ws://example.com/tests/dom/base/test/file_websocket", "test-41c");
|
||||
|
||||
wsc.onopen = function(e) {
|
||||
ok(true, "test 41c open");
|
||||
is(wsc.url, "wss://example.com/tests/dom/base/test/file_websocket",
|
||||
"test 41c ws should be redirected by hsts to wss");
|
||||
wsc.close();
|
||||
}
|
||||
|
||||
wsc.onclose = function(e) {
|
||||
ok(true, "test 41c close");
|
||||
|
||||
// clean up the STS state
|
||||
const Ci = SpecialPowers.Ci;
|
||||
var loadContext = SpecialPowers.wrap(window)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsILoadContext);
|
||||
var flags = 0;
|
||||
if (loadContext.usePrivateBrowsing)
|
||||
flags |= Ci.nsISocketProvider.NO_PERMANENT_STORAGE;
|
||||
SpecialPowers.cleanUpSTSData("http://example.com", flags);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test42() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
// test some utf-8 non-characters. They should be allowed in the
|
||||
// websockets context. Test via round trip echo.
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-42");
|
||||
var data = ["U+FFFE \ufffe",
|
||||
"U+FFFF \uffff",
|
||||
"U+10FFFF \udbff\udfff"];
|
||||
var index = 0;
|
||||
|
||||
ws.onopen = function() {
|
||||
ws.send(data[0]);
|
||||
ws.send(data[1]);
|
||||
ws.send(data[2]);
|
||||
}
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
is(e.data, data[index], "bad received message in test-42! index="+index);
|
||||
index++;
|
||||
if (index == 3) {
|
||||
ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test43() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var prots=["test-43"];
|
||||
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", prots);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
ok(true, "test 43 open");
|
||||
// Test binaryType setting
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.binaryType = "blob";
|
||||
ws.binaryType = ""; // illegal
|
||||
is(ws.binaryType, "blob");
|
||||
ws.binaryType = "ArrayBuffer"; // illegal
|
||||
is(ws.binaryType, "blob");
|
||||
ws.binaryType = "Blob"; // illegal
|
||||
is(ws.binaryType, "blob");
|
||||
ws.binaryType = "mcfoofluu"; // illegal
|
||||
is(ws.binaryType, "blob");
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
ok(true, "test 43 close");
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function test44() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-44");
|
||||
is(ws.readyState, 0, "bad readyState in test-44!");
|
||||
ws.binaryType = "arraybuffer";
|
||||
|
||||
ws.onopen = function() {
|
||||
is(ws.readyState, 1, "open bad readyState in test-44!");
|
||||
var buf = new ArrayBuffer(3);
|
||||
// create byte view
|
||||
var view = new Uint8Array(buf);
|
||||
view[0] = 5;
|
||||
view[1] = 0; // null byte
|
||||
view[2] = 7;
|
||||
ws.send(buf);
|
||||
}
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
ok(e.data instanceof ArrayBuffer, "Should receive an arraybuffer!");
|
||||
var view = new Uint8Array(e.data);
|
||||
ok(view.length == 2 && view[0] == 0 && view[1] ==4, "testing Reply arraybuffer" );
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.readyState, 3, "onclose bad readyState in test-44!");
|
||||
shouldCloseCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test45()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
function test45Real(blobFile) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-45");
|
||||
is(ws.readyState, 0, "bad readyState in test-45!");
|
||||
// ws.binaryType = "blob"; // Don't need to specify: blob is the default
|
||||
|
||||
ws.onopen = function() {
|
||||
is(ws.readyState, 1, "open bad readyState in test-45!");
|
||||
ws.send(blobFile);
|
||||
}
|
||||
|
||||
var test45blob;
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
test45blob = e.data;
|
||||
ok(test45blob instanceof Blob, "We should be receiving a Blob");
|
||||
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.readyState, 3, "onclose bad readyState in test-45!");
|
||||
shouldCloseCleanly(e);
|
||||
|
||||
// check blob contents
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
is(reader.result, "flob", "response should be 'flob': got '"
|
||||
+ reader.result + "'");
|
||||
}
|
||||
|
||||
reader.onerror = function(event) {
|
||||
testFailed("Failed to read blob: error code = " + reader.error.code);
|
||||
}
|
||||
|
||||
reader.onloadend = function(event) {
|
||||
resolve();
|
||||
}
|
||||
|
||||
reader.readAsBinaryString(test45blob);
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.createFiles([{name: "testBlobFile", data: "flob"}],
|
||||
function(files) {
|
||||
test45Real(files[0]);
|
||||
},
|
||||
function(msg) {
|
||||
testFailed("Failed to create file for test45: " + msg);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test46() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/base/test/file_websocket", "test-46");
|
||||
is(ws.readyState, 0, "create bad readyState in test-46!");
|
||||
|
||||
ws.onopen = function() {
|
||||
is(ws.readyState, 1, "open bad readyState in test-46!");
|
||||
ws.close()
|
||||
is(ws.readyState, 2, "close must set readyState to 2 in test-46!");
|
||||
}
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
ok(false, "received message after calling close in test-46!");
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
is(ws.readyState, 3, "onclose bad readyState in test-46!");
|
||||
shouldCloseCleanly(e);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test47() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var hasError = false;
|
||||
var ws = CreateTestWS("ws://another.websocket.server.that.probably.does.not.exist");
|
||||
|
||||
ws.onopen = shouldNotOpen;
|
||||
|
||||
ws.onerror = function (e) {
|
||||
is(ws.readyState, 3, "test-47: readyState should be CLOSED(3) in onerror: got "
|
||||
+ ws.readyState);
|
||||
ok(!ws._withinClose, "onerror() called during close()!");
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
ws.onclose = function(e) {
|
||||
shouldCloseNotCleanly(e);
|
||||
ok(hasError, "test-47: should have called onerror before onclose");
|
||||
is(ws.readyState, 3, "test-47: readyState should be CLOSED(3) in onclose: got "
|
||||
+ ws.readyState);
|
||||
ok(!ws._withinClose, "onclose() called during close()!");
|
||||
is(e.code, 1006, "test-47 close code should be 1006 but is:" + e.code);
|
||||
resolve();
|
||||
}
|
||||
|
||||
// Call close before we're connected: throws error
|
||||
// Make sure we call onerror/onclose asynchronously
|
||||
ws._withinClose = 1;
|
||||
ws.close(3333, "Closed before we were open: error");
|
||||
ws._withinClose = 0;
|
||||
is(ws.readyState, 2, "test-47: readyState should be CLOSING(2) after close(): got "
|
||||
+ ws.readyState);
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test41, // HSTS
|
||||
test42, // non-char utf-8 sequences
|
||||
|
@ -284,6 +25,10 @@ function testWebSocket() {
|
|||
doTest();
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
|
||||
"Expect all sorts of flakiness in this test...");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
<div id="feedback">
|
||||
|
|
|
@ -47,16 +47,20 @@ function forcegc() {
|
|||
SpecialPowers.gc();
|
||||
}
|
||||
|
||||
function feedback() {
|
||||
$("feedback").innerHTML = "executing test: " + (current_test+1) + " of " + tests.length + " tests.";
|
||||
}
|
||||
|
||||
function finish() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
if (current_test >= tests.length) {
|
||||
SimpleTest.finish();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
$("feedback").innerHTML = "executing test: " + (current_test+1) + " of " + tests.length + " tests.";
|
||||
feedback();
|
||||
tests[current_test++]().then(doTest);
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
|
||||
"Expect all sorts of flakiness in this test...");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -140,15 +140,18 @@ BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInf
|
|||
doc->NodePrincipal()->GetAppStatus(&status);
|
||||
}
|
||||
|
||||
mCharging = aBatteryInfo.charging();
|
||||
mRemainingTime = aBatteryInfo.remainingTime();
|
||||
|
||||
if (!nsContentUtils::IsChromeDoc(doc) &&
|
||||
status != nsIPrincipal::APP_STATUS_CERTIFIED)
|
||||
{
|
||||
mLevel = lround(mLevel * 10.0) / 10.0;
|
||||
if (mLevel == 1.0) {
|
||||
mRemainingTime = mCharging ? kDefaultRemainingTime : kUnknownRemainingTime;
|
||||
}
|
||||
}
|
||||
|
||||
mCharging = aBatteryInfo.charging();
|
||||
mRemainingTime = aBatteryInfo.remainingTime();
|
||||
|
||||
// Add some guards to make sure the values are coherent.
|
||||
if (mLevel == 1.0 && mCharging == true &&
|
||||
mRemainingTime != kDefaultRemainingTime) {
|
||||
|
|
|
@ -3499,13 +3499,9 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
|
|||
|
||||
virtual nscoord GetWidth()
|
||||
{
|
||||
gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0,
|
||||
mTextRun->GetLength(),
|
||||
mDoMeasureBoundingBox ?
|
||||
gfxFont::TIGHT_INK_EXTENTS :
|
||||
gfxFont::LOOSE_INK_EXTENTS,
|
||||
mDrawTarget,
|
||||
nullptr);
|
||||
gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(
|
||||
mDoMeasureBoundingBox ? gfxFont::TIGHT_INK_EXTENTS
|
||||
: gfxFont::LOOSE_INK_EXTENTS, mDrawTarget);
|
||||
|
||||
// this only measures the height; the total width is gotten from the
|
||||
// the return value of ProcessText.
|
||||
|
@ -3535,13 +3531,10 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
|
|||
// glyph string on OS X and DWrite where textrun widths may
|
||||
// involve fractional pixels.
|
||||
gfxTextRun::Metrics textRunMetrics =
|
||||
mTextRun->MeasureText(0,
|
||||
mTextRun->GetLength(),
|
||||
mDoMeasureBoundingBox ?
|
||||
gfxFont::TIGHT_INK_EXTENTS :
|
||||
gfxFont::LOOSE_INK_EXTENTS,
|
||||
mDrawTarget,
|
||||
nullptr);
|
||||
mTextRun->MeasureText(mDoMeasureBoundingBox ?
|
||||
gfxFont::TIGHT_INK_EXTENTS :
|
||||
gfxFont::LOOSE_INK_EXTENTS,
|
||||
mDrawTarget);
|
||||
inlineCoord += textRunMetrics.mAdvanceWidth;
|
||||
// old code was:
|
||||
// point.x += width * mAppUnitsPerDevPixel;
|
||||
|
|
|
@ -26,7 +26,9 @@ class WebGLContextLossHandler : public dom::workers::WorkerFeature
|
|||
bool mShouldRunTimerAgain;
|
||||
bool mIsDisabled;
|
||||
bool mFeatureAdded;
|
||||
DebugOnly<nsIThread*> mThread;
|
||||
#ifdef DEBUG
|
||||
nsIThread* mThread;
|
||||
#endif
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(WebGLContextLossHandler)
|
||||
|
|
|
@ -1332,24 +1332,16 @@ private:
|
|||
class ImportKeyTask : public WebCryptoTask
|
||||
{
|
||||
public:
|
||||
void Init(JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
void Init(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat, const ObjectOrString& aAlgorithm,
|
||||
bool aExtractable, const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
mFormat = aFormat;
|
||||
mDataIsSet = false;
|
||||
mDataIsJwk = false;
|
||||
|
||||
// Get the current global object from the context
|
||||
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
if (!global) {
|
||||
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// This stuff pretty much always happens, so we'll do it here
|
||||
mKey = new CryptoKey(global);
|
||||
mKey = new CryptoKey(aGlobal);
|
||||
mKey->SetExtractable(aExtractable);
|
||||
mKey->ClearUsages();
|
||||
for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) {
|
||||
|
@ -1472,20 +1464,20 @@ private:
|
|||
class ImportSymmetricKeyTask : public ImportKeyTask
|
||||
{
|
||||
public:
|
||||
ImportSymmetricKeyTask(JSContext* aCx,
|
||||
ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
ImportSymmetricKeyTask(JSContext* aCx,
|
||||
ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat, const JS::Handle<JSObject*> aKeyData,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1498,12 +1490,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1630,20 +1621,20 @@ private:
|
|||
class ImportRsaKeyTask : public ImportKeyTask
|
||||
{
|
||||
public:
|
||||
ImportRsaKeyTask(JSContext* aCx,
|
||||
ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
ImportRsaKeyTask(JSContext* aCx,
|
||||
ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1656,12 +1647,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx,
|
||||
void Init(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1798,19 +1789,19 @@ private:
|
|||
class ImportEcKeyTask : public ImportKeyTask
|
||||
{
|
||||
public:
|
||||
ImportEcKeyTask(JSContext* aCx, const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat, const ObjectOrString& aAlgorithm,
|
||||
bool aExtractable, const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
ImportEcKeyTask(JSContext* aCx, const nsAString& aFormat,
|
||||
JS::Handle<JSObject*> aKeyData,
|
||||
ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1819,11 +1810,11 @@ public:
|
|||
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx, const nsAString& aFormat,
|
||||
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1951,30 +1942,30 @@ private:
|
|||
class ImportDhKeyTask : public ImportKeyTask
|
||||
{
|
||||
public:
|
||||
ImportDhKeyTask(JSContext* aCx, const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat, const ObjectOrString& aAlgorithm,
|
||||
bool aExtractable, const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
ImportDhKeyTask(JSContext* aCx, const nsAString& aFormat,
|
||||
JS::Handle<JSObject*> aKeyData,
|
||||
ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_SUCCEEDED(mEarlyRv)) {
|
||||
SetKeyData(aCx, aKeyData);
|
||||
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
|
||||
}
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx, const nsAString& aFormat,
|
||||
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2197,18 +2188,12 @@ private:
|
|||
class GenerateSymmetricKeyTask : public WebCryptoTask
|
||||
{
|
||||
public:
|
||||
GenerateSymmetricKeyTask(JSContext* aCx,
|
||||
GenerateSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
{
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
if (!global) {
|
||||
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an empty key and set easy attributes
|
||||
mKey = new CryptoKey(global);
|
||||
mKey = new CryptoKey(aGlobal);
|
||||
mKey->SetExtractable(aExtractable);
|
||||
mKey->SetType(CryptoKey::SECRET);
|
||||
|
||||
|
@ -2326,16 +2311,10 @@ private:
|
|||
};
|
||||
|
||||
GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
|
||||
JSContext* aCx, const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
nsIGlobalObject* aGlobal, JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
bool aExtractable, const Sequence<nsString>& aKeyUsages)
|
||||
: mKeyPair(new CryptoKeyPair())
|
||||
{
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
if (!global) {
|
||||
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
mArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if (!mArena) {
|
||||
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
|
@ -2343,8 +2322,8 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
|
|||
}
|
||||
|
||||
// Create an empty key pair and set easy attributes
|
||||
mKeyPair->mPrivateKey = new CryptoKey(global);
|
||||
mKeyPair->mPublicKey = new CryptoKey(global);
|
||||
mKeyPair->mPrivateKey = new CryptoKey(aGlobal);
|
||||
mKeyPair->mPublicKey = new CryptoKey(aGlobal);
|
||||
|
||||
// Extract algorithm name
|
||||
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName);
|
||||
|
@ -2853,7 +2832,7 @@ template<class DeriveBitsTask>
|
|||
class DeriveKeyTask : public DeriveBitsTask
|
||||
{
|
||||
public:
|
||||
DeriveKeyTask(JSContext* aCx,
|
||||
DeriveKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm, CryptoKey& aBaseKey,
|
||||
const ObjectOrString& aDerivedKeyType, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
|
@ -2865,7 +2844,7 @@ public:
|
|||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(format, WEBCRYPTO_KEY_FORMAT_RAW);
|
||||
mTask = new ImportSymmetricKeyTask(aCx, format, aDerivedKeyType,
|
||||
mTask = new ImportSymmetricKeyTask(aGlobal, aCx, format, aDerivedKeyType,
|
||||
aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
|
@ -3295,7 +3274,8 @@ WebCryptoTask::CreateDigestTask(JSContext* aCx,
|
|||
}
|
||||
|
||||
WebCryptoTask*
|
||||
WebCryptoTask::CreateImportKeyTask(JSContext* aCx,
|
||||
WebCryptoTask::CreateImportKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
JS::Handle<JSObject*> aKeyData,
|
||||
const ObjectOrString& aAlgorithm,
|
||||
|
@ -3333,19 +3313,19 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx,
|
|||
algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
|
||||
return new ImportSymmetricKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
return new ImportSymmetricKeyTask(aGlobal, aCx, aFormat, aKeyData,
|
||||
aAlgorithm, aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
|
||||
return new ImportRsaKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
return new ImportRsaKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
return new ImportEcKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
return new ImportEcKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
|
||||
return new ImportDhKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
return new ImportDhKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else {
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
|
@ -3394,7 +3374,8 @@ WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat,
|
|||
}
|
||||
|
||||
WebCryptoTask*
|
||||
WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
|
||||
WebCryptoTask::CreateGenerateKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm,
|
||||
bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages)
|
||||
|
@ -3420,21 +3401,24 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
|
|||
algName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_AES_KW) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
|
||||
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
return new GenerateSymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable,
|
||||
aKeyUsages);
|
||||
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
|
||||
return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
return new GenerateAsymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable,
|
||||
aKeyUsages);
|
||||
} else {
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
WebCryptoTask*
|
||||
WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx,
|
||||
WebCryptoTask::CreateDeriveKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aBaseKey,
|
||||
const ObjectOrString& aDerivedKeyType,
|
||||
|
@ -3460,21 +3444,21 @@ WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx,
|
|||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) {
|
||||
return new DeriveKeyTask<DeriveHkdfBitsTask>(aCx, aAlgorithm, aBaseKey,
|
||||
aDerivedKeyType, aExtractable,
|
||||
aKeyUsages);
|
||||
return new DeriveKeyTask<DeriveHkdfBitsTask>(aGlobal, aCx, aAlgorithm,
|
||||
aBaseKey, aDerivedKeyType,
|
||||
aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
|
||||
return new DeriveKeyTask<DerivePbkdfBitsTask>(aCx, aAlgorithm, aBaseKey,
|
||||
aDerivedKeyType, aExtractable,
|
||||
aKeyUsages);
|
||||
return new DeriveKeyTask<DerivePbkdfBitsTask>(aGlobal, aCx, aAlgorithm,
|
||||
aBaseKey, aDerivedKeyType,
|
||||
aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
|
||||
return new DeriveKeyTask<DeriveEcdhBitsTask>(aCx, aAlgorithm, aBaseKey,
|
||||
aDerivedKeyType, aExtractable,
|
||||
aKeyUsages);
|
||||
return new DeriveKeyTask<DeriveEcdhBitsTask>(aGlobal, aCx, aAlgorithm,
|
||||
aBaseKey, aDerivedKeyType,
|
||||
aExtractable, aKeyUsages);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
|
@ -3568,7 +3552,8 @@ WebCryptoTask::CreateWrapKeyTask(JSContext* aCx,
|
|||
}
|
||||
|
||||
WebCryptoTask*
|
||||
WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx,
|
||||
WebCryptoTask::CreateUnwrapKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
const ArrayBufferViewOrArrayBuffer& aWrappedKey,
|
||||
CryptoKey& aUnwrappingKey,
|
||||
|
@ -3602,13 +3587,13 @@ WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx,
|
|||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HKDF) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
|
||||
importTask = new ImportSymmetricKeyTask(aCx, aFormat,
|
||||
importTask = new ImportSymmetricKeyTask(aGlobal, aCx, aFormat,
|
||||
aUnwrappedKeyAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
|
||||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS)) {
|
||||
importTask = new ImportRsaKeyTask(aCx, aFormat,
|
||||
importTask = new ImportRsaKeyTask(aGlobal, aCx, aFormat,
|
||||
aUnwrappedKeyAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else {
|
||||
|
|
|
@ -122,7 +122,8 @@ public:
|
|||
const ObjectOrString& aAlgorithm,
|
||||
const CryptoOperationData& aData);
|
||||
|
||||
static WebCryptoTask* CreateImportKeyTask(JSContext* aCx,
|
||||
static WebCryptoTask* CreateImportKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
JS::Handle<JSObject*> aKeyData,
|
||||
const ObjectOrString& aAlgorithm,
|
||||
|
@ -130,12 +131,14 @@ public:
|
|||
const Sequence<nsString>& aKeyUsages);
|
||||
static WebCryptoTask* CreateExportKeyTask(const nsAString& aFormat,
|
||||
CryptoKey& aKey);
|
||||
static WebCryptoTask* CreateGenerateKeyTask(JSContext* aCx,
|
||||
static WebCryptoTask* CreateGenerateKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm,
|
||||
bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages);
|
||||
|
||||
static WebCryptoTask* CreateDeriveKeyTask(JSContext* aCx,
|
||||
static WebCryptoTask* CreateDeriveKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aBaseKey,
|
||||
const ObjectOrString& aDerivedKeyType,
|
||||
|
@ -151,7 +154,8 @@ public:
|
|||
CryptoKey& aKey,
|
||||
CryptoKey& aWrappingKey,
|
||||
const ObjectOrString& aWrapAlgorithm);
|
||||
static WebCryptoTask* CreateUnwrapKeyTask(JSContext* aCx,
|
||||
static WebCryptoTask* CreateUnwrapKeyTask(nsIGlobalObject* aGlobal,
|
||||
JSContext* aCx,
|
||||
const nsAString& aFormat,
|
||||
const ArrayBufferViewOrArrayBuffer& aWrappedKey,
|
||||
CryptoKey& aUnwrappingKey,
|
||||
|
@ -228,7 +232,7 @@ private:
|
|||
class GenerateAsymmetricKeyTask : public WebCryptoTask
|
||||
{
|
||||
public:
|
||||
GenerateAsymmetricKeyTask(JSContext* aCx,
|
||||
GenerateAsymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm, bool aExtractable,
|
||||
const Sequence<nsString>& aKeyUsages);
|
||||
protected:
|
||||
|
|
|
@ -987,6 +987,52 @@ TestArray.addTest(
|
|||
doCheckRSASSA().then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Test that we're using the right globals when creating objects",
|
||||
function() {
|
||||
var that = this;
|
||||
var data = crypto.getRandomValues(new Uint8Array(10));
|
||||
var hmacAlg = {name: "HMAC", length: 256, hash: "SHA-1"};
|
||||
|
||||
var rsaAlg = {
|
||||
name: "RSA-PSS",
|
||||
hash: "SHA-1",
|
||||
modulusLength: 1024,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||
};
|
||||
|
||||
function checkPrototypes(obj, type) {
|
||||
return obj.__proto__ != window[type].prototype &&
|
||||
obj.__proto__ == frames[0][type].prototype
|
||||
}
|
||||
|
||||
var p1 = crypto.subtle.importKey.call(
|
||||
frames[0].crypto.subtle, "raw", data, hmacAlg, false, ["sign", "verify"]);
|
||||
var p2 = crypto.subtle.generateKey.call(
|
||||
frames[0].crypto.subtle, hmacAlg, false, ["sign", "verify"]);
|
||||
var p3 = crypto.subtle.generateKey.call(
|
||||
frames[0].crypto.subtle, rsaAlg, false, ["sign", "verify"]);
|
||||
|
||||
if (!checkPrototypes(p1, "Promise") ||
|
||||
!checkPrototypes(p2, "Promise") ||
|
||||
!checkPrototypes(p3, "Promise")) {
|
||||
error(that)();
|
||||
}
|
||||
|
||||
Promise.all([p1, p2, p3]).then(complete(that, keys => {
|
||||
return keys.every(key => {
|
||||
if (key instanceof CryptoKey) {
|
||||
return checkPrototypes(key, "CryptoKey");
|
||||
}
|
||||
|
||||
return checkPrototypes(key.publicKey, "CryptoKey") &&
|
||||
checkPrototypes(key.privateKey, "CryptoKey");
|
||||
});
|
||||
}), error(that));
|
||||
}
|
||||
);
|
||||
/*]]>*/</script>
|
||||
</head>
|
||||
|
||||
|
@ -997,6 +1043,7 @@ TestArray.addTest(
|
|||
<b>Web</b>Crypto<br>
|
||||
</div>
|
||||
|
||||
<iframe style="display: none;"></iframe>
|
||||
<div id="start" onclick="start();">RUN ALL</div>
|
||||
|
||||
<div id="resultDiv" class="content">
|
||||
|
|
|
@ -658,10 +658,9 @@ ContentEventHandler::AppendFontRanges(FontRangeArray& aFontRanges,
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t skipStart = iter.ConvertOriginalToSkipped(frameXPStart);
|
||||
uint32_t skipEnd = iter.ConvertOriginalToSkipped(frameXPEnd);
|
||||
gfxTextRun::GlyphRunIterator runIter(
|
||||
textRun, skipStart, skipEnd - skipStart);
|
||||
gfxTextRun::Range skipRange(iter.ConvertOriginalToSkipped(frameXPStart),
|
||||
iter.ConvertOriginalToSkipped(frameXPEnd));
|
||||
gfxTextRun::GlyphRunIterator runIter(textRun, skipRange);
|
||||
int32_t lastXPEndOffset = frameXPStart;
|
||||
while (runIter.NextRun()) {
|
||||
gfxFont* font = runIter.GetGlyphRun()->mFont.get();
|
||||
|
|
|
@ -39,13 +39,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(runTests, window);
|
||||
SimpleTest.waitForFocus(runTest, window);
|
||||
|
||||
var gScrollableElement = document.getElementById("scrollable");
|
||||
var gScrolledElement = document.getElementById("scrolled");
|
||||
|
@ -55,42 +55,43 @@ var gHorizontalLine = 0;
|
|||
var gPageHeight = 0;
|
||||
var gPageWidth = 0;
|
||||
|
||||
function prepareScrollUnits()
|
||||
function* prepareScrollUnits()
|
||||
{
|
||||
var result = -1;
|
||||
function handler(aEvent)
|
||||
{
|
||||
result = aEvent.detail;
|
||||
aEvent.preventDefault();
|
||||
setTimeout(continueTest, 0);
|
||||
}
|
||||
window.addEventListener("MozMousePixelScroll", handler, true);
|
||||
|
||||
synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaY: 1.0, lineOrPageDeltaY: 1 });
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaY: 1.0, lineOrPageDeltaY: 1 });
|
||||
gLineHeight = result;
|
||||
ok(gLineHeight > 10 && gLineHeight < 25, "prepareScrollUnits: gLineHeight may be illegal value, got " + gLineHeight);
|
||||
|
||||
result = -1;
|
||||
synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 1.0, lineOrPageDeltaX: 1 });
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 1.0, lineOrPageDeltaX: 1 });
|
||||
gHorizontalLine = result;
|
||||
ok(gHorizontalLine > 5 && gHorizontalLine < 16, "prepareScrollUnits: gHorizontalLine may be illegal value, got " + gHorizontalLine);
|
||||
|
||||
result = -1;
|
||||
synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
|
||||
deltaY: 1.0, lineOrPageDeltaY: 1 });
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
|
||||
deltaY: 1.0, lineOrPageDeltaY: 1 });
|
||||
gPageHeight = result;
|
||||
// XXX Cannot we know the actual scroll port size?
|
||||
ok(gPageHeight >= 150 && gPageHeight <= 200,
|
||||
"prepareScrollUnits: gPageHeight is strange value, got " + gPageHeight);
|
||||
|
||||
result = -1;
|
||||
synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
|
||||
deltaX: 1.0, lineOrPageDeltaX: 1 });
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_PAGE,
|
||||
deltaX: 1.0, lineOrPageDeltaX: 1 });
|
||||
gPageWidth = result;
|
||||
ok(gPageWidth >= 150 && gPageWidth <= 200,
|
||||
"prepareScrollUnits: gPageWidth is strange value, got " + gPageWidth);
|
||||
|
@ -123,7 +124,7 @@ function testMakingUntrustedEvent()
|
|||
|
||||
// delta_multiplier prefs should cause changing delta values of trusted events only.
|
||||
// And also legacy events' detail value should be changed too.
|
||||
function testDeltaMultiplierPrefs()
|
||||
function* testDeltaMultiplierPrefs()
|
||||
{
|
||||
const kModifierAlt = 0x01;
|
||||
const kModifierControl = 0x02;
|
||||
|
@ -190,6 +191,7 @@ function testDeltaMultiplierPrefs()
|
|||
];
|
||||
|
||||
var currentTest, currentModifiers, currentEvent, currentPref, currentMultiplier, testingExpected;
|
||||
var expectedHandlerCalls;
|
||||
var description;
|
||||
var calledHandlers = { wheel: false,
|
||||
DOMMouseScroll: { horizontal: false, vertical: false },
|
||||
|
@ -215,9 +217,13 @@ function testDeltaMultiplierPrefs()
|
|||
break;
|
||||
}
|
||||
}
|
||||
is(aEvent.deltaX, expectedDeltaX, description + "deltaX (" + currentEvent.deltaX + ") was invaild");
|
||||
is(aEvent.deltaY, expectedDeltaY, description + "deltaY (" + currentEvent.deltaY + ") was invaild");
|
||||
is(aEvent.deltaZ, expectedDeltaZ, description + "deltaZ (" + currentEvent.deltaZ + ") was invaild");
|
||||
is(aEvent.deltaX, expectedDeltaX, description + "deltaX (" + currentEvent.deltaX + ") was invalid");
|
||||
is(aEvent.deltaY, expectedDeltaY, description + "deltaY (" + currentEvent.deltaY + ") was invalid");
|
||||
is(aEvent.deltaZ, expectedDeltaZ, description + "deltaZ (" + currentEvent.deltaZ + ") was invalid");
|
||||
|
||||
if (--expectedHandlerCalls == 0) {
|
||||
setTimeout(continueTest, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function legacyEventHandler(aEvent) {
|
||||
|
@ -276,13 +282,17 @@ function testDeltaMultiplierPrefs()
|
|||
is(aEvent.detail, expectedDetail, description + eventName + "detail was invalid");
|
||||
|
||||
aEvent.preventDefault();
|
||||
|
||||
if (--expectedHandlerCalls == 0) {
|
||||
setTimeout(continueTest, 0);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("wheel", wheelEventHandler, true);
|
||||
window.addEventListener("DOMMouseScroll", legacyEventHandler, true);
|
||||
window.addEventListener("MozMousePixelScroll", legacyEventHandler, true);
|
||||
|
||||
function dispatchEvent(aIsExpected) {
|
||||
function* dispatchEvent(aIsExpected) {
|
||||
for (var i = 0; i < kEvents.length; i++) {
|
||||
currentEvent = kEvents[i];
|
||||
currentEvent.shiftKey = (currentModifiers & kModifierShift) != 0;
|
||||
|
@ -312,17 +322,13 @@ function testDeltaMultiplierPrefs()
|
|||
for (var k = 0; k < kDeltaMultiplierPrefs.length; k++) {
|
||||
currentPref = "mousewheel." + currentTest.name + "." + kDeltaMultiplierPrefs[k];
|
||||
|
||||
SpecialPowers.setIntPref(currentPref, kPrefValues[j]);
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[currentPref, kPrefValues[j]]]}, continueTest);
|
||||
|
||||
gScrollableElement.scrollTop = gScrollableElement.scrollBottom = 1000;
|
||||
|
||||
// trusted event's delta valuses should be reverted by the pref.
|
||||
testingExpected = aIsExpected;
|
||||
|
||||
description = "testDeltaMultiplierPrefs, pref: " + currentPref + "=" + kPrefValues[j] +
|
||||
", deltaMode: " + currentEvent.deltaMode + ", modifiers: \"" + modifierList + "\", (trusted event): ";
|
||||
synthesizeWheel(gScrollableElement, 10, 10, currentEvent);
|
||||
|
||||
var expectedProps = {
|
||||
deltaX: currentEvent.deltaX * currentMultiplier,
|
||||
deltaY: currentEvent.deltaY * currentMultiplier,
|
||||
|
@ -331,20 +337,37 @@ function testDeltaMultiplierPrefs()
|
|||
lineOrPageDeltaY: currentEvent.lineOrPageDeltaY * currentMultiplier,
|
||||
};
|
||||
|
||||
var expectedWheel = expectedProps.deltaX != 0 || expectedProps.deltaY != 0 || expectedProps.deltaZ != 0;
|
||||
var expectedDOMMouseX = expectedProps.lineOrPageDeltaX >= 1 || expectedProps.lineOrPageDeltaX <= -1;
|
||||
var expectedDOMMouseY = expectedProps.lineOrPageDeltaY >= 1 || expectedProps.lineOrPageDeltaY <= -1;
|
||||
var expectedMozMouseX = expectedProps.deltaX >= 1 || expectedProps.deltaX <= -1;
|
||||
var expectedMozMouseY = expectedProps.deltaY >= 1 || expectedProps.deltaY <= -1;
|
||||
|
||||
expectedHandlerCalls = 0;
|
||||
if (expectedWheel) ++expectedHandlerCalls;
|
||||
if (expectedDOMMouseX) ++expectedHandlerCalls;
|
||||
if (expectedDOMMouseY) ++expectedHandlerCalls;
|
||||
if (expectedMozMouseX) ++expectedHandlerCalls;
|
||||
if (expectedMozMouseY) ++expectedHandlerCalls;
|
||||
|
||||
description = "testDeltaMultiplierPrefs, pref: " + currentPref + "=" + kPrefValues[j] +
|
||||
", deltaMode: " + currentEvent.deltaMode + ", modifiers: \"" + modifierList + "\", (trusted event): ";
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10, currentEvent);
|
||||
|
||||
is(calledHandlers.wheel,
|
||||
expectedProps.deltaX != 0 || expectedProps.deltaY != 0 || expectedProps.deltaZ != 0,
|
||||
expectedWheel,
|
||||
description + "wheel event was (not) fired");
|
||||
is(calledHandlers.DOMMouseScroll.horizontal,
|
||||
expectedProps.lineOrPageDeltaX >= 1 || expectedProps.lineOrPageDeltaX <= -1,
|
||||
expectedDOMMouseX,
|
||||
description + "Horizontal DOMMouseScroll event was (not) fired");
|
||||
is(calledHandlers.DOMMouseScroll.vertical,
|
||||
expectedProps.lineOrPageDeltaY >= 1 || expectedProps.lineOrPageDeltaY <= -1,
|
||||
expectedDOMMouseY,
|
||||
description + "Vertical DOMMouseScroll event was (not) fired");
|
||||
is(calledHandlers.MozMousePixelScroll.horizontal,
|
||||
expectedProps.deltaY >= 1 || expectedProps.deltaY <= -1,
|
||||
expectedMozMouseX,
|
||||
description + "Horizontal MozMousePixelScroll event was (not) fired");
|
||||
is(calledHandlers.MozMousePixelScroll.vertical,
|
||||
expectedProps.deltaY >= 1 || expectedProps.deltaY <= -1,
|
||||
expectedMozMouseY,
|
||||
description + "Vertical MozMousePixelScroll event was (not) fired");
|
||||
|
||||
calledHandlers = { wheel: false,
|
||||
|
@ -381,7 +404,7 @@ function testDeltaMultiplierPrefs()
|
|||
ok(!calledHandlers.MozMousePixelScroll.vertical,
|
||||
description + "Vertical MozMousePixelScroll event was fired for untrusted event");
|
||||
|
||||
SpecialPowers.setIntPref(currentPref, 100);
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[currentPref, 100]]}, continueTest);
|
||||
|
||||
calledHandlers = { wheel: false,
|
||||
DOMMouseScroll: { horizontal: false, vertical: false },
|
||||
|
@ -401,11 +424,11 @@ function testDeltaMultiplierPrefs()
|
|||
currentTest = kTests[i];
|
||||
for (var j = 0; j < currentTest.expected.length; j++) {
|
||||
currentModifiers = currentTest.expected[j];
|
||||
dispatchEvent(true);
|
||||
yield* dispatchEvent(true);
|
||||
}
|
||||
for (var k = 0; k < currentTest.unexpected.length; k++) {
|
||||
currentModifiers = currentTest.unexpected[k];
|
||||
dispatchEvent(false);
|
||||
yield* dispatchEvent(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,7 +491,7 @@ function testDispatchingUntrustEvent()
|
|||
window.removeEventListener("MozMousePixelScroll", legacyEventHandler, true);
|
||||
}
|
||||
|
||||
function testEventOrder()
|
||||
function* testEventOrder()
|
||||
{
|
||||
const kWheelEvent = 0x0001;
|
||||
const kDOMMouseScrollEvent = 0x0002;
|
||||
|
@ -615,21 +638,24 @@ function testEventOrder()
|
|||
event |= kDefaultPrevented;
|
||||
}
|
||||
currentTest.resultEvents.push(event);
|
||||
return event;
|
||||
|
||||
if (event == currentTest.doPreventDefaultAt) {
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
|
||||
if (currentTest.resultEvents.length == currentTest.expectedEvents.length) {
|
||||
setTimeout(continueTest, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function handler(aEvent)
|
||||
{
|
||||
if (pushEvent(aEvent, false) == currentTest.doPreventDefaultAt) {
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
pushEvent(aEvent, false);
|
||||
}
|
||||
|
||||
function systemHandler(aEvent)
|
||||
{
|
||||
if (pushEvent(aEvent, true) == currentTest.doPreventDefaultAt) {
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
pushEvent(aEvent, true);
|
||||
}
|
||||
|
||||
window.addEventListener("wheel", handler, true);
|
||||
|
@ -642,8 +668,8 @@ function testEventOrder()
|
|||
|
||||
for (var i = 0; i < kTests.length; i++) {
|
||||
currentTest = kTests[i];
|
||||
synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0 });
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0 });
|
||||
|
||||
for (var j = 0; j < currentTest.expectedEvents.length; j++) {
|
||||
if (currentTest.resultEvents.length == j) {
|
||||
|
@ -672,34 +698,54 @@ function testEventOrder()
|
|||
}
|
||||
|
||||
var gOnWheelAttrHandled = new Array;
|
||||
var gOnWheelAttrCount = 0;
|
||||
|
||||
function testOnWheelAttr()
|
||||
function* testOnWheelAttr()
|
||||
{
|
||||
document.documentElement.setAttribute("onwheel", "gOnWheelAttrHandled['html'] = true;");
|
||||
document.body.setAttribute("onwheel", "gOnWheelAttrHandled['body'] = true;");
|
||||
gScrollableElement.setAttribute("onwheel", "gOnWheelAttrHandled['div'] = true;");
|
||||
function onWheelHandledString(attr) {
|
||||
return `gOnWheelAttrHandled['${attr}'] = true;
|
||||
++gOnWheelAttrCount;
|
||||
if (gOnWheelAttrCount == 3) {
|
||||
setTimeout(continueTest, 0);
|
||||
};`;
|
||||
}
|
||||
|
||||
document.documentElement.setAttribute("onwheel", onWheelHandledString("html"));
|
||||
document.body.setAttribute("onwheel", onWheelHandledString("body"));
|
||||
gScrollableElement.setAttribute("onwheel", onWheelHandledString("div"));
|
||||
var target = document.getElementById("onwheel");
|
||||
synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 1.0, deltaY: 2.0 });
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 1.0, deltaY: 2.0 });
|
||||
ok(gOnWheelAttrHandled['html'], "html element's onwheel attribute isn't performed");
|
||||
ok(gOnWheelAttrHandled['body'], "body element's onwheel attribute isn't performed");
|
||||
ok(gOnWheelAttrHandled['div'], "div element's onwheel attribute isn't performed");
|
||||
}
|
||||
|
||||
var gOnWheelPropHandled = new Array;
|
||||
var gOnWheelPropCount = 0;
|
||||
|
||||
function testOnWheelProperty()
|
||||
function* testOnWheelProperty()
|
||||
{
|
||||
window.onwheel = function (e) { gOnWheelPropHandled["window"] = true; }
|
||||
document.onwheel = function (e) { gOnWheelPropHandled["document"] = true; }
|
||||
document.documentElement.onwheel = function (e) { gOnWheelPropHandled["html"] = true; };
|
||||
document.body.onwheel = function (e) { gOnWheelPropHandled["body"] = true; };
|
||||
gScrollableElement.onwheel = function (e) { gOnWheelPropHandled["div"] = true; };
|
||||
const handleOnWheelProp = prop => e => {
|
||||
gOnWheelPropHandled[prop] = true;
|
||||
++gOnWheelPropCount;
|
||||
if (gOnWheelPropCount == 5) {
|
||||
setTimeout(continueTest, 0);
|
||||
}
|
||||
}
|
||||
|
||||
window.onwheel = handleOnWheelProp('window');
|
||||
document.onwheel = handleOnWheelProp('document');
|
||||
document.documentElement.onwheel = handleOnWheelProp('html');
|
||||
document.body.onwheel = handleOnWheelProp('body');
|
||||
gScrollableElement.onwheel = handleOnWheelProp('div');
|
||||
|
||||
var target = document.getElementById("onwheel");
|
||||
synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 1.0, deltaY: 2.0 });
|
||||
yield synthesizeWheel(gScrollableElement, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 1.0, deltaY: 2.0 });
|
||||
|
||||
ok(gOnWheelPropHandled['window'], "window's onwheel property isn't performed");
|
||||
ok(gOnWheelPropHandled['document'], "document's onwheel property isn't performed");
|
||||
ok(gOnWheelPropHandled['html'], "html element's onwheel property isn't performed");
|
||||
|
@ -707,57 +753,53 @@ function testOnWheelProperty()
|
|||
ok(gOnWheelPropHandled['div'], "div element's onwheel property isn't performed");
|
||||
}
|
||||
|
||||
function runTests()
|
||||
function* testBody()
|
||||
{
|
||||
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_z", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_x", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_y", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_alt.delta_multiplier_z", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_x", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_y", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_control.delta_multiplier_z", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_x", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_y", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_meta.delta_multiplier_z", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_x", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_y", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_shift.delta_multiplier_z", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_x", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_y", 100);
|
||||
SpecialPowers.setIntPref("mousewheel.with_win.delta_multiplier_z", 100);
|
||||
|
||||
prepareScrollUnits();
|
||||
yield* prepareScrollUnits();
|
||||
testMakingUntrustedEvent();
|
||||
testDeltaMultiplierPrefs();
|
||||
yield* testDeltaMultiplierPrefs();
|
||||
testDispatchingUntrustEvent();
|
||||
testEventOrder();
|
||||
testOnWheelAttr();
|
||||
testOnWheelProperty();
|
||||
|
||||
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_x");
|
||||
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_y");
|
||||
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_z");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_x");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_y");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_alt.delta_multiplier_z");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_x");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_y");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_control.delta_multiplier_z");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_x");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_y");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_meta.delta_multiplier_z");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_x");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_y");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_shift.delta_multiplier_z");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_x");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_y");
|
||||
SpecialPowers.clearUserPref("mousewheel.with_win.delta_multiplier_z");
|
||||
|
||||
SimpleTest.finish();
|
||||
yield* testEventOrder();
|
||||
yield* testOnWheelAttr();
|
||||
yield* testOnWheelProperty();
|
||||
}
|
||||
|
||||
var gTestContinuation = null;
|
||||
|
||||
function continueTest()
|
||||
{
|
||||
if (!gTestContinuation) {
|
||||
gTestContinuation = testBody();
|
||||
}
|
||||
var ret = gTestContinuation.next();
|
||||
if (ret.done) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function runTest()
|
||||
{
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["mousewheel.default.delta_multiplier_x", 100],
|
||||
["mousewheel.default.delta_multiplier_y", 100],
|
||||
["mousewheel.default.delta_multiplier_z", 100],
|
||||
["mousewheel.with_alt.delta_multiplier_x", 100],
|
||||
["mousewheel.with_alt.delta_multiplier_y", 100],
|
||||
["mousewheel.with_alt.delta_multiplier_z", 100],
|
||||
["mousewheel.with_control.delta_multiplier_x", 100],
|
||||
["mousewheel.with_control.delta_multiplier_y", 100],
|
||||
["mousewheel.with_control.delta_multiplier_z", 100],
|
||||
["mousewheel.with_meta.delta_multiplier_x", 100],
|
||||
["mousewheel.with_meta.delta_multiplier_y", 100],
|
||||
["mousewheel.with_meta.delta_multiplier_z", 100],
|
||||
["mousewheel.with_shift.delta_multiplier_x", 100],
|
||||
["mousewheel.with_shift.delta_multiplier_y", 100],
|
||||
["mousewheel.with_shift.delta_multiplier_z", 100],
|
||||
["mousewheel.with_win.delta_multiplier_x", 100],
|
||||
["mousewheel.with_win.delta_multiplier_y", 100],
|
||||
["mousewheel.with_win.delta_multiplier_z", 100]]},
|
||||
continueTest);
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -755,7 +755,9 @@ template <class Derived>
|
|||
FetchBody<Derived>::FetchBody()
|
||||
: mFeature(nullptr)
|
||||
, mBodyUsed(false)
|
||||
#ifdef DEBUG
|
||||
, mReadDone(false)
|
||||
#endif
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
|
@ -940,7 +942,9 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
|
|||
MOZ_ASSERT(mBodyUsed);
|
||||
MOZ_ASSERT(!mReadDone);
|
||||
MOZ_ASSERT_IF(mWorkerPrivate, mFeature);
|
||||
#ifdef DEBUG
|
||||
mReadDone = true;
|
||||
#endif
|
||||
|
||||
AutoFreeBuffer autoFree(aResult);
|
||||
|
||||
|
|
|
@ -214,7 +214,9 @@ private:
|
|||
// Only touched on target thread.
|
||||
ConsumeType mConsumeType;
|
||||
RefPtr<Promise> mConsumePromise;
|
||||
DebugOnly<bool> mReadDone;
|
||||
#ifdef DEBUG
|
||||
bool mReadDone;
|
||||
#endif
|
||||
|
||||
nsMainThreadPtrHandle<nsIInputStreamPump> mConsumeBodyPump;
|
||||
};
|
||||
|
|
|
@ -50,8 +50,10 @@ FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
|
|||
: mPrincipal(aPrincipal)
|
||||
, mLoadGroup(aLoadGroup)
|
||||
, mRequest(aRequest)
|
||||
#ifdef DEBUG
|
||||
, mResponseAvailableCalled(false)
|
||||
, mFetchCalled(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -66,8 +68,10 @@ nsresult
|
|||
FetchDriver::Fetch(FetchDriverObserver* aObserver)
|
||||
{
|
||||
workers::AssertIsOnMainThread();
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!mFetchCalled);
|
||||
mFetchCalled = true;
|
||||
#endif
|
||||
|
||||
mObserver = aObserver;
|
||||
|
||||
|
@ -412,7 +416,9 @@ FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse,
|
|||
MOZ_ASSERT(filteredResponse);
|
||||
MOZ_ASSERT(mObserver);
|
||||
mObserver->OnResponseAvailable(filteredResponse);
|
||||
#ifdef DEBUG
|
||||
mResponseAvailableCalled = true;
|
||||
#endif
|
||||
return filteredResponse.forget();
|
||||
}
|
||||
|
||||
|
@ -423,7 +429,9 @@ FetchDriver::FailWithNetworkError()
|
|||
RefPtr<InternalResponse> error = InternalResponse::NetworkError();
|
||||
if (mObserver) {
|
||||
mObserver->OnResponseAvailable(error);
|
||||
#ifdef DEBUG
|
||||
mResponseAvailableCalled = true;
|
||||
#endif
|
||||
mObserver->OnResponseEnd();
|
||||
mObserver = nullptr;
|
||||
}
|
||||
|
|
|
@ -83,8 +83,10 @@ private:
|
|||
RefPtr<FetchDriverObserver> mObserver;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
|
||||
DebugOnly<bool> mResponseAvailableCalled;
|
||||
DebugOnly<bool> mFetchCalled;
|
||||
#ifdef DEBUG
|
||||
bool mResponseAvailableCalled;
|
||||
bool mFetchCalled;
|
||||
#endif
|
||||
|
||||
FetchDriver() = delete;
|
||||
FetchDriver(const FetchDriver&) = delete;
|
||||
|
|
|
@ -5653,7 +5653,9 @@ struct ConnectionPool::TransactionInfo final
|
|||
const bool mIsWriteTransaction;
|
||||
bool mRunning;
|
||||
|
||||
DebugOnly<bool> mFinished;
|
||||
#ifdef DEBUG
|
||||
bool mFinished;
|
||||
#endif
|
||||
|
||||
TransactionInfo(DatabaseInfo* aDatabaseInfo,
|
||||
const nsID& aBackgroundChildLoggingId,
|
||||
|
@ -5913,7 +5915,9 @@ private:
|
|||
class MOZ_STACK_CLASS DatabaseOperationBase::AutoSetProgressHandler final
|
||||
{
|
||||
mozIStorageConnection* mConnection;
|
||||
DebugOnly<DatabaseOperationBase*> mDEBUGDatabaseOp;
|
||||
#ifdef DEBUG
|
||||
DatabaseOperationBase* mDEBUGDatabaseOp;
|
||||
#endif
|
||||
|
||||
public:
|
||||
AutoSetProgressHandler();
|
||||
|
@ -6014,7 +6018,9 @@ class Factory final
|
|||
|
||||
RefPtr<DatabaseLoggingInfo> mLoggingInfo;
|
||||
|
||||
DebugOnly<bool> mActorDestroyed;
|
||||
#ifdef DEBUG
|
||||
bool mActorDestroyed;
|
||||
#endif
|
||||
|
||||
public:
|
||||
static already_AddRefed<Factory>
|
||||
|
@ -7924,7 +7930,9 @@ class NormalTransactionOp
|
|||
: public TransactionDatabaseOperationBase
|
||||
, public PBackgroundIDBRequestParent
|
||||
{
|
||||
DebugOnly<bool> mResponseSent;
|
||||
#ifdef DEBUG
|
||||
bool mResponseSent;
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual void
|
||||
|
@ -7933,7 +7941,9 @@ public:
|
|||
protected:
|
||||
explicit NormalTransactionOp(TransactionBase* aTransaction)
|
||||
: TransactionDatabaseOperationBase(aTransaction)
|
||||
#ifdef DEBUG
|
||||
, mResponseSent(false)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
virtual
|
||||
|
@ -8392,13 +8402,17 @@ protected:
|
|||
|
||||
CursorResponse mResponse;
|
||||
|
||||
DebugOnly<bool> mResponseSent;
|
||||
#ifdef DEBUG
|
||||
bool mResponseSent;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
explicit CursorOpBase(Cursor* aCursor)
|
||||
: TransactionDatabaseOperationBase(aCursor->mTransaction)
|
||||
, mCursor(aCursor)
|
||||
#ifdef DEBUG
|
||||
, mResponseSent(false)
|
||||
#endif
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aCursor);
|
||||
|
@ -9245,16 +9259,20 @@ class MOZ_STACK_CLASS DatabaseMaintenance::AutoProgressHandler final
|
|||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
#ifdef DEBUG
|
||||
// This class is stack-based so we never actually allow AddRef/Release to do
|
||||
// anything. But we need to know if any consumer *thinks* that they have a
|
||||
// reference to this object so we track the reference countin DEBUG builds.
|
||||
DebugOnly<nsrefcnt> mDEBUGRefCnt;
|
||||
nsrefcnt mDEBUGRefCnt;
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit AutoProgressHandler(Maintenance* aMaintenance)
|
||||
: mMaintenance(aMaintenance)
|
||||
, mConnection(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mDEBUGRefCnt(0)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
|
@ -12642,7 +12660,9 @@ TransactionInfo::TransactionInfo(
|
|||
, mObjectStoreNames(aObjectStoreNames)
|
||||
, mIsWriteTransaction(aIsWriteTransaction)
|
||||
, mRunning(false)
|
||||
#ifdef DEBUG
|
||||
, mFinished(false)
|
||||
#endif
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aDatabaseInfo);
|
||||
|
@ -12793,7 +12813,9 @@ uint64_t Factory::sFactoryInstanceCount = 0;
|
|||
|
||||
Factory::Factory(already_AddRefed<DatabaseLoggingInfo> aLoggingInfo)
|
||||
: mLoggingInfo(Move(aLoggingInfo))
|
||||
#ifdef DEBUG
|
||||
, mActorDestroyed(false)
|
||||
#endif
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
|
||||
|
@ -12882,7 +12904,9 @@ Factory::ActorDestroy(ActorDestroyReason aWhy)
|
|||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!mActorDestroyed);
|
||||
|
||||
#ifdef DEBUG
|
||||
mActorDestroyed = true;
|
||||
#endif
|
||||
|
||||
// Clean up if there are no more instances.
|
||||
if (!(--sFactoryInstanceCount)) {
|
||||
|
@ -18205,7 +18229,9 @@ AutoProgressHandler::AddRef()
|
|||
{
|
||||
NS_ASSERT_OWNINGTHREAD(DatabaseMaintenance::AutoProgressHandler);
|
||||
|
||||
#ifdef DEBUG
|
||||
mDEBUGRefCnt++;
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -18215,7 +18241,9 @@ AutoProgressHandler::Release()
|
|||
{
|
||||
NS_ASSERT_OWNINGTHREAD(DatabaseMaintenance::AutoProgressHandler);
|
||||
|
||||
#ifdef DEBUG
|
||||
mDEBUGRefCnt--;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -19203,7 +19231,9 @@ DatabaseOperationBase::OnProgress(mozIStorageConnection* aConnection,
|
|||
DatabaseOperationBase::
|
||||
AutoSetProgressHandler::AutoSetProgressHandler()
|
||||
: mConnection(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mDEBUGDatabaseOp(nullptr)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
}
|
||||
|
@ -19244,7 +19274,9 @@ AutoSetProgressHandler::Register(mozIStorageConnection* aConnection,
|
|||
MOZ_ASSERT(!oldProgressHandler);
|
||||
|
||||
mConnection = aConnection;
|
||||
#ifdef DEBUG
|
||||
mDEBUGDatabaseOp = aDatabaseOp;
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -24352,7 +24384,9 @@ NormalTransactionOp::SendSuccessResult()
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
mResponseSent = true;
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -24371,7 +24405,9 @@ NormalTransactionOp::SendFailureResult(nsresult aResultCode)
|
|||
ClampResultCode(aResultCode));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
mResponseSent = true;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -26062,7 +26098,9 @@ CursorOpBase::SendFailureResult(nsresult aResultCode)
|
|||
mCursor->SendResponseInternal(mResponse, mFiles);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
mResponseSent = true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27072,7 +27110,9 @@ OpenOp::SendSuccessResult()
|
|||
|
||||
mCursor->SendResponseInternal(mResponse, mFiles);
|
||||
|
||||
#ifdef DEBUG
|
||||
mResponseSent = true;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -27248,7 +27288,9 @@ ContinueOp::SendSuccessResult()
|
|||
|
||||
mCursor->SendResponseInternal(mResponse, mFiles);
|
||||
|
||||
#ifdef DEBUG
|
||||
mResponseSent = true;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -297,7 +297,9 @@ TabParent::TabParent(nsIContentParent* aManager,
|
|||
, mCursor(nsCursor(-1))
|
||||
, mTabSetsCursor(false)
|
||||
, mHasContentOpener(false)
|
||||
#ifdef DEBUG
|
||||
, mActiveSupressDisplayportCount(0)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aManager);
|
||||
}
|
||||
|
@ -2835,13 +2837,14 @@ TabParent::SuppressDisplayport(bool aEnabled)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aEnabled) {
|
||||
mActiveSupressDisplayportCount++;
|
||||
} else {
|
||||
mActiveSupressDisplayportCount--;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mActiveSupressDisplayportCount >= 0);
|
||||
#endif
|
||||
|
||||
Unused << SendSuppressDisplayport(aEnabled);
|
||||
return NS_OK;
|
||||
|
|
|
@ -720,7 +720,9 @@ private:
|
|||
|
||||
bool mHasContentOpener;
|
||||
|
||||
DebugOnly<int32_t> mActiveSupressDisplayportCount;
|
||||
#ifdef DEBUG
|
||||
int32_t mActiveSupressDisplayportCount;
|
||||
#endif
|
||||
|
||||
ShowInfo GetShowInfo();
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "CubebUtils.h"
|
||||
|
||||
#include "webrtc/MediaEngineWebRTC.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
@ -606,15 +608,22 @@ AudioCallbackDriver::Init()
|
|||
input = output;
|
||||
input.channels = mInputChannels; // change to support optional stereo capture
|
||||
|
||||
cubeb_stream* stream;
|
||||
// XXX Only pass input input if we have an input listener. Always
|
||||
// set up output because it's easier, and it will just get silence.
|
||||
// XXX Add support for adding/removing an input listener later.
|
||||
if (cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
|
||||
cubeb_stream* stream = nullptr;
|
||||
CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
|
||||
// We have to translate the deviceID values to cubeb devid's since those can be
|
||||
// freed whenever enumerate is called.
|
||||
if ((!mGraphImpl->mInputWanted ||
|
||||
AudioInputCubeb::GetDeviceID(mGraphImpl->mInputDeviceID, input_id)) &&
|
||||
(mGraphImpl->mOutputDeviceID == -1 || // pass nullptr for ID for default output
|
||||
AudioInputCubeb::GetDeviceID(mGraphImpl->mOutputDeviceID, output_id)) &&
|
||||
// XXX Only pass input input if we have an input listener. Always
|
||||
// set up output because it's easier, and it will just get silence.
|
||||
// XXX Add support for adding/removing an input listener later.
|
||||
cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
|
||||
"AudioCallbackDriver",
|
||||
mGraphImpl->mInputDeviceID,
|
||||
input_id,
|
||||
mGraphImpl->mInputWanted ? &input : nullptr,
|
||||
mGraphImpl->mOutputDeviceID,
|
||||
output_id,
|
||||
mGraphImpl->mOutputWanted ? &output : nullptr, latency,
|
||||
DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
|
||||
mAudioStream.own(stream);
|
||||
|
|
|
@ -695,22 +695,6 @@ MediaDecoderStateMachine::Push(MediaData* aSample, MediaData::Type aSampleType)
|
|||
DispatchDecodeTasksIfNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::PushFront(MediaData* aSample, MediaData::Type aSampleType)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aSample);
|
||||
if (aSample->mType == MediaData::AUDIO_DATA) {
|
||||
AudioQueue().PushFront(aSample);
|
||||
} else if (aSample->mType == MediaData::VIDEO_DATA) {
|
||||
aSample->As<VideoData>()->mFrameID = ++mCurrentFrameID;
|
||||
VideoQueue().PushFront(aSample);
|
||||
} else {
|
||||
// TODO: Handle MediaRawData, determine which queue should be pushed.
|
||||
}
|
||||
UpdateNextFrameStatus();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::CheckIsAudible(const MediaData* aSample)
|
||||
{
|
||||
|
@ -885,7 +869,8 @@ MediaDecoderStateMachine::MaybeFinishDecodeFirstFrame()
|
|||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
||||
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample,
|
||||
TimeStamp aDecodeStartTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
RefPtr<MediaData> video(aVideoSample);
|
||||
|
@ -931,7 +916,7 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
|||
if (mReader->IsAsync()) {
|
||||
return;
|
||||
}
|
||||
TimeDuration decodeTime = TimeStamp::Now() - mVideoDecodeStartTime;
|
||||
TimeDuration decodeTime = TimeStamp::Now() - aDecodeStartTime;
|
||||
if (!IsDecodingFirstFrame() &&
|
||||
THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
|
||||
!HasLowUndecodedData())
|
||||
|
@ -1768,24 +1753,32 @@ MediaDecoderStateMachine::RequestVideoData()
|
|||
// Time the video decode, so that if it's slow, we can increase our low
|
||||
// audio threshold to reduce the chance of an audio underrun while we're
|
||||
// waiting for a video decode to complete.
|
||||
mVideoDecodeStartTime = TimeStamp::Now();
|
||||
TimeStamp videoDecodeStartTime = TimeStamp::Now();
|
||||
|
||||
bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
|
||||
NeedToSkipToNextKeyframe();
|
||||
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
|
||||
|
||||
int64_t currentTime =
|
||||
mState == DECODER_STATE_SEEKING || !mSentFirstFrameLoadedEvent
|
||||
? 0 : GetMediaTime() + StartTime();
|
||||
|
||||
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
|
||||
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
|
||||
currentTime);
|
||||
|
||||
RefPtr<MediaDecoderStateMachine> self = this;
|
||||
if (mSentFirstFrameLoadedEvent) {
|
||||
mVideoDataRequest.Begin(
|
||||
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData,
|
||||
skipToNextKeyFrame, currentTime)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
|
||||
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
|
||||
},
|
||||
[self] (MediaDecoderReader::NotDecodedReason aReason) {
|
||||
self->OnVideoNotDecoded(aReason);
|
||||
}));
|
||||
} else {
|
||||
mVideoDataRequest.Begin(
|
||||
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
|
@ -1795,9 +1788,13 @@ MediaDecoderStateMachine::RequestVideoData()
|
|||
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise, MediaData::VIDEO_DATA>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<MediaData::VIDEO_DATA>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
|
||||
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
|
||||
},
|
||||
[self] (MediaDecoderReader::NotDecodedReason aReason) {
|
||||
self->OnVideoNotDecoded(aReason);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2524,7 +2521,8 @@ MediaDecoderStateMachine::DropVideoUpToSeekTarget(MediaData* aSample)
|
|||
DECODER_LOG("DropVideoUpToSeekTarget() found video frame [%lld, %lld] containing target=%lld",
|
||||
video->mTime, video->GetEndTime(), target);
|
||||
|
||||
PushFront(video, MediaData::VIDEO_DATA);
|
||||
MOZ_ASSERT(VideoQueue().GetSize() == 0, "Should be the 1st sample after seeking");
|
||||
Push(video, MediaData::VIDEO_DATA);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2600,7 +2598,8 @@ MediaDecoderStateMachine::DropAudioUpToSeekTarget(MediaData* aSample)
|
|||
Move(audioData),
|
||||
channels,
|
||||
audio->mRate));
|
||||
PushFront(data, MediaData::AUDIO_DATA);
|
||||
MOZ_ASSERT(AudioQueue().GetSize() == 0, "Should be the 1st sample after seeking");
|
||||
Push(data, MediaData::AUDIO_DATA);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -364,7 +364,7 @@ private:
|
|||
// TODO: Those callback function may receive demuxed-only data.
|
||||
// Need to figure out a suitable API name for this case.
|
||||
void OnAudioDecoded(MediaData* aAudioSample);
|
||||
void OnVideoDecoded(MediaData* aVideoSample);
|
||||
void OnVideoDecoded(MediaData* aVideoSample, TimeStamp aDecodeStartTime);
|
||||
void OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason);
|
||||
void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
|
||||
{
|
||||
|
@ -392,7 +392,6 @@ protected:
|
|||
// aSample must not be null.
|
||||
|
||||
void Push(MediaData* aSample, MediaData::Type aSampleType);
|
||||
void PushFront(MediaData* aSample, MediaData::Type aSampleType);
|
||||
|
||||
void OnAudioPopped(const RefPtr<MediaData>& aSample);
|
||||
void OnVideoPopped(const RefPtr<MediaData>& aSample);
|
||||
|
@ -789,11 +788,6 @@ private:
|
|||
bool HaveStartTime() { return mStartTimeRendezvous && mStartTimeRendezvous->HaveStartTime(); }
|
||||
int64_t StartTime() { return mStartTimeRendezvous->StartTime(); }
|
||||
|
||||
// Time at which the last video sample was requested. If it takes too long
|
||||
// before the sample arrives, we will increase the amount of audio we buffer.
|
||||
// This is necessary for legacy synchronous decoders to prevent underruns.
|
||||
TimeStamp mVideoDecodeStartTime;
|
||||
|
||||
// Queue of audio frames. This queue is threadsafe, and is accessed from
|
||||
// the audio, decoder, state machine, and main threads.
|
||||
MediaQueue<MediaData> mAudioQueue;
|
||||
|
|
|
@ -23,7 +23,6 @@ class CDMProxy;
|
|||
class MediaFormatReader final : public MediaDecoderReader
|
||||
{
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
typedef media::Interval<int64_t> ByteInterval;
|
||||
|
||||
public:
|
||||
MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
||||
|
|
|
@ -1510,11 +1510,11 @@ MediaManager::IsInMediaThread()
|
|||
MediaManager::Get() {
|
||||
if (!sSingleton) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
#ifdef DEBUG
|
||||
|
||||
static int timesCreated = 0;
|
||||
timesCreated++;
|
||||
MOZ_ASSERT(timesCreated == 1);
|
||||
#endif
|
||||
MOZ_RELEASE_ASSERT(timesCreated == 1);
|
||||
|
||||
sSingleton = new MediaManager();
|
||||
|
||||
sSingleton->mMediaThread = new base::Thread("MediaManager");
|
||||
|
@ -3291,8 +3291,12 @@ GetUserMediaCallbackMediaStreamListener::NotifyFinished()
|
|||
mFinished = true;
|
||||
Stop(); // we know it's been activated
|
||||
|
||||
RefPtr<MediaManager> manager(MediaManager::GetInstance());
|
||||
manager->RemoveFromWindowList(mWindowID, this);
|
||||
RefPtr<MediaManager> manager(MediaManager::GetIfExists());
|
||||
if (manager) {
|
||||
manager->RemoveFromWindowList(mWindowID, this);
|
||||
} else {
|
||||
NS_WARNING("Late NotifyFinished after MediaManager shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
// Called from the MediaStreamGraph thread
|
||||
|
|
|
@ -104,7 +104,8 @@ MediaStreamGraphImpl::AddStreamGraphThread(MediaStream* aStream)
|
|||
STREAM_LOG(LogLevel::Debug, ("Adding media stream %p to the graph, in the suspended stream array", aStream));
|
||||
} else {
|
||||
mStreams.AppendElement(aStream);
|
||||
STREAM_LOG(LogLevel::Debug, ("Adding media stream %p to the graph", aStream));
|
||||
STREAM_LOG(LogLevel::Debug, ("Adding media stream %p to graph %p, count %lu", aStream, this, mStreams.Length()));
|
||||
LIFECYCLE_LOG("Adding media stream %p to graph %p, count %lu", aStream, this, mStreams.Length());
|
||||
}
|
||||
|
||||
SetStreamOrderDirty();
|
||||
|
@ -134,9 +135,12 @@ MediaStreamGraphImpl::RemoveStreamGraphThread(MediaStream* aStream)
|
|||
mStreams.RemoveElement(aStream);
|
||||
}
|
||||
|
||||
NS_RELEASE(aStream); // probably destroying it
|
||||
STREAM_LOG(LogLevel::Debug, ("Removed media stream %p from graph %p, count %lu",
|
||||
aStream, this, mStreams.Length()))
|
||||
LIFECYCLE_LOG("Removed media stream %p from graph %p, count %lu",
|
||||
aStream, this, mStreams.Length());
|
||||
|
||||
STREAM_LOG(LogLevel::Debug, ("Removing media stream %p from the graph", aStream));
|
||||
NS_RELEASE(aStream); // probably destroying it
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -336,19 +340,19 @@ namespace {
|
|||
const uint32_t IN_MUTED_CYCLE = 1;
|
||||
} // namespace
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::UpdateStreamOrder()
|
||||
bool
|
||||
MediaStreamGraphImpl::AudioTrackPresent(bool& aNeedsAEC)
|
||||
{
|
||||
#ifdef MOZ_WEBRTC
|
||||
bool shouldAEC = false;
|
||||
#endif
|
||||
bool audioTrackPresent = false;
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
for (uint32_t i = 0; i < mStreams.Length() && audioTrackPresent == false; ++i) {
|
||||
MediaStream* stream = mStreams[i];
|
||||
SourceMediaStream* source = stream->AsSourceStream();
|
||||
#ifdef MOZ_WEBRTC
|
||||
if (stream->AsSourceStream() &&
|
||||
stream->AsSourceStream()->NeedsMixing()) {
|
||||
shouldAEC = true;
|
||||
if (source && source->NeedsMixing()) {
|
||||
aNeedsAEC = true;
|
||||
}
|
||||
#endif
|
||||
// If this is a AudioNodeStream, force a AudioCallbackDriver.
|
||||
|
@ -360,14 +364,46 @@ MediaStreamGraphImpl::UpdateStreamOrder()
|
|||
audioTrackPresent = true;
|
||||
}
|
||||
}
|
||||
if (source) {
|
||||
for (auto& data : source->mPendingTracks) {
|
||||
if (data.mData->GetType() == MediaSegment::AUDIO) {
|
||||
audioTrackPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX For some reason, there are race conditions when starting an audio input where
|
||||
// we find no active audio tracks. In any case, if we have an active audio input we
|
||||
// should not allow a switch back to a SystemClockDriver
|
||||
if (!audioTrackPresent && mInputDeviceUsers.Count() != 0) {
|
||||
NS_WARNING("No audio tracks, but full-duplex audio is enabled!!!!!");
|
||||
audioTrackPresent = true;
|
||||
shouldAEC = true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WEBRTC
|
||||
aNeedsAEC = shouldAEC;
|
||||
#endif
|
||||
return audioTrackPresent;
|
||||
}
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::UpdateStreamOrder()
|
||||
{
|
||||
bool shouldAEC = false;
|
||||
bool audioTrackPresent = AudioTrackPresent(shouldAEC);
|
||||
|
||||
// Note that this looks for any audio streams, input or output, and switches to a
|
||||
// SystemClockDriver if there are none
|
||||
// SystemClockDriver if there are none. However, if another is already pending, let that
|
||||
// switch happen.
|
||||
|
||||
if (!audioTrackPresent && mRealtime &&
|
||||
CurrentDriver()->AsAudioCallbackDriver()) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (CurrentDriver()->AsAudioCallbackDriver()->IsStarted()) {
|
||||
if (CurrentDriver()->AsAudioCallbackDriver()->IsStarted() &&
|
||||
!(CurrentDriver()->Switching())) {
|
||||
if (mLifecycleState == LIFECYCLE_RUNNING) {
|
||||
SystemClockDriver* driver = new SystemClockDriver(this);
|
||||
CurrentDriver()->SwitchAtNextIteration(driver);
|
||||
|
@ -935,7 +971,7 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
|||
}
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
|
||||
MediaStreamGraphImpl::OpenAudioInputImpl(int aID,
|
||||
AudioDataListener *aListener)
|
||||
{
|
||||
// Bug 1238038 Need support for multiple mics at once
|
||||
|
@ -957,24 +993,30 @@ MediaStreamGraphImpl::OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
|
|||
count++;
|
||||
mInputDeviceUsers.Put(aListener, count); // creates a new entry in the hash if needed
|
||||
|
||||
// aID is a cubeb_devid, and we assume that opaque ptr is valid until
|
||||
// we close cubeb.
|
||||
mInputDeviceID = aID;
|
||||
if (count == 1) { // first open for this listener
|
||||
// aID is a cubeb_devid, and we assume that opaque ptr is valid until
|
||||
// we close cubeb.
|
||||
mInputDeviceID = aID;
|
||||
mAudioInputs.AppendElement(aListener); // always monitor speaker data
|
||||
}
|
||||
|
||||
// Switch Drivers since we're adding input (to input-only or full-duplex)
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (mLifecycleState == LIFECYCLE_RUNNING) {
|
||||
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
|
||||
driver->SetInputListener(aListener);
|
||||
CurrentDriver()->SwitchAtNextIteration(driver);
|
||||
// Switch Drivers since we're adding input (to input-only or full-duplex)
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (mLifecycleState == LIFECYCLE_RUNNING) {
|
||||
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
|
||||
STREAM_LOG(LogLevel::Debug, ("OpenAudioInput: starting new AudioCallbackDriver(input) %p", driver));
|
||||
LIFECYCLE_LOG("OpenAudioInput: starting new AudioCallbackDriver(input) %p", driver);
|
||||
driver->SetInputListener(aListener);
|
||||
CurrentDriver()->SwitchAtNextIteration(driver);
|
||||
} else {
|
||||
STREAM_LOG(LogLevel::Error, ("OpenAudioInput in shutdown!"));
|
||||
LIFECYCLE_LOG("OpenAudioInput in shutdown!");
|
||||
NS_ASSERTION(false, "Can't open cubeb inputs in shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaStreamGraphImpl::OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
MediaStreamGraphImpl::OpenAudioInput(int aID,
|
||||
AudioDataListener *aListener)
|
||||
{
|
||||
// So, so, so annoying. Can't AppendMessage except on Mainthread
|
||||
|
@ -986,7 +1028,7 @@ MediaStreamGraphImpl::OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
|||
}
|
||||
class Message : public ControlMessage {
|
||||
public:
|
||||
Message(MediaStreamGraphImpl *aGraph, CubebUtils::AudioDeviceID aID,
|
||||
Message(MediaStreamGraphImpl *aGraph, int aID,
|
||||
AudioDataListener *aListener) :
|
||||
ControlMessage(nullptr), mGraph(aGraph), mID(aID), mListener(aListener) {}
|
||||
virtual void Run()
|
||||
|
@ -994,9 +1036,7 @@ MediaStreamGraphImpl::OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
|||
mGraph->OpenAudioInputImpl(mID, mListener);
|
||||
}
|
||||
MediaStreamGraphImpl *mGraph;
|
||||
// aID is a cubeb_devid, and we assume that opaque ptr is valid until
|
||||
// we close cubeb.
|
||||
CubebUtils::AudioDeviceID mID;
|
||||
int mID;
|
||||
RefPtr<AudioDataListener> mListener;
|
||||
};
|
||||
// XXX Check not destroyed!
|
||||
|
@ -1015,7 +1055,7 @@ MediaStreamGraphImpl::CloseAudioInputImpl(AudioDataListener *aListener)
|
|||
return; // still in use
|
||||
}
|
||||
mInputDeviceUsers.Remove(aListener);
|
||||
mInputDeviceID = nullptr;
|
||||
mInputDeviceID = -1;
|
||||
mInputWanted = false;
|
||||
AudioCallbackDriver *driver = CurrentDriver()->AsAudioCallbackDriver();
|
||||
if (driver) {
|
||||
|
@ -1024,20 +1064,8 @@ MediaStreamGraphImpl::CloseAudioInputImpl(AudioDataListener *aListener)
|
|||
mAudioInputs.RemoveElement(aListener);
|
||||
|
||||
// Switch Drivers since we're adding or removing an input (to nothing/system or output only)
|
||||
bool audioTrackPresent = false;
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
MediaStream* stream = mStreams[i];
|
||||
// If this is a AudioNodeStream, force a AudioCallbackDriver.
|
||||
if (stream->AsAudioNodeStream()) {
|
||||
audioTrackPresent = true;
|
||||
} else if (CurrentDriver()->AsAudioCallbackDriver()) {
|
||||
// only if there's a real switch!
|
||||
for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer(), MediaSegment::AUDIO);
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
audioTrackPresent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool shouldAEC = false;
|
||||
bool audioTrackPresent = AudioTrackPresent(shouldAEC);
|
||||
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (mLifecycleState == LIFECYCLE_RUNNING) {
|
||||
|
@ -2322,7 +2350,7 @@ MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener)
|
|||
}
|
||||
|
||||
nsresult
|
||||
SourceMediaStream::OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
SourceMediaStream::OpenAudioInput(int aID,
|
||||
AudioDataListener *aListener)
|
||||
{
|
||||
if (GraphImpl()) {
|
||||
|
@ -2371,6 +2399,7 @@ SourceMediaStream::AddTrackInternal(TrackID aID, TrackRate aRate, StreamTime aSt
|
|||
nsTArray<TrackData> *track_data = (aFlags & ADDTRACK_QUEUED) ?
|
||||
&mPendingTracks : &mUpdateTracks;
|
||||
TrackData* data = track_data->AppendElement();
|
||||
LIFECYCLE_LOG("AddTrackInternal: %lu/%lu", mPendingTracks.Length(), mUpdateTracks.Length());
|
||||
data->mID = aID;
|
||||
data->mInputRate = aRate;
|
||||
data->mResamplerChannelCount = 0;
|
||||
|
@ -2388,6 +2417,7 @@ SourceMediaStream::FinishAddTracks()
|
|||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mUpdateTracks.AppendElements(Move(mPendingTracks));
|
||||
LIFECYCLE_LOG("FinishAddTracks: %lu/%lu", mPendingTracks.Length(), mUpdateTracks.Length());
|
||||
if (GraphImpl()) {
|
||||
GraphImpl()->EnsureNextIteration();
|
||||
}
|
||||
|
@ -2808,9 +2838,9 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
|||
: MediaStreamGraph(aSampleRate)
|
||||
, mPortCount(0)
|
||||
, mInputWanted(false)
|
||||
, mInputDeviceID(nullptr)
|
||||
, mInputDeviceID(-1)
|
||||
, mOutputWanted(true)
|
||||
, mOutputDeviceID(nullptr)
|
||||
, mOutputDeviceID(-1)
|
||||
, mNeedAnotherIteration(false)
|
||||
, mGraphDriverAsleep(false)
|
||||
, mMonitor("MediaStreamGraphImpl")
|
||||
|
@ -3271,17 +3301,9 @@ MediaStreamGraphImpl::ApplyAudioContextOperationImpl(
|
|||
// This is the same logic as in UpdateStreamOrder, but it's simpler to have it
|
||||
// here as well so we don't have to store the Promise(s) on the Graph.
|
||||
if (aOperation != AudioContextOperation::Resume) {
|
||||
bool audioTrackPresent = false;
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
MediaStream* stream = mStreams[i];
|
||||
if (stream->AsAudioNodeStream()) {
|
||||
audioTrackPresent = true;
|
||||
}
|
||||
for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer(), MediaSegment::AUDIO);
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
audioTrackPresent = true;
|
||||
}
|
||||
}
|
||||
bool shouldAEC = false;
|
||||
bool audioTrackPresent = AudioTrackPresent(shouldAEC);
|
||||
|
||||
if (!audioTrackPresent && CurrentDriver()->AsAudioCallbackDriver()) {
|
||||
CurrentDriver()->AsAudioCallbackDriver()->
|
||||
EnqueueStreamAndPromiseForOperation(aDestinationStream, aPromise,
|
||||
|
|
|
@ -739,7 +739,7 @@ public:
|
|||
// last stream referencing an input goes away, so it can close the cubeb
|
||||
// input. Also note: callable on any thread (though it bounces through
|
||||
// MainThread to set the command if needed).
|
||||
nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
nsresult OpenAudioInput(int aID,
|
||||
AudioDataListener *aListener);
|
||||
// Note: also implied when Destroy() happens
|
||||
void CloseAudioInput();
|
||||
|
@ -1224,7 +1224,7 @@ public:
|
|||
// Idempotent
|
||||
static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
|
||||
|
||||
virtual nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
virtual nsresult OpenAudioInput(int aID,
|
||||
AudioDataListener *aListener) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -185,10 +185,6 @@ public:
|
|||
* This is called during application shutdown.
|
||||
*/
|
||||
void ForceShutDown(ShutdownTicket* aShutdownTicket);
|
||||
/**
|
||||
* Shutdown() this MediaStreamGraph's threads and return when they've shut down.
|
||||
*/
|
||||
void ShutdownThreads();
|
||||
|
||||
/**
|
||||
* Called before the thread runs.
|
||||
|
@ -333,6 +329,12 @@ public:
|
|||
void SuspendOrResumeStreams(dom::AudioContextOperation aAudioContextOperation,
|
||||
const nsTArray<MediaStream*>& aStreamSet);
|
||||
|
||||
/**
|
||||
* Determine if we have any audio tracks, or are about to add any audiotracks.
|
||||
* Also checks if we'll need the AEC running (i.e. microphone input tracks)
|
||||
*/
|
||||
bool AudioTrackPresent(bool& aNeedsAEC);
|
||||
|
||||
/**
|
||||
* Sort mStreams so that every stream not in a cycle is after any streams
|
||||
* it depends on, and every stream in a cycle is marked as being in a cycle.
|
||||
|
@ -389,9 +391,9 @@ public:
|
|||
* at the current buffer end point. The StreamBuffer's tracks must be
|
||||
* explicitly set to finished by the caller.
|
||||
*/
|
||||
void OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
|
||||
void OpenAudioInputImpl(int aID,
|
||||
AudioDataListener *aListener);
|
||||
virtual nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
virtual nsresult OpenAudioInput(int aID,
|
||||
AudioDataListener *aListener) override;
|
||||
void CloseAudioInputImpl(AudioDataListener *aListener);
|
||||
virtual void CloseAudioInput(AudioDataListener *aListener) override;
|
||||
|
@ -628,9 +630,9 @@ public:
|
|||
* and boolean to control if we want input/output
|
||||
*/
|
||||
bool mInputWanted;
|
||||
CubebUtils::AudioDeviceID mInputDeviceID;
|
||||
int mInputDeviceID;
|
||||
bool mOutputWanted;
|
||||
CubebUtils::AudioDeviceID mOutputDeviceID;
|
||||
int mOutputDeviceID;
|
||||
// Maps AudioDataListeners to a usecount of streams using the listener
|
||||
// so we can know when it's no longer in use.
|
||||
nsDataHashtable<nsPtrHashKey<AudioDataListener>, uint32_t> mInputDeviceUsers;
|
||||
|
|
|
@ -366,6 +366,8 @@ RTCPeerConnection.prototype = {
|
|||
Services.prefs.getBoolPref("media.peerconnection.ice.relay_only")) {
|
||||
rtcConfig.iceTransportPolicy = "relay";
|
||||
}
|
||||
this._config = Object.assign({}, rtcConfig);
|
||||
|
||||
if (!rtcConfig.iceServers ||
|
||||
!Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
|
||||
try {
|
||||
|
@ -452,6 +454,10 @@ RTCPeerConnection.prototype = {
|
|||
return this._pc;
|
||||
},
|
||||
|
||||
getConfiguration: function() {
|
||||
return this._config;
|
||||
},
|
||||
|
||||
_initCertificate: function(certificates) {
|
||||
let certPromise;
|
||||
if (certificates && certificates.length > 0) {
|
||||
|
|
|
@ -28,7 +28,7 @@ GetDirectShowLog() {
|
|||
DirectShowReader::DirectShowReader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder),
|
||||
mMP3FrameParser(aDecoder->GetResource()->GetLength()),
|
||||
#ifdef DEBUG
|
||||
#ifdef DIRECTSHOW_REGISTER_GRAPH
|
||||
mRotRegister(0),
|
||||
#endif
|
||||
mNumChannels(0),
|
||||
|
@ -44,7 +44,7 @@ DirectShowReader::~DirectShowReader()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_COUNT_DTOR(DirectShowReader);
|
||||
#ifdef DEBUG
|
||||
#ifdef DIRECTSHOW_REGISTER_GRAPH
|
||||
if (mRotRegister) {
|
||||
RemoveGraphFromRunningObjectTable(mRotRegister);
|
||||
}
|
||||
|
@ -104,11 +104,7 @@ DirectShowReader::ReadMetadata(MediaInfo* aInfo,
|
|||
rv = ParseMP3Headers(&mMP3FrameParser, mDecoder->GetResource());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Add the graph to the Running Object Table so that we can connect
|
||||
// to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must
|
||||
// also regsvr32 proppage.dll from the Windows SDK.
|
||||
// See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx
|
||||
#ifdef DIRECTSHOW_REGISTER_GRAPH
|
||||
hr = AddGraphToRunningObjectTable(mGraph, &mRotRegister);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "MP3FrameParser.h"
|
||||
|
||||
// Add the graph to the Running Object Table so that we can connect
|
||||
// to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must
|
||||
// also regsvr32 proppage.dll from the Windows SDK.
|
||||
// See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx
|
||||
// #define DIRECTSHOW_REGISTER_GRAPH
|
||||
|
||||
struct IGraphBuilder;
|
||||
struct IMediaControl;
|
||||
struct IMediaSeeking;
|
||||
|
@ -83,7 +89,7 @@ private:
|
|||
// the MP3 frames to get a more accuate estimate of the duration.
|
||||
MP3FrameParser mMP3FrameParser;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DIRECTSHOW_REGISTER_GRAPH
|
||||
// Used to add/remove the filter graph to the Running Object Table. You can
|
||||
// connect GraphEdit/GraphStudio to the graph to observe and/or debug its
|
||||
// topology and state.
|
||||
|
|
|
@ -167,7 +167,7 @@ CanCreateWMFDecoder()
|
|||
static bool
|
||||
IsH264DecoderBlacklisted()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
#ifdef BLACKLIST_CRASHY_H264_DECODERS
|
||||
WCHAR systemPath[MAX_PATH + 1];
|
||||
if (!ConstructSystem32Path(L"msmpeg2vdec.dll", systemPath, MAX_PATH + 1)) {
|
||||
// Cannot build path -> Assume it's not the blacklisted DLL.
|
||||
|
@ -193,7 +193,7 @@ IsH264DecoderBlacklisted()
|
|||
return true;
|
||||
}
|
||||
}
|
||||
#endif // _WIN64
|
||||
#endif // BLACKLIST_CRASHY_H264_DECODERS
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,196 +1,5 @@
|
|||
external-media-tests
|
||||
===================
|
||||
|
||||
[Marionette Python tests][marionette-python-tests] for media playback in Mozilla Firefox. MediaTestCase uses [Firefox Puppeteer][ff-puppeteer-docs] library.
|
||||
Documentation for this library has moved to https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests.
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
Normally, you get this source by cloning a firefox repo such as mozilla-central. The path to these tests would be in <mozilla-central>/dom/media/test/external, and these instructions refer to this path as '$PROJECT_HOME'.
|
||||
|
||||
Running from a build
|
||||
--------------------
|
||||
|
||||
If you have built Firefox using ./mach build from a source tree such as mozilla-central, you can run the following command:
|
||||
|
||||
'''sh
|
||||
$ ./mach external-media-tests
|
||||
'''
|
||||
|
||||
You can pass any of the test options on this command line. They are listed below.
|
||||
|
||||
Running with an installer and a tests payload
|
||||
---------------------------------------------
|
||||
|
||||
If you are testing a version of Firefox that you have not built, you must setup a virtualenv to run tests from. You will need a path to the installer or binary of Firefox.
|
||||
|
||||
* Create a virtualenv called `foo`.
|
||||
|
||||
```sh
|
||||
$ virtualenv foo
|
||||
$ source foo/bin/activate #or `foo\Scripts\activate` on Windows
|
||||
```
|
||||
|
||||
* Install `external-media-tests` in development mode. (To get an environment that is closer to what is actually used in Mozilla's automation jobs, run `pip install -r requirements.txt` first.)
|
||||
|
||||
```sh
|
||||
$ python setup.py develop
|
||||
```
|
||||
|
||||
Now `external-media-tests` should be a recognized command. Try `external-media-tests --help` to see if it works.
|
||||
|
||||
|
||||
Running the Tests
|
||||
-----------------
|
||||
|
||||
In the examples below, `$FF_PATH` is a path to a recent Firefox binary. If you are running from a source build, the commands below should be invoked with:
|
||||
|
||||
'''sh
|
||||
./mach external-media-tests
|
||||
'''
|
||||
|
||||
If you are running with a virtualenv, you will need to run like this:
|
||||
|
||||
'''sh
|
||||
external-media-tests --binary $FF_PATH
|
||||
'''
|
||||
|
||||
or
|
||||
|
||||
'''sh
|
||||
external-media-tests --installer $FF_INSTALLER_PATH
|
||||
'''
|
||||
|
||||
or
|
||||
|
||||
'''sh
|
||||
external-media-tests --installer-url <url to installer package>
|
||||
'''
|
||||
|
||||
The following examples assume that you will use of these command lines instead of $EXTERNAL-MEDIA-TESTS.
|
||||
|
||||
|
||||
This runs all the tests listed in `$PROJECT_HOME/external_media_tests/manifest.ini`:
|
||||
|
||||
```sh
|
||||
$ $EXTERNAL-MEDIA-TESTS
|
||||
```
|
||||
|
||||
You can also run all the tests at a particular path:
|
||||
|
||||
```sh
|
||||
$ $EXTERNAL-MEDIA-TESTS some/path/foo
|
||||
```
|
||||
|
||||
Or you can run the tests that are listed in a manifest file of your choice.
|
||||
|
||||
```sh
|
||||
$ $EXTERNAL-MEDIA-TESTS some/other/path/manifest.ini
|
||||
```
|
||||
|
||||
By default, the urls listed in `external_media_tests/urls/default.ini` are used for the tests, but you can also supply your own ini file of urls:
|
||||
|
||||
```sh
|
||||
$ $EXTERNAL-MEDIA-TESTS --urls some/other/path/my_urls.ini
|
||||
```
|
||||
|
||||
### Running EME tests
|
||||
|
||||
In order to run EME tests, you must use a Firefox profile that has a signed plugin-container.exe and voucher.bin. With Netflix, this will be created when you log in and save the credentials. You must also use a custom .ini file for urls to the provider's content and indicate which test to run, like above. Ex:
|
||||
|
||||
```sh
|
||||
$ $EXTERNAL-MEDIA-TESTS some/path/tests.ini --profile custom_profile --urls some/path/provider-urls.ini
|
||||
```
|
||||
|
||||
|
||||
### Running tests in a way that provides information about a crash
|
||||
|
||||
What if Firefox crashes during a test run? You want to know why! To report useful crash data, the test runner needs access to a "minidump_stackwalk" binary and a "symbols.zip" file.
|
||||
|
||||
1. Download a `minidump_stackwalk` binary for your platform (save it wherever). Get it from http://hg.mozilla.org/build/tools/file/tip/breakpad/.
|
||||
2. Make `minidump_stackwalk` executable
|
||||
|
||||
```sh
|
||||
$ chmod +x path/to/minidump_stackwalk
|
||||
```
|
||||
|
||||
3. Create an environment variable called `MINIDUMP_STACKWALK` that points to that local path
|
||||
|
||||
```sh
|
||||
$ export MINIDUMP_STACKWALK=path/to/minidump_stackwalk
|
||||
```
|
||||
|
||||
4. Download the `crashreporter-symbols.zip` file for the Firefox build you are testing and extract it. Example: ftp://ftp.mozilla.org/pub/firefox/tinderbox-builds/mozilla-aurora-win32/1427442016/firefox-38.0a2.en-US.win32.crashreporter-symbols.zip
|
||||
|
||||
5. Run the tests with a `--symbols-path` flag
|
||||
|
||||
```sh
|
||||
$ $EXTERNAL-MEDIA-TESTS --symbols-path path/to/example/firefox-38.0a2.en-US.win32.crashreporter-symbols
|
||||
```
|
||||
|
||||
To check whether the above setup is working for you, trigger a (silly) Firefox crash while the tests are running. One way to do this is with the [crashme add-on](https://github.com/luser/crashme) -- you can add it to Firefox even while the tests are running. Another way on Linux and Mac OS systems:
|
||||
|
||||
1. Find the process id (PID) of the Firefox process being used by the tests.
|
||||
|
||||
```sh
|
||||
$ ps x | grep 'Firefox'
|
||||
```
|
||||
|
||||
2. Kill the Firefox process with SIGABRT.
|
||||
```sh
|
||||
# 1234 is an example of a PID
|
||||
$ kill -6 1234
|
||||
```
|
||||
|
||||
Somewhere in the output produced by `external-media-tests`, you should see something like:
|
||||
|
||||
```
|
||||
0:12.68 CRASH: MainThread pid:1234. Test:test_basic_playback.py TestVideoPlayback.test_playback_starts.
|
||||
Minidump anaylsed:False.
|
||||
Signature:[@ XUL + 0x2a65900]
|
||||
Crash dump filename:
|
||||
/var/folders/5k/xmn_fndx0qs2jcpcwhzl86wm0000gn/T/tmpB4Bolj.mozrunner/minidumps/DA3BB025-8302-4F96-8DF3-A97E424C877A.dmp
|
||||
Operating system: Mac OS X
|
||||
10.10.2 14C1514
|
||||
CPU: amd64
|
||||
family 6 model 69 stepping 1
|
||||
4 CPUs
|
||||
|
||||
Crash reason: EXC_SOFTWARE / SIGABRT
|
||||
Crash address: 0x104616900
|
||||
...
|
||||
```
|
||||
|
||||
### Setting up for network shaping tests (browsermobproxy)
|
||||
|
||||
1. Download the browsermob proxy zip file from http://bmp.lightbody.net/. The most current version as of this writing is browsermob-proxy-2.1.0-beta-2-bin.zip.
|
||||
2. Unpack the .zip file.
|
||||
3. Verify that you can launch browsermobproxy on your machine by running \<browsermob\>/bin/browsermob-proxy (or browsermob-proxy.bat on Windows) on your machine. I had to do a lot of work to install and use a java that browsermobproxy would like.
|
||||
4. Import the certificate into your Firefox profile. Select Preferences->Advanced->Certificates->View Certificates->Import... Navigate to <browsermob>/ssl-support and select cybervilliansCA.cer. Select all of the checkboxes.
|
||||
5. Tell marionette where browsermobproxy is and what port to start it on. Add the following command-line parameters to your external-media-tests command line:
|
||||
|
||||
<pre><code>
|
||||
--browsermob-script <browsermob>/bin/browsermob-proxy --browsermob-port 999 --profile <your saved profile>
|
||||
</code></pre>
|
||||
|
||||
You can then call browsermob to shape the network. You can find an example in external_media_tests/playback/test_playback_limiting_bandwidth.py. Another example can be found at https://dxr.mozilla.org/mozilla-central/source/testing/marionette/harness/marionette/tests/unit/test_browsermobproxy.py.
|
||||
|
||||
### A warning about video URLs
|
||||
The ini files in `external_media_tests/urls` may contain URLs pulled from Firefox crash or bug data. Automated tests don't care about video content, but you might: visit these at your own risk and be aware that they may be NSFW. We do not intend to ever moderate or filter these URLs.
|
||||
|
||||
Writing a test
|
||||
--------------
|
||||
Write your test in a new or existing `test_*.py` file under `$PROJECT_HOME/external_media_tests`. Add it to the appropriate `manifest.ini` file(s) as well. Look in `media_utils` for useful video-playback functions.
|
||||
|
||||
* [Marionette docs][marionette-docs]
|
||||
- [Marionette Command Line Options](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options)
|
||||
* [Firefox Puppeteer docs][ff-puppeteer-docs]
|
||||
|
||||
License
|
||||
-------
|
||||
This software is licensed under the [Mozilla Public License v. 2.0](http://mozilla.org/MPL/2.0/).
|
||||
|
||||
[marionette-python-tests]: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Marionette_Python_Tests
|
||||
[ff-puppeteer-docs]: http://firefox-puppeteer.readthedocs.org/en/latest/
|
||||
[marionette-docs]: http://marionette-client.readthedocs.org/en/latest/reference.html
|
||||
[ff-nightly]:https://nightly.mozilla.org/
|
||||
|
|
|
@ -690,7 +690,7 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
|||
skip-if = os == 'win' && !debug # bug 1228605
|
||||
tags=msg
|
||||
[test_mediarecorder_bitrate.html]
|
||||
skip-if = (toolkit == 'gonk' || android_version == '10') # B2G emulator is too slow to run this without timing out and Android doesn't like the seek.webm
|
||||
skip-if = (toolkit == 'gonk' || toolkit == 'android') # B2G emulator is too slow to run this without timing out and Fennec does not support video recording
|
||||
tags=msg
|
||||
[test_mediarecorder_creation.html]
|
||||
tags=msg capturestream
|
||||
|
@ -707,7 +707,7 @@ tags=msg
|
|||
[test_mediarecorder_record_audionode.html]
|
||||
tags=msg
|
||||
[test_mediarecorder_record_canvas_captureStream.html]
|
||||
skip-if = android_version < '17' # Android/Gonk before SDK version 17 does not have the OMX Encoder API.
|
||||
skip-if = (android_version < '17' || toolkit == 'android') # Android/Gonk before SDK version 17 does not have the OMX Encoder API and Fennec does not support video recording
|
||||
tags=msg
|
||||
[test_mediarecorder_record_changing_video_resolution.html]
|
||||
skip-if = android_version < '17' # Android/Gonk before SDK version 17 does not have the OMX Encoder API.
|
||||
|
|
|
@ -9,12 +9,14 @@ var Ci = SpecialPowers.Ci;
|
|||
|
||||
// Specifies whether we are using fake streams to run this automation
|
||||
var FAKE_ENABLED = true;
|
||||
var TEST_AUDIO_FREQ = 1000;
|
||||
try {
|
||||
var audioDevice = SpecialPowers.getCharPref('media.audio_loopback_dev');
|
||||
var videoDevice = SpecialPowers.getCharPref('media.video_loopback_dev');
|
||||
dump('TEST DEVICES: Using media devices:\n');
|
||||
dump('audio: ' + audioDevice + '\nvideo: ' + videoDevice + '\n');
|
||||
FAKE_ENABLED = false;
|
||||
TEST_AUDIO_FREQ = 440;
|
||||
} catch (e) {
|
||||
dump('TEST DEVICES: No test devices found (in media.{audio,video}_loopback_dev, using fake streams.\n');
|
||||
FAKE_ENABLED = true;
|
||||
|
|
|
@ -22,6 +22,16 @@ var makePC = (config, expected_error) => {
|
|||
"RTCPeerConnection(" + JSON.stringify(config) + ")");
|
||||
};
|
||||
|
||||
// The order of properties in objects is not guaranteed in JavaScript, so this
|
||||
// transform produces json-comparable dictionaries. The resulting copy is only
|
||||
// meant to be used in comparisons (e.g. array-ness is not preserved).
|
||||
|
||||
var toComparable = o =>
|
||||
(typeof o != 'object' || !o)? o : Object.keys(o).sort().reduce((co, key) => {
|
||||
co[key] = toComparable(o[key]);
|
||||
return co;
|
||||
}, {});
|
||||
|
||||
// This is a test of the iceServers parsing code + readable errors
|
||||
runNetworkTest(() => {
|
||||
var exception = null;
|
||||
|
@ -72,6 +82,21 @@ runNetworkTest(() => {
|
|||
"RTCPeerConnection() constructor has readable exceptions");
|
||||
}
|
||||
|
||||
// Test getConfiguration
|
||||
var config = {
|
||||
bundlePolicy: "max-bundle",
|
||||
iceTransportPolicy: "relay",
|
||||
peerIdentity: null,
|
||||
iceServers: [
|
||||
{ urls: ["stun:127.0.0.1", "stun:localhost"], credentialType:"password" },
|
||||
{ urls: ["turn:[::1]:3478"], username:"p", credential:"p", credentialType:"token" },
|
||||
],
|
||||
};
|
||||
var pc = new RTCPeerConnection(config);
|
||||
is(JSON.stringify(toComparable(pc.getConfiguration())),
|
||||
JSON.stringify(toComparable(config)), "getConfiguration");
|
||||
pc.close();
|
||||
|
||||
// Below tests are setting the about:config User preferences for default
|
||||
// ice servers and checking the outputs when RTCPeerConnection() is
|
||||
// invoked. See Bug 1167922 for more information.
|
||||
|
|
|
@ -17,7 +17,7 @@ runNetworkTest(() => {
|
|||
var test = new PeerConnectionTest();
|
||||
|
||||
// Always use fake tracks since we depend on video to be somewhat green and
|
||||
// audio to have a large 1000Hz component.
|
||||
// audio to have a large 1000Hz component (or 440Hz if using fake devices).
|
||||
test.setMediaConstraints([{audio: true, video: true, fake: true}], []);
|
||||
test.chain.append([
|
||||
function CHECK_ASSUMPTIONS() {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче