mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Merge m-c to b2g-inbound. a=merge
This commit is contained in:
commit
7941dfa396
@ -355,10 +355,12 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
if (accWrap) {
|
||||
Accessible* acc = accWrap->GetChildAt(i);
|
||||
return acc ? GetNativeFromGeckoAccessible(acc) : nil;
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||
Accessible* child = accWrap->GetChildAt(i);
|
||||
return child ? GetNativeFromGeckoAccessible(child) : nil;
|
||||
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||
ProxyAccessible* child = proxy->ChildAt(i);
|
||||
return child ? GetNativeFromProxy(child) : nil;
|
||||
}
|
||||
|
||||
return nil;
|
||||
@ -849,12 +851,14 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
if (!accWrap)
|
||||
nsIntRect rect;
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible])
|
||||
rect = accWrap->Bounds();
|
||||
else if (ProxyAccessible* proxy = [self getProxyAccessible])
|
||||
rect = proxy->Bounds();
|
||||
else
|
||||
return nil;
|
||||
|
||||
nsIntRect rect = accWrap->Bounds();
|
||||
|
||||
NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
|
||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView);
|
||||
NSPoint p = NSMakePoint(static_cast<CGFloat>(rect.x) / scaleFactor,
|
||||
@ -869,11 +873,14 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
||||
if (!accWrap)
|
||||
nsIntRect rect;
|
||||
if (AccessibleWrap* accWrap = [self getGeckoAccessible])
|
||||
rect = accWrap->Bounds();
|
||||
else if (ProxyAccessible* proxy = [self getProxyAccessible])
|
||||
rect = proxy->Bounds();
|
||||
else
|
||||
return nil;
|
||||
|
||||
nsIntRect rect = accWrap->Bounds();
|
||||
CGFloat scaleFactor =
|
||||
nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]);
|
||||
return [NSValue valueWithSize:NSMakeSize(static_cast<CGFloat>(rect.width) / scaleFactor,
|
||||
|
@ -1118,9 +1118,6 @@ pref("services.mobileid.server.uri", "https://msisdn.services.mozilla.com");
|
||||
pref("dom.mapped_arraybuffer.enabled", true);
|
||||
#endif
|
||||
|
||||
// BroadcastChannel API
|
||||
pref("dom.broadcastChannel.enabled", true);
|
||||
|
||||
// SystemUpdate API
|
||||
pref("dom.system_update.enabled", true);
|
||||
|
||||
|
@ -35,6 +35,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||
|
@ -34,7 +34,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||
FXOS_SIMULATOR=1
|
||||
|
@ -35,6 +35,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||
|
@ -34,7 +34,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||
FXOS_SIMULATOR=1
|
||||
|
@ -32,6 +32,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||
|
@ -30,7 +30,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||
FXOS_SIMULATOR=1
|
||||
|
@ -29,6 +29,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||
|
@ -27,7 +27,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||
FXOS_SIMULATOR=1
|
||||
|
@ -14,10 +14,10 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"filename": "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -14,10 +14,10 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"filename": "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -17,10 +17,10 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"filename": "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -6,10 +6,10 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"filename": "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
|
@ -8,4 +8,4 @@ ac_add_options --enable-default-toolkit=cairo-gtk2
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
@ -24,7 +24,7 @@ ac_add_options --enable-warnings-as-errors
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
@ -10,4 +10,4 @@ MOZ_AUTOMATION_SDK=0
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
||||
# Include Firefox OS fonts.
|
||||
MOZTTDIR=$topsrcdir/moztt
|
||||
MOZTTDIR=$topsrcdir/moz-tt
|
||||
|
@ -14,10 +14,10 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"filename": "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -17,10 +17,10 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"filename": "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -13,10 +13,10 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 31057326,
|
||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
||||
"size": 31078810,
|
||||
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||
"algorithm": "sha512",
|
||||
"filename": "moztt.tar.bz2",
|
||||
"filename": "moz-tt.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -644,6 +644,7 @@
|
||||
@RESPATH@/components/AppsService.manifest
|
||||
@RESPATH@/components/Push.js
|
||||
@RESPATH@/components/Push.manifest
|
||||
@RESPATH@/components/PushClient.js
|
||||
@RESPATH@/components/PushNotificationService.js
|
||||
@RESPATH@/components/PushServiceLauncher.js
|
||||
|
||||
@ -710,6 +711,7 @@
|
||||
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
||||
@RESPATH@/components/nsUrlClassifierListManager.js
|
||||
@RESPATH@/components/nsUrlClassifierLib.js
|
||||
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||
@RESPATH@/components/url-classifier.xpt
|
||||
|
||||
; GNOME hooks
|
||||
|
@ -148,8 +148,13 @@ let wrapper = {
|
||||
|
||||
if (accountData.customizeSync) {
|
||||
Services.prefs.setBoolPref(PREF_SYNC_SHOW_CUSTOMIZATION, true);
|
||||
delete accountData.customizeSync;
|
||||
}
|
||||
delete accountData.customizeSync;
|
||||
// sessionTokenContext is erroneously sent by the content server.
|
||||
// https://github.com/mozilla/fxa-content-server/issues/2766
|
||||
// To avoid having the FxA storage manager not knowing what to do with
|
||||
// it we delete it here.
|
||||
delete accountData.sessionTokenContext;
|
||||
|
||||
// We need to confirm a relink - see shouldAllowRelink for more
|
||||
let newAccountEmail = accountData.email;
|
||||
|
@ -116,8 +116,12 @@ let TrackingProtection = {
|
||||
// Add the current host in the 'trackingprotection' consumer of
|
||||
// the permission manager using a normalized URI. This effectively
|
||||
// places this host on the tracking protection allowlist.
|
||||
Services.perms.add(normalizedUrl,
|
||||
"trackingprotection", Services.perms.ALLOW_ACTION);
|
||||
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
|
||||
PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl);
|
||||
} else {
|
||||
Services.perms.add(normalizedUrl,
|
||||
"trackingprotection", Services.perms.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
// Telemetry for disable protection.
|
||||
this.eventsHistogram.add(1);
|
||||
@ -133,8 +137,11 @@ let TrackingProtection = {
|
||||
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
|
||||
null, null);
|
||||
|
||||
Services.perms.remove(normalizedUrl,
|
||||
"trackingprotection");
|
||||
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
|
||||
PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl);
|
||||
} else {
|
||||
Services.perms.remove(normalizedUrl, "trackingprotection");
|
||||
}
|
||||
|
||||
// Telemetry for enable protection.
|
||||
this.eventsHistogram.add(2);
|
||||
|
@ -431,6 +431,10 @@ tags = trackingprotection
|
||||
support-files =
|
||||
trackingPage.html
|
||||
benignPage.html
|
||||
[browser_trackingUI_5.js]
|
||||
tags = trackingprotection
|
||||
support-files =
|
||||
trackingPage.html
|
||||
[browser_typeAheadFind.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_unknownContentType_title.js]
|
||||
|
122
browser/base/content/test/general/browser_trackingUI_5.js
Normal file
122
browser/base/content/test/general/browser_trackingUI_5.js
Normal file
@ -0,0 +1,122 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that sites added to the Tracking Protection whitelist in private
|
||||
// browsing mode don't persist once the private browsing window closes.
|
||||
|
||||
const PB_PREF = "privacy.trackingprotection.pbmode.enabled";
|
||||
const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
|
||||
let TrackingProtection = null;
|
||||
let browser = null;
|
||||
let {UrlClassifierTestUtils} = Cu.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
TrackingProtection = browser = null;
|
||||
UrlClassifierTestUtils.cleanupTestTrackers();
|
||||
});
|
||||
|
||||
function hidden(sel) {
|
||||
let win = browser.ownerGlobal;
|
||||
let el = win.document.querySelector(sel);
|
||||
let display = win.getComputedStyle(el).getPropertyValue("display", null);
|
||||
return display === "none";
|
||||
}
|
||||
|
||||
function clickButton(sel) {
|
||||
let win = browser.ownerGlobal;
|
||||
let el = win.document.querySelector(sel);
|
||||
el.doCommand();
|
||||
}
|
||||
|
||||
function testTrackingPage(window) {
|
||||
info("Tracking content must be blocked");
|
||||
ok(!TrackingProtection.container.hidden, "The container is visible");
|
||||
is(TrackingProtection.content.getAttribute("state"), "blocked-tracking-content",
|
||||
'content: state="blocked-tracking-content"');
|
||||
is(TrackingProtection.icon.getAttribute("state"), "blocked-tracking-content",
|
||||
'icon: state="blocked-tracking-content"');
|
||||
|
||||
ok(!hidden("#tracking-protection-icon"), "icon is visible");
|
||||
ok(hidden("#tracking-action-block"), "blockButton is hidden");
|
||||
|
||||
ok(hidden("#tracking-action-unblock"), "unblockButton is hidden");
|
||||
ok(!hidden("#tracking-action-unblock-private"), "unblockButtonPrivate is visible");
|
||||
|
||||
// Make sure that the blocked tracking elements message appears
|
||||
ok(hidden("#tracking-not-detected"), "labelNoTracking is hidden");
|
||||
ok(hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
|
||||
ok(!hidden("#tracking-blocked"), "labelTrackingBlocked is visible");
|
||||
}
|
||||
|
||||
function testTrackingPageUnblocked() {
|
||||
info("Tracking content must be white-listed and not blocked");
|
||||
ok(!TrackingProtection.container.hidden, "The container is visible");
|
||||
is(TrackingProtection.content.getAttribute("state"), "loaded-tracking-content",
|
||||
'content: state="loaded-tracking-content"');
|
||||
is(TrackingProtection.icon.getAttribute("state"), "loaded-tracking-content",
|
||||
'icon: state="loaded-tracking-content"');
|
||||
|
||||
ok(!hidden("#tracking-protection-icon"), "icon is visible");
|
||||
ok(!hidden("#tracking-action-block"), "blockButton is visible");
|
||||
ok(hidden("#tracking-action-unblock"), "unblockButton is hidden");
|
||||
|
||||
// Make sure that the blocked tracking elements message appears
|
||||
ok(hidden("#tracking-not-detected"), "labelNoTracking is hidden");
|
||||
ok(!hidden("#tracking-loaded"), "labelTrackingLoaded is visible");
|
||||
ok(hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
|
||||
}
|
||||
|
||||
add_task(function* testExceptionAddition() {
|
||||
yield UrlClassifierTestUtils.addTestTrackers();
|
||||
let privateWin = yield promiseOpenAndLoadWindow({private: true}, true);
|
||||
browser = privateWin.gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
|
||||
TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
yield pushPrefs([PB_PREF, true]);
|
||||
|
||||
ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
|
||||
|
||||
info("Load a test page containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
|
||||
testTrackingPage(tab.ownerDocument.defaultView);
|
||||
|
||||
info("Disable TP for the page (which reloads the page)");
|
||||
let tabReloadPromise = promiseTabLoadEvent(tab);
|
||||
clickButton("#tracking-action-unblock");
|
||||
yield tabReloadPromise;
|
||||
testTrackingPageUnblocked();
|
||||
|
||||
info("Test that the exception is remembered across tabs in the same private window");
|
||||
tab = browser.selectedTab = browser.addTab();
|
||||
|
||||
info("Load a test page containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
testTrackingPageUnblocked();
|
||||
|
||||
yield promiseWindowClosed(privateWin);
|
||||
});
|
||||
|
||||
add_task(function* testExceptionPersistence() {
|
||||
info("Open another private browsing window");
|
||||
let privateWin = yield promiseOpenAndLoadWindow({private: true}, true);
|
||||
browser = privateWin.gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
|
||||
TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
ok(TrackingProtection.enabled, "TP is still enabled");
|
||||
|
||||
info("Load a test page containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
|
||||
testTrackingPage(tab.ownerDocument.defaultView);
|
||||
|
||||
info("Disable TP for the page (which reloads the page)");
|
||||
let tabReloadPromise = promiseTabLoadEvent(tab);
|
||||
clickButton("#tracking-action-unblock");
|
||||
yield tabReloadPromise;
|
||||
testTrackingPageUnblocked();
|
||||
|
||||
privateWin.close();
|
||||
});
|
@ -1,7 +1,5 @@
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
@ -35,18 +33,14 @@ function promiseInitContentBlocklistSvc(aBrowser)
|
||||
* @returns a Promise that resolves to true after the time has elapsed
|
||||
*/
|
||||
function waitForMs(aMs) {
|
||||
let deferred = Promise.defer();
|
||||
let startTime = Date.now();
|
||||
setTimeout(done, aMs);
|
||||
function done() {
|
||||
deferred.resolve(true);
|
||||
}
|
||||
return deferred.promise;
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(done, aMs);
|
||||
function done() {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// DOM Promise fails for unknown reasons here, so we're using
|
||||
// resource://gre/modules/Promise.jsm.
|
||||
function waitForEvent(subject, eventName, checkFn, useCapture, useUntrusted) {
|
||||
return new Promise((resolve, reject) => {
|
||||
subject.addEventListener(eventName, function listener(event) {
|
||||
@ -84,33 +78,33 @@ function waitForEvent(subject, eventName, checkFn, useCapture, useUntrusted) {
|
||||
* @rejects if a valid load event is not received within a meaningful interval
|
||||
*/
|
||||
function promiseTabLoadEvent(tab, url, eventType="load") {
|
||||
let deferred = Promise.defer();
|
||||
info("Wait tab event: " + eventType);
|
||||
return new Promise((resolve, reject) => {
|
||||
info("Wait tab event: " + eventType);
|
||||
|
||||
function handle(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank" ||
|
||||
(url && event.target.location.href != url)) {
|
||||
info("Skipping spurious '" + eventType + "'' event" +
|
||||
" for " + event.target.location.href);
|
||||
return;
|
||||
function handle(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank" ||
|
||||
(url && event.target.location.href != url)) {
|
||||
info("Skipping spurious '" + eventType + "'' event" +
|
||||
" for " + event.target.location.href);
|
||||
return;
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
info("Tab event received: " + eventType);
|
||||
resolve(event);
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
info("Tab event received: " + eventType);
|
||||
deferred.resolve(event);
|
||||
}
|
||||
|
||||
let timeout = setTimeout(() => {
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
deferred.reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
|
||||
}, 30000);
|
||||
let timeout = setTimeout(() => {
|
||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||
reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
|
||||
}, 30000);
|
||||
|
||||
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
|
||||
if (url) {
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
}
|
||||
return deferred.promise;
|
||||
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
|
||||
if (url) {
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function waitForCondition(condition, nextTest, errorMsg, aTries, aWait) {
|
||||
@ -139,11 +133,11 @@ function waitForCondition(condition, nextTest, errorMsg, aTries, aWait) {
|
||||
|
||||
// Waits for a conditional function defined by the caller to return true.
|
||||
function promiseForCondition(aConditionFn, aMessage, aTries, aWait) {
|
||||
let deferred = Promise.defer();
|
||||
waitForCondition(aConditionFn, deferred.resolve,
|
||||
(aMessage || "Condition didn't pass."),
|
||||
aTries, aWait);
|
||||
return deferred.promise;
|
||||
return new Promise((resolve) => {
|
||||
waitForCondition(aConditionFn, resolve,
|
||||
(aMessage || "Condition didn't pass."),
|
||||
aTries, aWait);
|
||||
});
|
||||
}
|
||||
|
||||
// Returns the chrome side nsIPluginTag for this plugin
|
||||
@ -298,17 +292,15 @@ function resetBlocklist() {
|
||||
// Insure there's a popup notification present. This test does not indicate
|
||||
// open state. aBrowser can be undefined.
|
||||
function promisePopupNotification(aName, aBrowser) {
|
||||
let deferred = Promise.defer();
|
||||
return new Promise((resolve) => {
|
||||
waitForCondition(() => PopupNotifications.getNotification(aName, aBrowser),
|
||||
() => {
|
||||
ok(!!PopupNotifications.getNotification(aName, aBrowser),
|
||||
aName + " notification appeared");
|
||||
|
||||
waitForCondition(() => PopupNotifications.getNotification(aName, aBrowser),
|
||||
() => {
|
||||
ok(!!PopupNotifications.getNotification(aName, aBrowser),
|
||||
aName + " notification appeared");
|
||||
|
||||
deferred.resolve();
|
||||
}, "timeout waiting for popup notification " + aName);
|
||||
|
||||
return deferred.promise;
|
||||
resolve();
|
||||
}, "timeout waiting for popup notification " + aName);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -361,9 +353,9 @@ function waitForNotificationBar(notificationID, browser, callback) {
|
||||
}
|
||||
|
||||
function promiseForNotificationBar(notificationID, browser) {
|
||||
let deferred = Promise.defer();
|
||||
waitForNotificationBar(notificationID, browser, deferred.resolve);
|
||||
return deferred.promise;
|
||||
return new Promise((resolve) => {
|
||||
waitForNotificationBar(notificationID, browser, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -386,9 +378,9 @@ function waitForNotificationShown(notification, callback) {
|
||||
}
|
||||
|
||||
function promiseForNotificationShown(notification) {
|
||||
let deferred = Promise.defer();
|
||||
waitForNotificationShown(notification, deferred.resolve);
|
||||
return deferred.promise;
|
||||
return new Promise((resolve) => {
|
||||
waitForNotificationShown(notification, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -957,9 +957,8 @@ const CustomizableWidgets = [
|
||||
type: "custom",
|
||||
label: "loop-call-button3.label",
|
||||
tooltiptext: "loop-call-button3.tooltiptext",
|
||||
privateBrowsingTooltiptext: "loop-call-button3-pb.tooltiptext",
|
||||
defaultArea: CustomizableUI.AREA_NAVBAR,
|
||||
// Not in private browsing, see bug 1108187.
|
||||
showInPrivateBrowsing: false,
|
||||
introducedInVersion: 4,
|
||||
onBuild: function(aDocument) {
|
||||
// If we're not supposed to see the button, return zip.
|
||||
@ -967,13 +966,21 @@ const CustomizableWidgets = [
|
||||
return null;
|
||||
}
|
||||
|
||||
let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(aDocument.defaultView);
|
||||
|
||||
let node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
|
||||
node.setAttribute("id", this.id);
|
||||
node.classList.add("toolbarbutton-1");
|
||||
node.classList.add("chromeclass-toolbar-additional");
|
||||
node.classList.add("badged-button");
|
||||
node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
|
||||
node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
|
||||
if (isWindowPrivate)
|
||||
node.setAttribute("disabled", "true");
|
||||
let tooltiptext = isWindowPrivate ?
|
||||
CustomizableUI.getLocalizedProperty(this, "privateBrowsingTooltiptext",
|
||||
[CustomizableUI.getLocalizedProperty(this, "label")]) :
|
||||
CustomizableUI.getLocalizedProperty(this, "tooltiptext");
|
||||
node.setAttribute("tooltiptext", tooltiptext);
|
||||
node.setAttribute("removable", "true");
|
||||
node.addEventListener("command", function(event) {
|
||||
aDocument.defaultView.LoopUI.togglePanel(event);
|
||||
|
@ -119,7 +119,7 @@ function configureFxAccountIdentity() {
|
||||
let storageManager = new MockFxaStorageManager();
|
||||
// and init storage with our user.
|
||||
storageManager.initialize(user);
|
||||
return new AccountState(this, storageManager);
|
||||
return new AccountState(storageManager);
|
||||
},
|
||||
getCertificate(data, keyPair, mustBeValidUntil) {
|
||||
this.cert = {
|
||||
|
@ -570,13 +570,15 @@ loop.conversationViews = (function(mozL10n) {
|
||||
|
||||
var OngoingConversationView = React.createClass({displayName: "OngoingConversationView",
|
||||
mixins: [
|
||||
loop.store.StoreMixin("conversationStore"),
|
||||
sharedMixins.MediaSetupMixin
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
// local
|
||||
audio: React.PropTypes.object,
|
||||
// We pass conversationStore here rather than use the mixin, to allow
|
||||
// easy configurability for the ui-showcase.
|
||||
conversationStore: React.PropTypes.instanceOf(loop.store.ConversationStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
// The poster URLs are for UI-showcase testing and development.
|
||||
localPosterUrl: React.PropTypes.string,
|
||||
@ -597,7 +599,17 @@ loop.conversationViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.getStoreState();
|
||||
return this.props.conversationStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.props.conversationStore.on("change", function() {
|
||||
this.setState(this.props.conversationStore.getStoreState());
|
||||
}, this);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.props.conversationStore.off("change", null, this);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
@ -633,6 +645,30 @@ loop.conversationViews = (function(mozL10n) {
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Should we render a visual cue to the user (e.g. a spinner) that a local
|
||||
* stream is on its way from the camera?
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_isLocalLoading: function () {
|
||||
return !this.state.localSrcVideoObject && !this.props.localPosterUrl;
|
||||
},
|
||||
|
||||
/**
|
||||
* Should we render a visual cue to the user (e.g. a spinner) that a remote
|
||||
* stream is on its way from the other user?
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_isRemoteLoading: function() {
|
||||
return !!(!this.state.remoteSrcVideoObject &&
|
||||
!this.props.remotePosterUrl &&
|
||||
!this.state.mediaConnected);
|
||||
},
|
||||
|
||||
shouldRenderRemoteVideo: function() {
|
||||
if (this.props.mediaConnected) {
|
||||
// If remote video is not enabled, we're muted, so we'll show an avatar
|
||||
@ -646,41 +682,32 @@ loop.conversationViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var localStreamClasses = React.addons.classSet({
|
||||
local: true,
|
||||
"local-stream": true,
|
||||
"local-stream-audio": !this.props.video.enabled
|
||||
});
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "video-layout-wrapper"},
|
||||
React.createElement("div", {className: "conversation"},
|
||||
React.createElement("div", {className: "media nested"},
|
||||
React.createElement("div", {className: "video_wrapper remote_wrapper"},
|
||||
React.createElement("div", {className: "video_inner remote focus-stream"},
|
||||
React.createElement(sharedViews.MediaView, {displayAvatar: !this.shouldRenderRemoteVideo(),
|
||||
isLoading: false,
|
||||
mediaType: "remote",
|
||||
posterUrl: this.props.remotePosterUrl,
|
||||
srcVideoObject: this.state.remoteSrcVideoObject})
|
||||
)
|
||||
),
|
||||
React.createElement("div", {className: localStreamClasses},
|
||||
React.createElement(sharedViews.MediaView, {displayAvatar: !this.props.video.enabled,
|
||||
isLoading: false,
|
||||
mediaType: "local",
|
||||
posterUrl: this.props.localPosterUrl,
|
||||
srcVideoObject: this.state.localSrcVideoObject})
|
||||
)
|
||||
),
|
||||
React.createElement(loop.shared.views.ConversationToolbar, {
|
||||
audio: this.props.audio,
|
||||
dispatcher: this.props.dispatcher,
|
||||
edit: { visible: false, enabled: false},
|
||||
hangup: this.hangup,
|
||||
publishStream: this.publishStream,
|
||||
video: this.props.video})
|
||||
)
|
||||
React.createElement("div", {className: "desktop-call-wrapper"},
|
||||
React.createElement(sharedViews.MediaLayoutView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
displayScreenShare: false,
|
||||
isLocalLoading: this._isLocalLoading(),
|
||||
isRemoteLoading: this._isRemoteLoading(),
|
||||
isScreenShareLoading: false,
|
||||
localPosterUrl: this.props.localPosterUrl,
|
||||
localSrcVideoObject: this.state.localSrcVideoObject,
|
||||
localVideoMuted: !this.props.video.enabled,
|
||||
matchMedia: this.state.matchMedia || window.matchMedia.bind(window),
|
||||
remotePosterUrl: this.props.remotePosterUrl,
|
||||
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
||||
renderRemoteVideo: this.shouldRenderRemoteVideo(),
|
||||
screenSharePosterUrl: null,
|
||||
screenShareVideoObject: this.state.screenShareVideoObject,
|
||||
showContextRoomName: false,
|
||||
useDesktopPaths: true}),
|
||||
React.createElement(loop.shared.views.ConversationToolbar, {
|
||||
audio: this.props.audio,
|
||||
dispatcher: this.props.dispatcher,
|
||||
edit: { visible: false, enabled: false},
|
||||
hangup: this.hangup,
|
||||
publishStream: this.publishStream,
|
||||
video: this.props.video})
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -778,6 +805,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
case CALL_STATES.ONGOING: {
|
||||
return (React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: !this.state.audioMuted},
|
||||
conversationStore: this.getStore(),
|
||||
dispatcher: this.props.dispatcher,
|
||||
mediaConnected: this.state.mediaConnected,
|
||||
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
||||
|
@ -570,13 +570,15 @@ loop.conversationViews = (function(mozL10n) {
|
||||
|
||||
var OngoingConversationView = React.createClass({
|
||||
mixins: [
|
||||
loop.store.StoreMixin("conversationStore"),
|
||||
sharedMixins.MediaSetupMixin
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
// local
|
||||
audio: React.PropTypes.object,
|
||||
// We pass conversationStore here rather than use the mixin, to allow
|
||||
// easy configurability for the ui-showcase.
|
||||
conversationStore: React.PropTypes.instanceOf(loop.store.ConversationStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
// The poster URLs are for UI-showcase testing and development.
|
||||
localPosterUrl: React.PropTypes.string,
|
||||
@ -597,7 +599,17 @@ loop.conversationViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.getStoreState();
|
||||
return this.props.conversationStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.props.conversationStore.on("change", function() {
|
||||
this.setState(this.props.conversationStore.getStoreState());
|
||||
}, this);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.props.conversationStore.off("change", null, this);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
@ -633,6 +645,30 @@ loop.conversationViews = (function(mozL10n) {
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Should we render a visual cue to the user (e.g. a spinner) that a local
|
||||
* stream is on its way from the camera?
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_isLocalLoading: function () {
|
||||
return !this.state.localSrcVideoObject && !this.props.localPosterUrl;
|
||||
},
|
||||
|
||||
/**
|
||||
* Should we render a visual cue to the user (e.g. a spinner) that a remote
|
||||
* stream is on its way from the other user?
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_isRemoteLoading: function() {
|
||||
return !!(!this.state.remoteSrcVideoObject &&
|
||||
!this.props.remotePosterUrl &&
|
||||
!this.state.mediaConnected);
|
||||
},
|
||||
|
||||
shouldRenderRemoteVideo: function() {
|
||||
if (this.props.mediaConnected) {
|
||||
// If remote video is not enabled, we're muted, so we'll show an avatar
|
||||
@ -646,41 +682,32 @@ loop.conversationViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var localStreamClasses = React.addons.classSet({
|
||||
local: true,
|
||||
"local-stream": true,
|
||||
"local-stream-audio": !this.props.video.enabled
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="video-layout-wrapper">
|
||||
<div className="conversation">
|
||||
<div className="media nested">
|
||||
<div className="video_wrapper remote_wrapper">
|
||||
<div className="video_inner remote focus-stream">
|
||||
<sharedViews.MediaView displayAvatar={!this.shouldRenderRemoteVideo()}
|
||||
isLoading={false}
|
||||
mediaType="remote"
|
||||
posterUrl={this.props.remotePosterUrl}
|
||||
srcVideoObject={this.state.remoteSrcVideoObject} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={localStreamClasses}>
|
||||
<sharedViews.MediaView displayAvatar={!this.props.video.enabled}
|
||||
isLoading={false}
|
||||
mediaType="local"
|
||||
posterUrl={this.props.localPosterUrl}
|
||||
srcVideoObject={this.state.localSrcVideoObject} />
|
||||
</div>
|
||||
</div>
|
||||
<loop.shared.views.ConversationToolbar
|
||||
audio={this.props.audio}
|
||||
dispatcher={this.props.dispatcher}
|
||||
edit={{ visible: false, enabled: false }}
|
||||
hangup={this.hangup}
|
||||
publishStream={this.publishStream}
|
||||
video={this.props.video} />
|
||||
</div>
|
||||
<div className="desktop-call-wrapper">
|
||||
<sharedViews.MediaLayoutView
|
||||
dispatcher={this.props.dispatcher}
|
||||
displayScreenShare={false}
|
||||
isLocalLoading={this._isLocalLoading()}
|
||||
isRemoteLoading={this._isRemoteLoading()}
|
||||
isScreenShareLoading={false}
|
||||
localPosterUrl={this.props.localPosterUrl}
|
||||
localSrcVideoObject={this.state.localSrcVideoObject}
|
||||
localVideoMuted={!this.props.video.enabled}
|
||||
matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
|
||||
remotePosterUrl={this.props.remotePosterUrl}
|
||||
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
||||
renderRemoteVideo={this.shouldRenderRemoteVideo()}
|
||||
screenSharePosterUrl={null}
|
||||
screenShareVideoObject={this.state.screenShareVideoObject}
|
||||
showContextRoomName={false}
|
||||
useDesktopPaths={true} />
|
||||
<loop.shared.views.ConversationToolbar
|
||||
audio={this.props.audio}
|
||||
dispatcher={this.props.dispatcher}
|
||||
edit={{ visible: false, enabled: false }}
|
||||
hangup={this.hangup}
|
||||
publishStream={this.publishStream}
|
||||
video={this.props.video} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -778,6 +805,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
case CALL_STATES.ONGOING: {
|
||||
return (<OngoingConversationView
|
||||
audio={{enabled: !this.state.audioMuted}}
|
||||
conversationStore={this.getStore()}
|
||||
dispatcher={this.props.dispatcher}
|
||||
mediaConnected={this.state.mediaConnected}
|
||||
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
||||
|
@ -665,7 +665,7 @@ loop.roomViews = (function(mozL10n) {
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_shouldRenderLocalLoading: function () {
|
||||
_isLocalLoading: function () {
|
||||
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
|
||||
!this.state.localSrcVideoObject;
|
||||
},
|
||||
@ -677,7 +677,7 @@ loop.roomViews = (function(mozL10n) {
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_shouldRenderRemoteLoading: function() {
|
||||
_isRemoteLoading: function() {
|
||||
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
|
||||
!this.state.remoteSrcVideoObject &&
|
||||
!this.state.mediaConnected);
|
||||
@ -741,63 +741,54 @@ loop.roomViews = (function(mozL10n) {
|
||||
return null;
|
||||
}
|
||||
default: {
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "room-conversation-wrapper"},
|
||||
React.createElement("div", {className: "video-layout-wrapper"},
|
||||
React.createElement("div", {className: "conversation room-conversation"},
|
||||
React.createElement("div", {className: "media nested"},
|
||||
React.createElement(DesktopRoomInvitationView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
onAddContextClick: this.handleAddContextClick,
|
||||
onEditContextClose: this.handleEditContextClose,
|
||||
roomData: roomData,
|
||||
savingContext: this.state.savingContext,
|
||||
show: shouldRenderInvitationOverlay,
|
||||
showEditContext: shouldRenderInvitationOverlay && shouldRenderEditContextView,
|
||||
socialShareProviders: this.state.socialShareProviders}),
|
||||
React.createElement("div", {className: "video_wrapper remote_wrapper"},
|
||||
React.createElement("div", {className: "video_inner remote focus-stream"},
|
||||
React.createElement(sharedViews.MediaView, {displayAvatar: !this.shouldRenderRemoteVideo(),
|
||||
isLoading: this._shouldRenderRemoteLoading(),
|
||||
mediaType: "remote",
|
||||
posterUrl: this.props.remotePosterUrl,
|
||||
srcVideoObject: this.state.remoteSrcVideoObject})
|
||||
)
|
||||
),
|
||||
React.createElement("div", {className: localStreamClasses},
|
||||
React.createElement(sharedViews.MediaView, {displayAvatar: this.state.videoMuted,
|
||||
isLoading: this._shouldRenderLocalLoading(),
|
||||
mediaType: "local",
|
||||
posterUrl: this.props.localPosterUrl,
|
||||
srcVideoObject: this.state.localSrcVideoObject})
|
||||
),
|
||||
React.createElement(DesktopRoomEditContextView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
onClose: this.handleEditContextClose,
|
||||
roomData: roomData,
|
||||
savingContext: this.state.savingContext,
|
||||
show: !shouldRenderInvitationOverlay && shouldRenderEditContextView})
|
||||
),
|
||||
React.createElement(sharedViews.ConversationToolbar, {
|
||||
audio: {enabled: !this.state.audioMuted, visible: true},
|
||||
dispatcher: this.props.dispatcher,
|
||||
edit: { visible: this.state.contextEnabled, enabled: !this.state.showEditContext},
|
||||
hangup: this.leaveRoom,
|
||||
onEditClick: this.handleEditContextClick,
|
||||
publishStream: this.publishStream,
|
||||
screenShare: screenShareData,
|
||||
video: {enabled: !this.state.videoMuted, visible: true}})
|
||||
)
|
||||
),
|
||||
React.createElement(sharedViews.chat.TextChatView, {
|
||||
React.createElement("div", {className: "room-conversation-wrapper desktop-room-wrapper"},
|
||||
React.createElement(sharedViews.MediaLayoutView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
showRoomName: false,
|
||||
useDesktopPaths: true})
|
||||
displayScreenShare: false,
|
||||
isLocalLoading: this._isLocalLoading(),
|
||||
isRemoteLoading: this._isRemoteLoading(),
|
||||
isScreenShareLoading: false,
|
||||
localPosterUrl: this.props.localPosterUrl,
|
||||
localSrcVideoObject: this.state.localSrcVideoObject,
|
||||
localVideoMuted: this.state.videoMuted,
|
||||
matchMedia: this.state.matchMedia || window.matchMedia.bind(window),
|
||||
remotePosterUrl: this.props.remotePosterUrl,
|
||||
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
||||
renderRemoteVideo: this.shouldRenderRemoteVideo(),
|
||||
screenSharePosterUrl: null,
|
||||
screenShareVideoObject: this.state.screenShareVideoObject,
|
||||
showContextRoomName: false,
|
||||
useDesktopPaths: true},
|
||||
React.createElement(DesktopRoomInvitationView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
onAddContextClick: this.handleAddContextClick,
|
||||
onEditContextClose: this.handleEditContextClose,
|
||||
roomData: roomData,
|
||||
savingContext: this.state.savingContext,
|
||||
show: shouldRenderInvitationOverlay,
|
||||
showEditContext: shouldRenderInvitationOverlay && shouldRenderEditContextView,
|
||||
socialShareProviders: this.state.socialShareProviders}),
|
||||
React.createElement(DesktopRoomEditContextView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
onClose: this.handleEditContextClose,
|
||||
roomData: roomData,
|
||||
savingContext: this.state.savingContext,
|
||||
show: !shouldRenderInvitationOverlay && shouldRenderEditContextView})
|
||||
),
|
||||
React.createElement(sharedViews.ConversationToolbar, {
|
||||
audio: {enabled: !this.state.audioMuted, visible: true},
|
||||
dispatcher: this.props.dispatcher,
|
||||
edit: { visible: this.state.contextEnabled, enabled: !this.state.showEditContext},
|
||||
hangup: this.leaveRoom,
|
||||
onEditClick: this.handleEditContextClick,
|
||||
publishStream: this.publishStream,
|
||||
screenShare: screenShareData,
|
||||
video: {enabled: !this.state.videoMuted, visible: true}})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -665,7 +665,7 @@ loop.roomViews = (function(mozL10n) {
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_shouldRenderLocalLoading: function () {
|
||||
_isLocalLoading: function () {
|
||||
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
|
||||
!this.state.localSrcVideoObject;
|
||||
},
|
||||
@ -677,7 +677,7 @@ loop.roomViews = (function(mozL10n) {
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_shouldRenderRemoteLoading: function() {
|
||||
_isRemoteLoading: function() {
|
||||
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
|
||||
!this.state.remoteSrcVideoObject &&
|
||||
!this.state.mediaConnected);
|
||||
@ -741,63 +741,54 @@ loop.roomViews = (function(mozL10n) {
|
||||
return null;
|
||||
}
|
||||
default: {
|
||||
|
||||
return (
|
||||
<div className="room-conversation-wrapper">
|
||||
<div className="video-layout-wrapper">
|
||||
<div className="conversation room-conversation">
|
||||
<div className="media nested">
|
||||
<DesktopRoomInvitationView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
onAddContextClick={this.handleAddContextClick}
|
||||
onEditContextClose={this.handleEditContextClose}
|
||||
roomData={roomData}
|
||||
savingContext={this.state.savingContext}
|
||||
show={shouldRenderInvitationOverlay}
|
||||
showEditContext={shouldRenderInvitationOverlay && shouldRenderEditContextView}
|
||||
socialShareProviders={this.state.socialShareProviders} />
|
||||
<div className="video_wrapper remote_wrapper">
|
||||
<div className="video_inner remote focus-stream">
|
||||
<sharedViews.MediaView displayAvatar={!this.shouldRenderRemoteVideo()}
|
||||
isLoading={this._shouldRenderRemoteLoading()}
|
||||
mediaType="remote"
|
||||
posterUrl={this.props.remotePosterUrl}
|
||||
srcVideoObject={this.state.remoteSrcVideoObject} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={localStreamClasses}>
|
||||
<sharedViews.MediaView displayAvatar={this.state.videoMuted}
|
||||
isLoading={this._shouldRenderLocalLoading()}
|
||||
mediaType="local"
|
||||
posterUrl={this.props.localPosterUrl}
|
||||
srcVideoObject={this.state.localSrcVideoObject} />
|
||||
</div>
|
||||
<DesktopRoomEditContextView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
onClose={this.handleEditContextClose}
|
||||
roomData={roomData}
|
||||
savingContext={this.state.savingContext}
|
||||
show={!shouldRenderInvitationOverlay && shouldRenderEditContextView} />
|
||||
</div>
|
||||
<sharedViews.ConversationToolbar
|
||||
audio={{enabled: !this.state.audioMuted, visible: true}}
|
||||
dispatcher={this.props.dispatcher}
|
||||
edit={{ visible: this.state.contextEnabled, enabled: !this.state.showEditContext }}
|
||||
hangup={this.leaveRoom}
|
||||
onEditClick={this.handleEditContextClick}
|
||||
publishStream={this.publishStream}
|
||||
screenShare={screenShareData}
|
||||
video={{enabled: !this.state.videoMuted, visible: true}} />
|
||||
</div>
|
||||
</div>
|
||||
<sharedViews.chat.TextChatView
|
||||
<div className="room-conversation-wrapper desktop-room-wrapper">
|
||||
<sharedViews.MediaLayoutView
|
||||
dispatcher={this.props.dispatcher}
|
||||
showRoomName={false}
|
||||
useDesktopPaths={true} />
|
||||
displayScreenShare={false}
|
||||
isLocalLoading={this._isLocalLoading()}
|
||||
isRemoteLoading={this._isRemoteLoading()}
|
||||
isScreenShareLoading={false}
|
||||
localPosterUrl={this.props.localPosterUrl}
|
||||
localSrcVideoObject={this.state.localSrcVideoObject}
|
||||
localVideoMuted={this.state.videoMuted}
|
||||
matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
|
||||
remotePosterUrl={this.props.remotePosterUrl}
|
||||
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
||||
renderRemoteVideo={this.shouldRenderRemoteVideo()}
|
||||
screenSharePosterUrl={null}
|
||||
screenShareVideoObject={this.state.screenShareVideoObject}
|
||||
showContextRoomName={false}
|
||||
useDesktopPaths={true}>
|
||||
<DesktopRoomInvitationView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
onAddContextClick={this.handleAddContextClick}
|
||||
onEditContextClose={this.handleEditContextClose}
|
||||
roomData={roomData}
|
||||
savingContext={this.state.savingContext}
|
||||
show={shouldRenderInvitationOverlay}
|
||||
showEditContext={shouldRenderInvitationOverlay && shouldRenderEditContextView}
|
||||
socialShareProviders={this.state.socialShareProviders} />
|
||||
<DesktopRoomEditContextView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
onClose={this.handleEditContextClose}
|
||||
roomData={roomData}
|
||||
savingContext={this.state.savingContext}
|
||||
show={!shouldRenderInvitationOverlay && shouldRenderEditContextView} />
|
||||
</sharedViews.MediaLayoutView>
|
||||
<sharedViews.ConversationToolbar
|
||||
audio={{enabled: !this.state.audioMuted, visible: true}}
|
||||
dispatcher={this.props.dispatcher}
|
||||
edit={{ visible: this.state.contextEnabled, enabled: !this.state.showEditContext }}
|
||||
hangup={this.leaveRoom}
|
||||
onEditClick={this.handleEditContextClick}
|
||||
publishStream={this.publishStream}
|
||||
screenShare={screenShareData}
|
||||
video={{enabled: !this.state.videoMuted, visible: true}} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -504,28 +504,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.fx-embedded .local-stream {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
bottom: 5px;
|
||||
/* next two lines are workaround for lack of object-fit; see bug 1020445 */
|
||||
max-width: 140px;
|
||||
width: 30%;
|
||||
height: 28%;
|
||||
max-height: 105px;
|
||||
}
|
||||
|
||||
.fx-embedded .local-stream.room-preview {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.conversation .media.nested .focus-stream {
|
||||
display: inline-block;
|
||||
position: absolute; /* workaround for lack of object-fit; see bug 1020445 */
|
||||
@ -592,15 +570,11 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.remote .avatar {
|
||||
.remote > .avatar {
|
||||
/* make visually distinct from local avatar */
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.fx-embedded .media.nested {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.fx-embedded-call-identifier {
|
||||
display: inline;
|
||||
width: 100%;
|
||||
@ -675,7 +649,9 @@
|
||||
* */
|
||||
html, .fx-embedded, #main,
|
||||
.video-layout-wrapper,
|
||||
.conversation {
|
||||
.conversation,
|
||||
.desktop-call-wrapper,
|
||||
.desktop-room-wrapper {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@ -935,7 +911,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
||||
border-top: 2px solid #444;
|
||||
border-bottom: 2px solid #444;
|
||||
padding: .5rem;
|
||||
max-height: 400px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
@ -951,7 +926,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
/* Make the context view float atop the video elements. */
|
||||
z-index: 2;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.room-invitation-overlay .room-context {
|
||||
@ -1087,12 +1062,12 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
.standalone-room-wrapper > .media-layout {
|
||||
/* 50px is the header, 64px for toolbar, 3em is the footer. */
|
||||
height: calc(100% - 50px - 64px - 3em);
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.media-layout > .media-wrapper {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
margin: 0 10px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@ -1139,6 +1114,14 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
height: calc(100% - 300px);
|
||||
}
|
||||
|
||||
.desktop-call-wrapper > .media-layout > .media-wrapper > .text-chat-view,
|
||||
.desktop-room-wrapper > .media-layout > .media-wrapper > .text-chat-view {
|
||||
/* Account for height of .conversation-toolbar on desktop */
|
||||
/* When we change the toolbar in bug 1184559 we can remove this. */
|
||||
margin-top: 26px;
|
||||
height: calc(100% - 150px - 26px);
|
||||
}
|
||||
|
||||
/* Temporarily slaved from .media-wrapper until we use it in more places
|
||||
to avoid affecting the conversation window on desktop. */
|
||||
.media-wrapper > .text-chat-view > .text-chat-entries {
|
||||
@ -1204,7 +1187,7 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
|
||||
/* Temporarily slaved from .media-wrapper until we use it in more places
|
||||
to avoid affecting the conversation window on desktop. */
|
||||
.media-wrapper > .text-chat-view > .text-chat-entries {
|
||||
.text-chat-view > .text-chat-entries {
|
||||
/* 40px is the height of .text-chat-box. */
|
||||
height: calc(100% - 40px);
|
||||
width: 100%;
|
||||
@ -1215,20 +1198,26 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.media-wrapper > .local {
|
||||
.media-wrapper > .focus-stream > .local {
|
||||
/* Position over the remote video */
|
||||
position: absolute;
|
||||
/* Make sure its on top */
|
||||
z-index: 1001;
|
||||
z-index: 2;
|
||||
margin: 3px;
|
||||
right: 0;
|
||||
/* 29px is (30% of 50px high header) + (height toolbar (38px) +
|
||||
height footer (25px) - height header (50px)) */
|
||||
bottom: calc(30% + 29px);
|
||||
bottom: 0;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.standalone-room-wrapper > .media-layout > .media-wrapper > .local {
|
||||
/* Add 10px for the margin on standalone */
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
|
||||
html[dir="rtl"] .media-wrapper > .local {
|
||||
right: auto;
|
||||
left: 0;
|
||||
@ -1247,6 +1236,15 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
height: 30%;
|
||||
}
|
||||
|
||||
.desktop-call-wrapper > .media-layout > .media-wrapper > .text-chat-view,
|
||||
.desktop-room-wrapper > .media-layout > .media-wrapper > .text-chat-view {
|
||||
/* When we change the toolbar in bug 1184559 we can remove this. */
|
||||
/* Reset back to 0 for .conversation-toolbar override on desktop */
|
||||
margin-top: 0;
|
||||
/* This is temp, to echo the .media-wrapper > .text-chat-view above */
|
||||
height: 30%;
|
||||
}
|
||||
|
||||
.media-wrapper.receiving-screen-share > .screen {
|
||||
order: 1;
|
||||
}
|
||||
@ -1288,6 +1286,47 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
}
|
||||
}
|
||||
|
||||
/* e.g. very narrow widths similar to conversation window */
|
||||
@media screen and (max-width:300px) {
|
||||
.media-layout > .media-wrapper {
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.media-wrapper > .focus-stream > .local {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
/* 30% is the height of the text chat. As we have a margin,
|
||||
we don't need to worry about any offset for a border */
|
||||
bottom: 0;
|
||||
margin: 3px;
|
||||
object-fit: contain;
|
||||
/* These make the avatar look reasonable and the local
|
||||
video not too big */
|
||||
width: 25%;
|
||||
height: 25%;
|
||||
}
|
||||
|
||||
.media-wrapper:not(.showing-remote-streams) > .focus-stream > .no-video {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-wrapper:not(.showing-remote-streams) > .focus-stream > .local {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
right: auto;
|
||||
left: auto;
|
||||
bottom: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.media-wrapper > .focus-stream {
|
||||
flex: 1 1 auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.standalone > #main > .room-conversation-wrapper > .media-layout > .conversation-toolbar {
|
||||
border: none;
|
||||
}
|
||||
@ -1415,37 +1454,12 @@ html[dir="rtl"] .standalone .room-conversation-wrapper .room-inner-info-area {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Text chat in rooms styles */
|
||||
|
||||
.fx-embedded .room-conversation-wrapper {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.fx-embedded .video-layout-wrapper {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
/* Text chat in styles */
|
||||
|
||||
.text-chat-view {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-view {
|
||||
flex: 1 0 auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-entries {
|
||||
flex: 1 1 auto;
|
||||
max-height: 120px;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.fx-embedded .text-chat-view > .text-chat-entries-empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.text-chat-box {
|
||||
flex: 0 0 auto;
|
||||
max-height: 40px;
|
||||
@ -1740,6 +1754,47 @@ html[dir="rtl"] .text-chat-entry.received .text-chat-arrow {
|
||||
}
|
||||
}
|
||||
|
||||
/* e.g. very narrow widths similar to conversation window */
|
||||
@media screen and (max-width:300px) {
|
||||
.text-chat-view {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
/* 120px max-height of .text-chat-entries plus 40px of .text-chat-box */
|
||||
max-height: 160px;
|
||||
/* 60px min-height of .text-chat-entries plus 40px of .text-chat-box */
|
||||
min-height: 100px;
|
||||
/* The !important is to override the values defined above which have more
|
||||
specificity when we fix bug 1184559, we should be able to remove it,
|
||||
but this should be tests first. */
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.text-chat-entries {
|
||||
/* The !important is to override the values defined above which have more
|
||||
specificity when we fix bug 1184559, we should be able to remove it,
|
||||
but this should be tests first. */
|
||||
flex: 1 1 auto !important;
|
||||
max-height: 120px;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.text-chat-entries-empty.text-chat-disabled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* When the text chat entries are not present, then hide the entries view
|
||||
and just show the chat box. */
|
||||
.text-chat-entries-empty {
|
||||
max-height: 40px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.text-chat-entries-empty > .text-chat-entries {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.self-view-hidden-message {
|
||||
/* Not displayed by default; display is turned on elsewhere when the
|
||||
* self-view is actually hidden.
|
||||
|
@ -580,21 +580,6 @@ loop.store.ActiveRoomStore = (function() {
|
||||
* @param {sharedActions.ConnectionFailure} actionData
|
||||
*/
|
||||
connectionFailure: function(actionData) {
|
||||
/**
|
||||
* XXX This is a workaround for desktop machines that do not have a
|
||||
* camera installed. As we don't yet have device enumeration, when
|
||||
* we do, this can be removed (bug 1138851), and the sdk should handle it.
|
||||
*/
|
||||
if (this._isDesktop &&
|
||||
actionData.reason === FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA &&
|
||||
this.getStoreState().videoMuted === false) {
|
||||
// We failed to publish with media, so due to the bug, we try again without
|
||||
// video.
|
||||
this.setStoreState({videoMuted: true});
|
||||
this._sdkDriver.retryPublishWithoutVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
var exitState = this._storeState.roomState === ROOM_STATES.FAILED ?
|
||||
this._storeState.failureExitState : this._storeState.roomState;
|
||||
|
||||
|
@ -146,21 +146,6 @@ loop.store = loop.store || {};
|
||||
* @param {sharedActions.ConnectionFailure} actionData The action data.
|
||||
*/
|
||||
connectionFailure: function(actionData) {
|
||||
/**
|
||||
* XXX This is a workaround for desktop machines that do not have a
|
||||
* camera installed. As we don't yet have device enumeration, when
|
||||
* we do, this can be removed (bug 1138851), and the sdk should handle it.
|
||||
*/
|
||||
if (this._isDesktop &&
|
||||
actionData.reason === FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA &&
|
||||
this.getStoreState().videoMuted === false) {
|
||||
// We failed to publish with media, so due to the bug, we try again without
|
||||
// video.
|
||||
this.setStoreState({videoMuted: true});
|
||||
this.sdkDriver.retryPublishWithoutVideo();
|
||||
return;
|
||||
}
|
||||
|
||||
this._endSession();
|
||||
this.setStoreState({
|
||||
callState: CALL_STATES.TERMINATED,
|
||||
|
@ -61,15 +61,26 @@ loop.OTSdkDriver = (function() {
|
||||
|
||||
/**
|
||||
* XXX This is a workaround for desktop machines that do not have a
|
||||
* camera installed. As we don't yet have device enumeration, when
|
||||
* we do, this can be removed (bug 1138851), and the sdk should handle it.
|
||||
* camera installed. The SDK doesn't currently do use the new device
|
||||
* enumeration apis, when it does (bug 1138851), we can drop this part.
|
||||
*/
|
||||
if (this._isDesktop && !window.MediaStreamTrack.getSources) {
|
||||
if (this._isDesktop) {
|
||||
// If there's no getSources function, the sdk defines its own and caches
|
||||
// the result. So here we define the "normal" one which doesn't get cached, so
|
||||
// we can change it later.
|
||||
// the result. So here we define our own one which wraps around the
|
||||
// real device enumeration api.
|
||||
window.MediaStreamTrack.getSources = function(callback) {
|
||||
callback([{kind: "audio"}, {kind: "video"}]);
|
||||
navigator.mediaDevices.enumerateDevices().then(function(devices) {
|
||||
var result = [];
|
||||
devices.forEach(function(device) {
|
||||
if (device.kind === "audioinput") {
|
||||
result.push({kind: "audio"});
|
||||
}
|
||||
if (device.kind === "videoinput") {
|
||||
result.push({kind: "video"});
|
||||
}
|
||||
});
|
||||
callback(result);
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -109,21 +120,13 @@ loop.OTSdkDriver = (function() {
|
||||
|
||||
this.sdk.on("exception", this._onOTException.bind(this));
|
||||
|
||||
// At this state we init the publisher, even though we might be waiting for
|
||||
// the initial connect of the session. This saves time when setting up
|
||||
// the media.
|
||||
this._publishLocalStreams();
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal function to publish a local stream.
|
||||
* XXX This can be simplified when bug 1138851 is actioned.
|
||||
*/
|
||||
_publishLocalStreams: function() {
|
||||
// We expect the local video to be muted automatically by the SDK. Hence
|
||||
// we don't mute it manually here.
|
||||
this._mockPublisherEl = document.createElement("div");
|
||||
|
||||
// At this state we init the publisher, even though we might be waiting for
|
||||
// the initial connect of the session. This saves time when setting up
|
||||
// the media.
|
||||
this.publisher = this.sdk.initPublisher(this._mockPublisherEl,
|
||||
_.extend(this._getDataChannelSettings, this._getCopyPublisherConfig));
|
||||
|
||||
@ -135,17 +138,6 @@ loop.OTSdkDriver = (function() {
|
||||
this._onAccessDialogOpened.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Forces the sdk into not using video, and starts publishing again.
|
||||
* XXX This is part of the work around that will be removed by bug 1138851.
|
||||
*/
|
||||
retryPublishWithoutVideo: function() {
|
||||
window.MediaStreamTrack.getSources = function(callback) {
|
||||
callback([{kind: "audio"}]);
|
||||
};
|
||||
this._publishLocalStreams();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the setMute action. Informs the published stream to mute
|
||||
* or unmute audio as appropriate.
|
||||
|
@ -150,8 +150,7 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||
var lastTimestamp = 0;
|
||||
|
||||
var entriesClasses = React.addons.classSet({
|
||||
"text-chat-entries": true,
|
||||
"text-chat-entries-empty": !this.props.messageList.length
|
||||
"text-chat-entries": true
|
||||
});
|
||||
|
||||
return (
|
||||
@ -382,7 +381,8 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||
|
||||
var textChatViewClasses = React.addons.classSet({
|
||||
"text-chat-view": true,
|
||||
"text-chat-disabled": !this.state.textChatEnabled
|
||||
"text-chat-disabled": !this.state.textChatEnabled,
|
||||
"text-chat-entries-empty": !messageList.length
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -150,8 +150,7 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||
var lastTimestamp = 0;
|
||||
|
||||
var entriesClasses = React.addons.classSet({
|
||||
"text-chat-entries": true,
|
||||
"text-chat-entries-empty": !this.props.messageList.length
|
||||
"text-chat-entries": true
|
||||
});
|
||||
|
||||
return (
|
||||
@ -382,7 +381,8 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||
|
||||
var textChatViewClasses = React.addons.classSet({
|
||||
"text-chat-view": true,
|
||||
"text-chat-disabled": !this.state.textChatEnabled
|
||||
"text-chat-disabled": !this.state.textChatEnabled,
|
||||
"text-chat-entries-empty": !messageList.length
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -946,6 +946,7 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
|
||||
var MediaLayoutView = React.createClass({displayName: "MediaLayoutView",
|
||||
propTypes: {
|
||||
children: React.PropTypes.node,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
displayScreenShare: React.PropTypes.bool.isRequired,
|
||||
isLocalLoading: React.PropTypes.bool.isRequired,
|
||||
@ -955,6 +956,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
localPosterUrl: React.PropTypes.string,
|
||||
localSrcVideoObject: React.PropTypes.object,
|
||||
localVideoMuted: React.PropTypes.bool.isRequired,
|
||||
// Passing in matchMedia, allows it to be overriden for ui-showcase's
|
||||
// benefit. We expect either the override or window.matchMedia.
|
||||
matchMedia: React.PropTypes.func.isRequired,
|
||||
remotePosterUrl: React.PropTypes.string,
|
||||
remoteSrcVideoObject: React.PropTypes.object,
|
||||
renderRemoteVideo: React.PropTypes.bool.isRequired,
|
||||
@ -964,6 +968,60 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
useDesktopPaths: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
isLocalMediaAbsolutelyPositioned: function(matchMedia) {
|
||||
if (!matchMedia) {
|
||||
matchMedia = this.props.matchMedia;
|
||||
}
|
||||
return matchMedia &&
|
||||
// The screen width is less than 640px and we are not screen sharing.
|
||||
((matchMedia("screen and (max-width:640px)").matches &&
|
||||
!this.props.displayScreenShare) ||
|
||||
// or the screen width is less than 300px.
|
||||
(matchMedia("screen and (max-width:300px)").matches));
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
localMediaAboslutelyPositioned: this.isLocalMediaAbsolutelyPositioned()
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
// This is all for the ui-showcase's benefit.
|
||||
if (this.props.matchMedia != nextProps.matchMedia) {
|
||||
this.updateLocalMediaState(null, nextProps.matchMedia);
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
window.addEventListener("resize", this.updateLocalMediaState);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
window.removeEventListener("resize", this.updateLocalMediaState);
|
||||
},
|
||||
|
||||
updateLocalMediaState: function(event, matchMedia) {
|
||||
var newState = this.isLocalMediaAbsolutelyPositioned(matchMedia);
|
||||
if (this.state.localMediaAboslutelyPositioned != newState) {
|
||||
this.setState({
|
||||
localMediaAboslutelyPositioned: newState
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
renderLocalVideo: function() {
|
||||
return (
|
||||
React.createElement("div", {className: "local"},
|
||||
React.createElement(MediaView, {displayAvatar: this.props.localVideoMuted,
|
||||
isLoading: this.props.isLocalLoading,
|
||||
mediaType: "local",
|
||||
posterUrl: this.props.localPosterUrl,
|
||||
srcVideoObject: this.props.localSrcVideoObject})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var remoteStreamClasses = React.addons.classSet({
|
||||
"remote": true,
|
||||
@ -979,7 +1037,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
"media-wrapper": true,
|
||||
"receiving-screen-share": this.props.displayScreenShare,
|
||||
"showing-local-streams": this.props.localSrcVideoObject ||
|
||||
this.props.localPosterUrl
|
||||
this.props.localPosterUrl,
|
||||
"showing-remote-streams": this.props.remoteSrcVideoObject ||
|
||||
this.props.remotePosterUrl || this.props.isRemoteLoading
|
||||
});
|
||||
|
||||
return (
|
||||
@ -993,7 +1053,10 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
isLoading: this.props.isRemoteLoading,
|
||||
mediaType: "remote",
|
||||
posterUrl: this.props.remotePosterUrl,
|
||||
srcVideoObject: this.props.remoteSrcVideoObject})
|
||||
srcVideoObject: this.props.remoteSrcVideoObject}),
|
||||
this.state.localMediaAboslutelyPositioned ?
|
||||
this.renderLocalVideo() : null,
|
||||
this.props.children
|
||||
),
|
||||
React.createElement("div", {className: screenShareStreamClasses},
|
||||
React.createElement(MediaView, {displayAvatar: false,
|
||||
@ -1006,13 +1069,8 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
dispatcher: this.props.dispatcher,
|
||||
showRoomName: this.props.showContextRoomName,
|
||||
useDesktopPaths: false}),
|
||||
React.createElement("div", {className: "local"},
|
||||
React.createElement(MediaView, {displayAvatar: this.props.localVideoMuted,
|
||||
isLoading: this.props.isLocalLoading,
|
||||
mediaType: "local",
|
||||
posterUrl: this.props.localPosterUrl,
|
||||
srcVideoObject: this.props.localSrcVideoObject})
|
||||
)
|
||||
this.state.localMediaAboslutelyPositioned ?
|
||||
null : this.renderLocalVideo()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -946,6 +946,7 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
|
||||
var MediaLayoutView = React.createClass({
|
||||
propTypes: {
|
||||
children: React.PropTypes.node,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
displayScreenShare: React.PropTypes.bool.isRequired,
|
||||
isLocalLoading: React.PropTypes.bool.isRequired,
|
||||
@ -955,6 +956,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
localPosterUrl: React.PropTypes.string,
|
||||
localSrcVideoObject: React.PropTypes.object,
|
||||
localVideoMuted: React.PropTypes.bool.isRequired,
|
||||
// Passing in matchMedia, allows it to be overriden for ui-showcase's
|
||||
// benefit. We expect either the override or window.matchMedia.
|
||||
matchMedia: React.PropTypes.func.isRequired,
|
||||
remotePosterUrl: React.PropTypes.string,
|
||||
remoteSrcVideoObject: React.PropTypes.object,
|
||||
renderRemoteVideo: React.PropTypes.bool.isRequired,
|
||||
@ -964,6 +968,60 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
useDesktopPaths: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
isLocalMediaAbsolutelyPositioned: function(matchMedia) {
|
||||
if (!matchMedia) {
|
||||
matchMedia = this.props.matchMedia;
|
||||
}
|
||||
return matchMedia &&
|
||||
// The screen width is less than 640px and we are not screen sharing.
|
||||
((matchMedia("screen and (max-width:640px)").matches &&
|
||||
!this.props.displayScreenShare) ||
|
||||
// or the screen width is less than 300px.
|
||||
(matchMedia("screen and (max-width:300px)").matches));
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
localMediaAboslutelyPositioned: this.isLocalMediaAbsolutelyPositioned()
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
// This is all for the ui-showcase's benefit.
|
||||
if (this.props.matchMedia != nextProps.matchMedia) {
|
||||
this.updateLocalMediaState(null, nextProps.matchMedia);
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
window.addEventListener("resize", this.updateLocalMediaState);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
window.removeEventListener("resize", this.updateLocalMediaState);
|
||||
},
|
||||
|
||||
updateLocalMediaState: function(event, matchMedia) {
|
||||
var newState = this.isLocalMediaAbsolutelyPositioned(matchMedia);
|
||||
if (this.state.localMediaAboslutelyPositioned != newState) {
|
||||
this.setState({
|
||||
localMediaAboslutelyPositioned: newState
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
renderLocalVideo: function() {
|
||||
return (
|
||||
<div className="local">
|
||||
<MediaView displayAvatar={this.props.localVideoMuted}
|
||||
isLoading={this.props.isLocalLoading}
|
||||
mediaType="local"
|
||||
posterUrl={this.props.localPosterUrl}
|
||||
srcVideoObject={this.props.localSrcVideoObject} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var remoteStreamClasses = React.addons.classSet({
|
||||
"remote": true,
|
||||
@ -979,7 +1037,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
"media-wrapper": true,
|
||||
"receiving-screen-share": this.props.displayScreenShare,
|
||||
"showing-local-streams": this.props.localSrcVideoObject ||
|
||||
this.props.localPosterUrl
|
||||
this.props.localPosterUrl,
|
||||
"showing-remote-streams": this.props.remoteSrcVideoObject ||
|
||||
this.props.remotePosterUrl || this.props.isRemoteLoading
|
||||
});
|
||||
|
||||
return (
|
||||
@ -994,6 +1054,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
mediaType="remote"
|
||||
posterUrl={this.props.remotePosterUrl}
|
||||
srcVideoObject={this.props.remoteSrcVideoObject} />
|
||||
{ this.state.localMediaAboslutelyPositioned ?
|
||||
this.renderLocalVideo() : null }
|
||||
{ this.props.children }
|
||||
</div>
|
||||
<div className={screenShareStreamClasses}>
|
||||
<MediaView displayAvatar={false}
|
||||
@ -1006,13 +1069,8 @@ loop.shared.views = (function(_, mozL10n) {
|
||||
dispatcher={this.props.dispatcher}
|
||||
showRoomName={this.props.showContextRoomName}
|
||||
useDesktopPaths={false} />
|
||||
<div className="local">
|
||||
<MediaView displayAvatar={this.props.localVideoMuted}
|
||||
isLoading={this.props.isLocalLoading}
|
||||
mediaType="local"
|
||||
posterUrl={this.props.localPosterUrl}
|
||||
srcVideoObject={this.props.localSrcVideoObject} />
|
||||
</div>
|
||||
{ this.state.localMediaAboslutelyPositioned ?
|
||||
null : this.renderLocalVideo() }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -256,11 +256,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
mixins: [
|
||||
Backbone.Events,
|
||||
sharedMixins.MediaSetupMixin,
|
||||
sharedMixins.RoomsAudioMixin,
|
||||
loop.store.StoreMixin("activeRoomStore")
|
||||
sharedMixins.RoomsAudioMixin
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
// We pass conversationStore here rather than use the mixin, to allow
|
||||
// easy configurability for the ui-showcase.
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
@ -282,6 +283,16 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
});
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.props.activeRoomStore.on("change", function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
}, this);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.props.activeRoomStore.off("change", null, this);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
// Adding a class to the document body element from here to ease styling it.
|
||||
document.body.classList.add("is-standalone-room");
|
||||
@ -429,7 +440,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
*/
|
||||
_isScreenShareLoading: function() {
|
||||
return this.state.receivingScreenShare &&
|
||||
!this.state.screenShareVideoObject;
|
||||
!this.state.screenShareVideoObject &&
|
||||
!this.props.screenSharePosterUrl;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@ -456,6 +468,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
localPosterUrl: this.props.localPosterUrl,
|
||||
localSrcVideoObject: this.state.localSrcVideoObject,
|
||||
localVideoMuted: this.state.videoMuted,
|
||||
matchMedia: this.state.matchMedia || window.matchMedia.bind(window),
|
||||
remotePosterUrl: this.props.remotePosterUrl,
|
||||
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
||||
renderRemoteVideo: this.shouldRenderRemoteVideo(),
|
||||
|
@ -256,11 +256,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
mixins: [
|
||||
Backbone.Events,
|
||||
sharedMixins.MediaSetupMixin,
|
||||
sharedMixins.RoomsAudioMixin,
|
||||
loop.store.StoreMixin("activeRoomStore")
|
||||
sharedMixins.RoomsAudioMixin
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
// We pass conversationStore here rather than use the mixin, to allow
|
||||
// easy configurability for the ui-showcase.
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
@ -282,6 +283,16 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
});
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.props.activeRoomStore.on("change", function() {
|
||||
this.setState(this.props.activeRoomStore.getStoreState());
|
||||
}, this);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.props.activeRoomStore.off("change", null, this);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
// Adding a class to the document body element from here to ease styling it.
|
||||
document.body.classList.add("is-standalone-room");
|
||||
@ -429,7 +440,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
*/
|
||||
_isScreenShareLoading: function() {
|
||||
return this.state.receivingScreenShare &&
|
||||
!this.state.screenShareVideoObject;
|
||||
!this.state.screenShareVideoObject &&
|
||||
!this.props.screenSharePosterUrl;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@ -456,6 +468,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
localPosterUrl={this.props.localPosterUrl}
|
||||
localSrcVideoObject={this.state.localSrcVideoObject}
|
||||
localVideoMuted={this.state.videoMuted}
|
||||
matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
|
||||
remotePosterUrl={this.props.remotePosterUrl}
|
||||
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
||||
renderRemoteVideo={this.shouldRenderRemoteVideo()}
|
||||
|
@ -474,7 +474,9 @@ describe("loop.conversationViews", function () {
|
||||
describe("OngoingConversationView", function() {
|
||||
function mountTestComponent(extraProps) {
|
||||
var props = _.extend({
|
||||
dispatcher: dispatcher
|
||||
conversationStore: conversationStore,
|
||||
dispatcher: dispatcher,
|
||||
matchMedia: window.matchMedia
|
||||
}, extraProps);
|
||||
return TestUtils.renderIntoDocument(
|
||||
React.createElement(loop.conversationViews.OngoingConversationView, props));
|
||||
@ -489,15 +491,6 @@ describe("loop.conversationViews", function () {
|
||||
sinon.match.hasOwn("name", "setupStreamElements"));
|
||||
});
|
||||
|
||||
it("should display an avatar for remote video when the stream is not enabled", function() {
|
||||
view = mountTestComponent({
|
||||
mediaConnected: true,
|
||||
remoteVideoEnabled: false
|
||||
});
|
||||
|
||||
TestUtils.findRenderedComponentWithType(view, sharedViews.AvatarView);
|
||||
});
|
||||
|
||||
it("should display the remote video when the stream is enabled", function() {
|
||||
conversationStore.setStoreState({
|
||||
remoteSrcVideoObject: { fake: 1 }
|
||||
@ -511,16 +504,6 @@ describe("loop.conversationViews", function () {
|
||||
expect(view.getDOMNode().querySelector(".remote video")).not.eql(null);
|
||||
});
|
||||
|
||||
it("should display an avatar for local video when the stream is not enabled", function() {
|
||||
view = mountTestComponent({
|
||||
video: {
|
||||
enabled: false
|
||||
}
|
||||
});
|
||||
|
||||
TestUtils.findRenderedComponentWithType(view, sharedViews.AvatarView);
|
||||
});
|
||||
|
||||
it("should display the local video when the stream is enabled", function() {
|
||||
conversationStore.setStoreState({
|
||||
localSrcVideoObject: { fake: 1 }
|
||||
|
@ -95,7 +95,7 @@
|
||||
|
||||
describe("Unexpected Warnings Check", function() {
|
||||
it("should long only the warnings we expect", function() {
|
||||
chai.expect(caughtWarnings.length).to.eql(27);
|
||||
chai.expect(caughtWarnings.length).to.eql(28);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -598,21 +598,6 @@ describe("loop.roomViews", function () {
|
||||
|
||||
});
|
||||
|
||||
describe("Mute", function() {
|
||||
it("should render local media as audio-only if video is muted",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.SESSION_CONNECTED,
|
||||
videoMuted: true
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode().querySelector(".local-stream-audio"))
|
||||
.not.eql(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Edit Context", function() {
|
||||
it("should show the form when the edit button is clicked", function() {
|
||||
view = mountTestComponent();
|
||||
|
@ -99,7 +99,7 @@ class Test1BrowserCall(MarionetteTestCase):
|
||||
self.switch_to_chatbox()
|
||||
|
||||
# expect a video container on desktop side
|
||||
media_container = self.wait_for_element_displayed(By.CLASS_NAME, "media")
|
||||
media_container = self.wait_for_element_displayed(By.CLASS_NAME, "media-layout")
|
||||
self.assertEqual(media_container.tag_name, "div", "expect a video container")
|
||||
|
||||
self.check_video(".local-video")
|
||||
|
@ -21,6 +21,7 @@
|
||||
"gMozLoopAPI": true,
|
||||
"mockDb": true,
|
||||
"mockPushHandler": true,
|
||||
"OpenBrowserWindow": true,
|
||||
"promiseDeletedOAuthParams": false,
|
||||
"promiseOAuthGetRegistration": false,
|
||||
"promiseOAuthParamsSetup": false,
|
||||
|
@ -167,3 +167,19 @@ add_task(function* test_screen_share() {
|
||||
MozLoopService.setScreenShareState("1", false);
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
});
|
||||
|
||||
add_task(function* test_private_browsing_window() {
|
||||
let win = OpenBrowserWindow({ private: true });
|
||||
yield new Promise(resolve => {
|
||||
win.addEventListener("load", function listener() {
|
||||
win.removeEventListener("load", listener);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let button = win.LoopUI.toolbarButton.node;
|
||||
Assert.ok(button, "Loop button should be present");
|
||||
Assert.ok(button.getAttribute("disabled"), "Disabled attribute should be set");
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
@ -916,26 +916,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
});
|
||||
});
|
||||
|
||||
it("should retry publishing if on desktop, and in the videoMuted state", function() {
|
||||
store._isDesktop = true;
|
||||
|
||||
store.connectionFailure(new sharedActions.ConnectionFailure({
|
||||
reason: FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA
|
||||
}));
|
||||
|
||||
sinon.assert.calledOnce(fakeSdkDriver.retryPublishWithoutVideo);
|
||||
});
|
||||
|
||||
it("should set videoMuted to try when retrying publishing", function() {
|
||||
store._isDesktop = true;
|
||||
|
||||
store.connectionFailure(new sharedActions.ConnectionFailure({
|
||||
reason: FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA
|
||||
}));
|
||||
|
||||
expect(store.getStoreState().videoMuted).eql(true);
|
||||
});
|
||||
|
||||
it("should store the failure reason", function() {
|
||||
store.connectionFailure(connectionFailureAction);
|
||||
|
||||
|
@ -147,26 +147,6 @@ describe("loop.store.ConversationStore", function () {
|
||||
store.setStoreState({windowId: "42"});
|
||||
});
|
||||
|
||||
it("should retry publishing if on desktop, and in the videoMuted state", function() {
|
||||
store._isDesktop = true;
|
||||
|
||||
store.connectionFailure(new sharedActions.ConnectionFailure({
|
||||
reason: FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA
|
||||
}));
|
||||
|
||||
sinon.assert.calledOnce(sdkDriver.retryPublishWithoutVideo);
|
||||
});
|
||||
|
||||
it("should set videoMuted to try when retrying publishing", function() {
|
||||
store._isDesktop = true;
|
||||
|
||||
store.connectionFailure(new sharedActions.ConnectionFailure({
|
||||
reason: FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA
|
||||
}));
|
||||
|
||||
expect(store.getStoreState().videoMuted).eql(true);
|
||||
});
|
||||
|
||||
it("should disconnect the session", function() {
|
||||
store.connectionFailure(
|
||||
new sharedActions.ConnectionFailure({reason: "fake"}));
|
||||
|
@ -133,43 +133,6 @@ describe("loop.OTSdkDriver", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#retryPublishWithoutVideo", function() {
|
||||
beforeEach(function() {
|
||||
sdk.initPublisher.returns(publisher);
|
||||
|
||||
driver.setupStreamElements(new sharedActions.SetupStreamElements({
|
||||
publisherConfig: publisherConfig
|
||||
}));
|
||||
});
|
||||
|
||||
it("should make MediaStreamTrack.getSources return without a video source", function(done) {
|
||||
driver.retryPublishWithoutVideo();
|
||||
|
||||
window.MediaStreamTrack.getSources(function(sources) {
|
||||
expect(sources.some(function(src) {
|
||||
return src.kind === "video";
|
||||
})).eql(false);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should call initPublisher", function() {
|
||||
driver.retryPublishWithoutVideo();
|
||||
|
||||
var expectedConfig = _.extend({
|
||||
channels: {
|
||||
text: {}
|
||||
}
|
||||
}, publisherConfig);
|
||||
|
||||
sinon.assert.calledTwice(sdk.initPublisher);
|
||||
sinon.assert.calledWith(sdk.initPublisher,
|
||||
sinon.match.instanceOf(HTMLDivElement),
|
||||
expectedConfig);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#setMute", function() {
|
||||
beforeEach(function() {
|
||||
sdk.initPublisher.returns(publisher);
|
||||
|
@ -56,27 +56,6 @@ describe("loop.shared.views.TextChatView", function () {
|
||||
store.setStoreState({ textChatEnabled: true });
|
||||
});
|
||||
|
||||
it("should add an empty class when the list is empty", function() {
|
||||
view = mountTestComponent({
|
||||
messageList: []
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().classList.contains("text-chat-entries-empty")).eql(true);
|
||||
});
|
||||
|
||||
it("should not add an empty class when the list is has items", function() {
|
||||
view = mountTestComponent({
|
||||
messageList: [{
|
||||
type: CHAT_MESSAGE_TYPES.RECEIVED,
|
||||
contentType: CHAT_CONTENT_TYPES.TEXT,
|
||||
message: "Hello!",
|
||||
receivedTimestamp: "2015-06-25T17:53:55.357Z"
|
||||
}]
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().classList.contains("text-chat-entries-empty")).eql(false);
|
||||
});
|
||||
|
||||
it("should render message entries when message were sent/ received", function() {
|
||||
view = mountTestComponent({
|
||||
messageList: [{
|
||||
@ -297,6 +276,41 @@ describe("loop.shared.views.TextChatView", function () {
|
||||
fakeServer.restore();
|
||||
});
|
||||
|
||||
it("should add a disabled class when text chat is disabled", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
store.setStoreState({ textChatEnabled: false });
|
||||
|
||||
expect(view.getDOMNode().classList.contains("text-chat-disabled")).eql(true);
|
||||
});
|
||||
|
||||
it("should not a disabled class when text chat is enabled", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
store.setStoreState({ textChatEnabled: true });
|
||||
|
||||
expect(view.getDOMNode().classList.contains("text-chat-disabled")).eql(false);
|
||||
});
|
||||
|
||||
it("should add an empty class when the entries list is empty", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode().classList.contains("text-chat-entries-empty")).eql(true);
|
||||
});
|
||||
|
||||
it("should not add an empty class when the entries list is has items", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
store.sendTextChatMessage({
|
||||
contentType: CHAT_CONTENT_TYPES.TEXT,
|
||||
message: "Hello!",
|
||||
sentTimestamp: "1970-01-01T00:02:00.000Z",
|
||||
receivedTimestamp: "1970-01-01T00:02:00.000Z"
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().classList.contains("text-chat-entries-empty")).eql(false);
|
||||
});
|
||||
|
||||
it("should show timestamps from msgs sent more than 1 min apart", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
@ -326,12 +340,6 @@ describe("loop.shared.views.TextChatView", function () {
|
||||
.to.eql(2);
|
||||
});
|
||||
|
||||
it("should display the view if no messages and text chat is enabled", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode()).not.eql(null);
|
||||
});
|
||||
|
||||
it("should render message entries when message were sent/ received", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
|
@ -1057,6 +1057,7 @@ describe("loop.shared.views", function() {
|
||||
isRemoteLoading: false,
|
||||
isScreenShareLoading: false,
|
||||
localVideoMuted: false,
|
||||
matchMedia: window.matchMedia,
|
||||
renderRemoteVideo: false,
|
||||
showContextRoomName: false,
|
||||
useDesktopPaths: false
|
||||
@ -1144,5 +1145,35 @@ describe("loop.shared.views", function() {
|
||||
expect(view.getDOMNode().querySelector(".media-wrapper")
|
||||
.classList.contains("showing-local-streams")).eql(true);
|
||||
});
|
||||
|
||||
it("should not mark the wrapper as showing remote streams when not displaying a stream", function() {
|
||||
view = mountTestComponent({
|
||||
remoteSrcVideoObject: null,
|
||||
remotePosterUrl: null
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().querySelector(".media-wrapper")
|
||||
.classList.contains("showing-remote-streams")).eql(false);
|
||||
});
|
||||
|
||||
it("should mark the wrapper as showing remote streams when displaying a stream", function() {
|
||||
view = mountTestComponent({
|
||||
remoteSrcVideoObject: {},
|
||||
remotePosterUrl: null
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().querySelector(".media-wrapper")
|
||||
.classList.contains("showing-remote-streams")).eql(true);
|
||||
});
|
||||
|
||||
it("should mark the wrapper as showing remote streams when displaying a poster url", function() {
|
||||
view = mountTestComponent({
|
||||
remoteSrcVideoObject: {},
|
||||
remotePosterUrl: "fake/url"
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().querySelector(".media-wrapper")
|
||||
.classList.contains("showing-remote-streams")).eql(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -75,13 +75,25 @@
|
||||
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
|
||||
var mockSDK = _.extend({
|
||||
var MockSDK = function() {
|
||||
dispatcher.register(this, [
|
||||
"setupStreamElements"
|
||||
]);
|
||||
};
|
||||
|
||||
MockSDK.prototype = {
|
||||
setupStreamElements: function() {
|
||||
// Dummy function to stop warnings.
|
||||
},
|
||||
|
||||
sendTextChatMessage: function(message) {
|
||||
dispatcher.dispatch(new loop.shared.actions.ReceivedTextChatMessage({
|
||||
message: message.message
|
||||
}));
|
||||
}
|
||||
}, Backbone.Events);
|
||||
};
|
||||
|
||||
var mockSDK = new MockSDK();
|
||||
|
||||
/**
|
||||
* Every view that uses an activeRoomStore needs its own; if they shared
|
||||
@ -116,7 +128,6 @@
|
||||
});
|
||||
|
||||
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
||||
|
||||
// Since this is called by setTimeout, we don't want to lose any
|
||||
// exceptions if there's a problem and we need to debug, so...
|
||||
try {
|
||||
@ -136,6 +147,17 @@
|
||||
camera: {height: 480, orientation: 0, width: 640}
|
||||
},
|
||||
remoteVideoEnabled: options.remoteVideoEnabled,
|
||||
// Override the matchMedia, this is so that the correct version is
|
||||
// used for the frame.
|
||||
//
|
||||
// Currently, we use an icky hack, and the showcase conspires with
|
||||
// react-frame-component to set iframe.contentWindow.matchMedia onto
|
||||
// the store. Once React context matures a bit (somewhere between
|
||||
// 0.14 and 1.0, apparently):
|
||||
//
|
||||
// https://facebook.github.io/react/blog/2015/02/24/streamlining-react-elements.html#solution-make-context-parent-based-instead-of-owner-based
|
||||
//
|
||||
// we should be able to use those to clean this up.
|
||||
matchMedia: contentWindow.matchMedia.bind(contentWindow),
|
||||
roomState: options.roomState,
|
||||
videoMuted: !!options.videoMuted
|
||||
@ -185,6 +207,10 @@
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
});
|
||||
|
||||
var updatingMobileActiveRoomStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
});
|
||||
|
||||
var localFaceMuteRoomStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
videoMuted: true
|
||||
@ -201,12 +227,19 @@
|
||||
receivingScreenShare: true
|
||||
});
|
||||
|
||||
var updatingSharingRoomMobileStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
receivingScreenShare: true
|
||||
});
|
||||
|
||||
var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
|
||||
mediaConnected: false,
|
||||
receivingScreenShare: true,
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
remoteSrcVideoObject: false
|
||||
});
|
||||
var loadingScreenSharingRoomStore = makeActiveRoomStore({
|
||||
receivingScreenShare: true,
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
});
|
||||
|
||||
@ -234,7 +267,10 @@
|
||||
});
|
||||
|
||||
var invitationRoomStore = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.INIT
|
||||
})
|
||||
});
|
||||
|
||||
var roomStore = new loop.store.RoomStore(dispatcher, {
|
||||
@ -253,6 +289,20 @@
|
||||
})
|
||||
});
|
||||
|
||||
var desktopRoomStoreMedium = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
})
|
||||
});
|
||||
|
||||
var desktopRoomStoreLarge = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
})
|
||||
});
|
||||
|
||||
var desktopLocalFaceMuteActiveRoomStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
videoMuted: true
|
||||
@ -272,15 +322,59 @@
|
||||
activeRoomStore: desktopRemoteFaceMuteActiveRoomStore
|
||||
});
|
||||
|
||||
var conversationStore = new loop.store.ConversationStore(dispatcher, {
|
||||
client: {},
|
||||
mozLoop: navigator.mozLoop,
|
||||
sdkDriver: mockSDK
|
||||
});
|
||||
var textChatStore = new loop.store.TextChatStore(dispatcher, {
|
||||
sdkDriver: mockSDK
|
||||
});
|
||||
|
||||
/**
|
||||
* Every view that uses an conversationStore needs its own; if they shared
|
||||
* a conversation store, they'd interfere with each other.
|
||||
*
|
||||
* @param options
|
||||
* @returns {loop.store.ConversationStore}
|
||||
*/
|
||||
function makeConversationStore() {
|
||||
var roomDispatcher = new loop.Dispatcher();
|
||||
|
||||
var store = new loop.store.ConversationStore(dispatcher, {
|
||||
client: {},
|
||||
mozLoop: navigator.mozLoop,
|
||||
sdkDriver: mockSDK
|
||||
});
|
||||
|
||||
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
||||
// Since this is called by setTimeout, we don't want to lose any
|
||||
// exceptions if there's a problem and we need to debug, so...
|
||||
try {
|
||||
var newStoreState = {
|
||||
// Override the matchMedia, this is so that the correct version is
|
||||
// used for the frame.
|
||||
//
|
||||
// Currently, we use an icky hack, and the showcase conspires with
|
||||
// react-frame-component to set iframe.contentWindow.matchMedia onto
|
||||
// the store. Once React context matures a bit (somewhere between
|
||||
// 0.14 and 1.0, apparently):
|
||||
//
|
||||
// https://facebook.github.io/react/blog/2015/02/24/streamlining-react-elements.html#solution-make-context-parent-based-instead-of-owner-based
|
||||
//
|
||||
// we should be able to use those to clean this up.
|
||||
matchMedia: contentWindow.matchMedia.bind(contentWindow)
|
||||
};
|
||||
|
||||
store.setStoreState(newStoreState);
|
||||
} catch (ex) {
|
||||
console.error("exception in forcedUpdate:", ex);
|
||||
}
|
||||
};
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
var conversationStores = [];
|
||||
for (var index = 0; index < 5; index++) {
|
||||
conversationStores[index] = makeConversationStore();
|
||||
}
|
||||
|
||||
// Update the text chat store with the room info.
|
||||
textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
|
||||
roomName: "A Very Long Conversation Name",
|
||||
@ -341,7 +435,7 @@
|
||||
|
||||
loop.store.StoreMixin.register({
|
||||
activeRoomStore: activeRoomStore,
|
||||
conversationStore: conversationStore,
|
||||
conversationStore: conversationStores[0],
|
||||
textChatStore: textChatStore
|
||||
});
|
||||
|
||||
@ -360,14 +454,6 @@
|
||||
requestCallUrlInfo: noop
|
||||
};
|
||||
|
||||
var mockConversationModel = new loop.shared.models.ConversationModel({
|
||||
callerId: "Mrs Jones",
|
||||
urlCreationDate: (new Date() / 1000).toString()
|
||||
}, {
|
||||
sdk: mockSDK
|
||||
});
|
||||
mockConversationModel.startSession = noop;
|
||||
|
||||
var mockWebSocket = new loop.CallConnectionWebSocket({
|
||||
url: "fake",
|
||||
callId: "fakeId",
|
||||
@ -763,7 +849,7 @@
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
||||
outgoing: false,
|
||||
store: conversationStore})
|
||||
store: conversationStores[0]})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true,
|
||||
@ -772,7 +858,7 @@
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
||||
outgoing: true,
|
||||
store: conversationStore})
|
||||
store: conversationStores[1]})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true,
|
||||
@ -781,18 +867,22 @@
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(CallFailedView, {dispatcher: dispatcher, emailLinkError: true,
|
||||
outgoing: true,
|
||||
store: conversationStore})
|
||||
store: conversationStores[0]})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "OngoingConversationView"},
|
||||
React.createElement(FramedExample, {height: 254,
|
||||
summary: "Desktop ongoing conversation window",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: conversationStores[0].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
conversationStore: conversationStores[0],
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mediaConnected: true,
|
||||
@ -802,28 +892,55 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {height: 600,
|
||||
summary: "Desktop ongoing conversation window large",
|
||||
width: 800},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mediaConnected: true,
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
remoteVideoEnabled: true,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 400,
|
||||
onContentsRendered: conversationStores[1].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window (medium)",
|
||||
width: 600},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
conversationStore: conversationStores[1],
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mediaConnected: true,
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
remoteVideoEnabled: true,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {height: 254,
|
||||
React.createElement(FramedExample, {
|
||||
height: 600,
|
||||
onContentsRendered: conversationStores[2].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window (large)",
|
||||
width: 800},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
conversationStore: conversationStores[2],
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mediaConnected: true,
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
remoteVideoEnabled: true,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: conversationStores[3].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window - local face mute",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
conversationStore: conversationStores[3],
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mediaConnected: true,
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
remoteVideoEnabled: true,
|
||||
@ -831,15 +948,19 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {height: 254,
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true, height: 394,
|
||||
onContentsRendered: conversationStores[4].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window - remote face mute",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
conversationStore: conversationStores[4],
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mediaConnected: true,
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
remoteVideoEnabled: false,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
@ -894,7 +1015,8 @@
|
||||
|
||||
React.createElement(Section, {name: "DesktopRoomConversationView"},
|
||||
React.createElement(FramedExample, {
|
||||
height: 254,
|
||||
height: 398,
|
||||
onContentsRendered: invitationRoomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
@ -911,6 +1033,7 @@
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: desktopRoomStoreLoading.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (loading)",
|
||||
width: 298},
|
||||
/* Hide scrollbars here. Rotating loading div overflows and causes
|
||||
@ -927,8 +1050,12 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {height: 254,
|
||||
summary: "Desktop room conversation"},
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: roomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
@ -941,10 +1068,48 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
summary: "Desktop room conversation local face-mute",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 482,
|
||||
onContentsRendered: desktopRoomStoreMedium.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (medium)",
|
||||
width: 602},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mozLoop: navigator.mozLoop,
|
||||
onCallTerminated: function(){},
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
roomStore: desktopRoomStoreMedium})
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 485,
|
||||
onContentsRendered: desktopRoomStoreLarge.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (large)",
|
||||
width: 646},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mozLoop: navigator.mozLoop,
|
||||
onCallTerminated: function(){},
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
roomStore: desktopRoomStoreLarge})
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation local face-mute",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
@ -955,7 +1120,9 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {dashed: true, height: 394,
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: desktopRemoteFaceMuteRoomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation remote face-mute",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
@ -964,6 +1131,7 @@
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
mozLoop: navigator.mozLoop,
|
||||
onCallTerminated: function(){},
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
roomStore: desktopRemoteFaceMuteRoomStore})
|
||||
)
|
||||
)
|
||||
@ -1081,8 +1249,7 @@
|
||||
isFirefox: true,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
screenSharePosterUrl: "sample-img/video-screen-baz.png"})
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS})
|
||||
)
|
||||
),
|
||||
|
||||
@ -1102,8 +1269,7 @@
|
||||
isFirefox: true,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
screenSharePosterUrl: "sample-img/video-screen-baz.png"})
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS})
|
||||
)
|
||||
),
|
||||
|
||||
@ -1171,12 +1337,12 @@
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 480,
|
||||
onContentsRendered: updatingActiveRoomStore.forcedUpdate,
|
||||
onContentsRendered: updatingMobileActiveRoomStore.forcedUpdate,
|
||||
summary: "Standalone room conversation (has-participants, 600x480)",
|
||||
width: 600},
|
||||
React.createElement("div", {className: "standalone"},
|
||||
React.createElement(StandaloneRoomView, {
|
||||
activeRoomStore: updatingActiveRoomStore,
|
||||
activeRoomStore: updatingMobileActiveRoomStore,
|
||||
dispatcher: dispatcher,
|
||||
isFirefox: true,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
@ -1189,12 +1355,12 @@
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 480,
|
||||
onContentsRendered: updatingSharingRoomStore.forcedUpdate,
|
||||
onContentsRendered: updatingSharingRoomMobileStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, receivingScreenShare, 600x480)",
|
||||
width: 600},
|
||||
React.createElement("div", {className: "standalone", cssClass: "standalone"},
|
||||
React.createElement(StandaloneRoomView, {
|
||||
activeRoomStore: updatingSharingRoomStore,
|
||||
activeRoomStore: updatingSharingRoomMobileStore,
|
||||
dispatcher: dispatcher,
|
||||
isFirefox: true,
|
||||
localPosterUrl: "sample-img/video-screen-local.png",
|
||||
@ -1282,7 +1448,7 @@
|
||||
|
||||
// This simulates the mocha layout for errors which means we can run
|
||||
// this alongside our other unit tests but use the same harness.
|
||||
var expectedWarningsCount = 23;
|
||||
var expectedWarningsCount = 18;
|
||||
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
||||
if (uncaughtError || warningsMismatch) {
|
||||
$("#results").append("<div class='failures'><em>" +
|
||||
|
@ -75,13 +75,25 @@
|
||||
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
|
||||
var mockSDK = _.extend({
|
||||
var MockSDK = function() {
|
||||
dispatcher.register(this, [
|
||||
"setupStreamElements"
|
||||
]);
|
||||
};
|
||||
|
||||
MockSDK.prototype = {
|
||||
setupStreamElements: function() {
|
||||
// Dummy function to stop warnings.
|
||||
},
|
||||
|
||||
sendTextChatMessage: function(message) {
|
||||
dispatcher.dispatch(new loop.shared.actions.ReceivedTextChatMessage({
|
||||
message: message.message
|
||||
}));
|
||||
}
|
||||
}, Backbone.Events);
|
||||
};
|
||||
|
||||
var mockSDK = new MockSDK();
|
||||
|
||||
/**
|
||||
* Every view that uses an activeRoomStore needs its own; if they shared
|
||||
@ -116,7 +128,6 @@
|
||||
});
|
||||
|
||||
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
||||
|
||||
// Since this is called by setTimeout, we don't want to lose any
|
||||
// exceptions if there's a problem and we need to debug, so...
|
||||
try {
|
||||
@ -136,6 +147,17 @@
|
||||
camera: {height: 480, orientation: 0, width: 640}
|
||||
},
|
||||
remoteVideoEnabled: options.remoteVideoEnabled,
|
||||
// Override the matchMedia, this is so that the correct version is
|
||||
// used for the frame.
|
||||
//
|
||||
// Currently, we use an icky hack, and the showcase conspires with
|
||||
// react-frame-component to set iframe.contentWindow.matchMedia onto
|
||||
// the store. Once React context matures a bit (somewhere between
|
||||
// 0.14 and 1.0, apparently):
|
||||
//
|
||||
// https://facebook.github.io/react/blog/2015/02/24/streamlining-react-elements.html#solution-make-context-parent-based-instead-of-owner-based
|
||||
//
|
||||
// we should be able to use those to clean this up.
|
||||
matchMedia: contentWindow.matchMedia.bind(contentWindow),
|
||||
roomState: options.roomState,
|
||||
videoMuted: !!options.videoMuted
|
||||
@ -185,6 +207,10 @@
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
});
|
||||
|
||||
var updatingMobileActiveRoomStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
});
|
||||
|
||||
var localFaceMuteRoomStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
videoMuted: true
|
||||
@ -201,12 +227,19 @@
|
||||
receivingScreenShare: true
|
||||
});
|
||||
|
||||
var updatingSharingRoomMobileStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
receivingScreenShare: true
|
||||
});
|
||||
|
||||
var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
|
||||
mediaConnected: false,
|
||||
receivingScreenShare: true,
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
remoteSrcVideoObject: false
|
||||
});
|
||||
var loadingScreenSharingRoomStore = makeActiveRoomStore({
|
||||
receivingScreenShare: true,
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
});
|
||||
|
||||
@ -234,7 +267,10 @@
|
||||
});
|
||||
|
||||
var invitationRoomStore = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.INIT
|
||||
})
|
||||
});
|
||||
|
||||
var roomStore = new loop.store.RoomStore(dispatcher, {
|
||||
@ -253,6 +289,20 @@
|
||||
})
|
||||
});
|
||||
|
||||
var desktopRoomStoreMedium = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
})
|
||||
});
|
||||
|
||||
var desktopRoomStoreLarge = new loop.store.RoomStore(dispatcher, {
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||
})
|
||||
});
|
||||
|
||||
var desktopLocalFaceMuteActiveRoomStore = makeActiveRoomStore({
|
||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||
videoMuted: true
|
||||
@ -272,15 +322,59 @@
|
||||
activeRoomStore: desktopRemoteFaceMuteActiveRoomStore
|
||||
});
|
||||
|
||||
var conversationStore = new loop.store.ConversationStore(dispatcher, {
|
||||
client: {},
|
||||
mozLoop: navigator.mozLoop,
|
||||
sdkDriver: mockSDK
|
||||
});
|
||||
var textChatStore = new loop.store.TextChatStore(dispatcher, {
|
||||
sdkDriver: mockSDK
|
||||
});
|
||||
|
||||
/**
|
||||
* Every view that uses an conversationStore needs its own; if they shared
|
||||
* a conversation store, they'd interfere with each other.
|
||||
*
|
||||
* @param options
|
||||
* @returns {loop.store.ConversationStore}
|
||||
*/
|
||||
function makeConversationStore() {
|
||||
var roomDispatcher = new loop.Dispatcher();
|
||||
|
||||
var store = new loop.store.ConversationStore(dispatcher, {
|
||||
client: {},
|
||||
mozLoop: navigator.mozLoop,
|
||||
sdkDriver: mockSDK
|
||||
});
|
||||
|
||||
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
||||
// Since this is called by setTimeout, we don't want to lose any
|
||||
// exceptions if there's a problem and we need to debug, so...
|
||||
try {
|
||||
var newStoreState = {
|
||||
// Override the matchMedia, this is so that the correct version is
|
||||
// used for the frame.
|
||||
//
|
||||
// Currently, we use an icky hack, and the showcase conspires with
|
||||
// react-frame-component to set iframe.contentWindow.matchMedia onto
|
||||
// the store. Once React context matures a bit (somewhere between
|
||||
// 0.14 and 1.0, apparently):
|
||||
//
|
||||
// https://facebook.github.io/react/blog/2015/02/24/streamlining-react-elements.html#solution-make-context-parent-based-instead-of-owner-based
|
||||
//
|
||||
// we should be able to use those to clean this up.
|
||||
matchMedia: contentWindow.matchMedia.bind(contentWindow)
|
||||
};
|
||||
|
||||
store.setStoreState(newStoreState);
|
||||
} catch (ex) {
|
||||
console.error("exception in forcedUpdate:", ex);
|
||||
}
|
||||
};
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
var conversationStores = [];
|
||||
for (var index = 0; index < 5; index++) {
|
||||
conversationStores[index] = makeConversationStore();
|
||||
}
|
||||
|
||||
// Update the text chat store with the room info.
|
||||
textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
|
||||
roomName: "A Very Long Conversation Name",
|
||||
@ -341,7 +435,7 @@
|
||||
|
||||
loop.store.StoreMixin.register({
|
||||
activeRoomStore: activeRoomStore,
|
||||
conversationStore: conversationStore,
|
||||
conversationStore: conversationStores[0],
|
||||
textChatStore: textChatStore
|
||||
});
|
||||
|
||||
@ -360,14 +454,6 @@
|
||||
requestCallUrlInfo: noop
|
||||
};
|
||||
|
||||
var mockConversationModel = new loop.shared.models.ConversationModel({
|
||||
callerId: "Mrs Jones",
|
||||
urlCreationDate: (new Date() / 1000).toString()
|
||||
}, {
|
||||
sdk: mockSDK
|
||||
});
|
||||
mockConversationModel.startSession = noop;
|
||||
|
||||
var mockWebSocket = new loop.CallConnectionWebSocket({
|
||||
url: "fake",
|
||||
callId: "fakeId",
|
||||
@ -763,7 +849,7 @@
|
||||
<div className="fx-embedded">
|
||||
<CallFailedView dispatcher={dispatcher}
|
||||
outgoing={false}
|
||||
store={conversationStore} />
|
||||
store={conversationStores[0]} />
|
||||
</div>
|
||||
</Example>
|
||||
<Example dashed={true}
|
||||
@ -772,7 +858,7 @@
|
||||
<div className="fx-embedded">
|
||||
<CallFailedView dispatcher={dispatcher}
|
||||
outgoing={true}
|
||||
store={conversationStore} />
|
||||
store={conversationStores[1]} />
|
||||
</div>
|
||||
</Example>
|
||||
<Example dashed={true}
|
||||
@ -781,18 +867,22 @@
|
||||
<div className="fx-embedded">
|
||||
<CallFailedView dispatcher={dispatcher} emailLinkError={true}
|
||||
outgoing={true}
|
||||
store={conversationStore} />
|
||||
store={conversationStores[0]} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="OngoingConversationView">
|
||||
<FramedExample height={254}
|
||||
summary="Desktop ongoing conversation window"
|
||||
width={298}>
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={394}
|
||||
onContentsRendered={conversationStores[0].forcedUpdate}
|
||||
summary="Desktop ongoing conversation window"
|
||||
width={298}>
|
||||
<div className="fx-embedded">
|
||||
<OngoingConversationView
|
||||
audio={{enabled: true}}
|
||||
conversationStore={conversationStores[0]}
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mediaConnected={true}
|
||||
@ -802,28 +892,55 @@
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample height={600}
|
||||
summary="Desktop ongoing conversation window large"
|
||||
width={800}>
|
||||
<div className="fx-embedded">
|
||||
<OngoingConversationView
|
||||
audio={{enabled: true}}
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mediaConnected={true}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
remoteVideoEnabled={true}
|
||||
video={{enabled: true}} />
|
||||
</div>
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={400}
|
||||
onContentsRendered={conversationStores[1].forcedUpdate}
|
||||
summary="Desktop ongoing conversation window (medium)"
|
||||
width={600}>
|
||||
<div className="fx-embedded">
|
||||
<OngoingConversationView
|
||||
audio={{enabled: true}}
|
||||
conversationStore={conversationStores[1]}
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mediaConnected={true}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
remoteVideoEnabled={true}
|
||||
video={{enabled: true}} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample height={254}
|
||||
<FramedExample
|
||||
height={600}
|
||||
onContentsRendered={conversationStores[2].forcedUpdate}
|
||||
summary="Desktop ongoing conversation window (large)"
|
||||
width={800}>
|
||||
<div className="fx-embedded">
|
||||
<OngoingConversationView
|
||||
audio={{enabled: true}}
|
||||
conversationStore={conversationStores[2]}
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mediaConnected={true}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
remoteVideoEnabled={true}
|
||||
video={{enabled: true}} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={394}
|
||||
onContentsRendered={conversationStores[3].forcedUpdate}
|
||||
summary="Desktop ongoing conversation window - local face mute"
|
||||
width={298} >
|
||||
<div className="fx-embedded">
|
||||
<OngoingConversationView
|
||||
audio={{enabled: true}}
|
||||
conversationStore={conversationStores[3]}
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mediaConnected={true}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
remoteVideoEnabled={true}
|
||||
@ -831,15 +948,19 @@
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample height={254}
|
||||
<FramedExample
|
||||
dashed={true} height={394}
|
||||
onContentsRendered={conversationStores[4].forcedUpdate}
|
||||
summary="Desktop ongoing conversation window - remote face mute"
|
||||
width={298} >
|
||||
<div className="fx-embedded">
|
||||
<OngoingConversationView
|
||||
audio={{enabled: true}}
|
||||
conversationStore={conversationStores[4]}
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mediaConnected={true}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
remoteVideoEnabled={false}
|
||||
video={{enabled: true}} />
|
||||
</div>
|
||||
@ -894,7 +1015,8 @@
|
||||
|
||||
<Section name="DesktopRoomConversationView">
|
||||
<FramedExample
|
||||
height={254}
|
||||
height={398}
|
||||
onContentsRendered={invitationRoomStore.activeRoomStore.forcedUpdate}
|
||||
summary="Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)"
|
||||
width={298}>
|
||||
<div className="fx-embedded">
|
||||
@ -911,6 +1033,7 @@
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={394}
|
||||
onContentsRendered={desktopRoomStoreLoading.activeRoomStore.forcedUpdate}
|
||||
summary="Desktop room conversation (loading)"
|
||||
width={298}>
|
||||
{/* Hide scrollbars here. Rotating loading div overflows and causes
|
||||
@ -927,8 +1050,12 @@
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample height={254}
|
||||
summary="Desktop room conversation">
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={394}
|
||||
onContentsRendered={roomStore.activeRoomStore.forcedUpdate}
|
||||
summary="Desktop room conversation"
|
||||
width={298}>
|
||||
<div className="fx-embedded">
|
||||
<DesktopRoomConversationView
|
||||
dispatcher={dispatcher}
|
||||
@ -941,10 +1068,48 @@
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample dashed={true}
|
||||
height={394}
|
||||
summary="Desktop room conversation local face-mute"
|
||||
width={298}>
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={482}
|
||||
onContentsRendered={desktopRoomStoreMedium.activeRoomStore.forcedUpdate}
|
||||
summary="Desktop room conversation (medium)"
|
||||
width={602}>
|
||||
<div className="fx-embedded">
|
||||
<DesktopRoomConversationView
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mozLoop={navigator.mozLoop}
|
||||
onCallTerminated={function(){}}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
roomState={ROOM_STATES.HAS_PARTICIPANTS}
|
||||
roomStore={desktopRoomStoreMedium} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={485}
|
||||
onContentsRendered={desktopRoomStoreLarge.activeRoomStore.forcedUpdate}
|
||||
summary="Desktop room conversation (large)"
|
||||
width={646}>
|
||||
<div className="fx-embedded">
|
||||
<DesktopRoomConversationView
|
||||
dispatcher={dispatcher}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mozLoop={navigator.mozLoop}
|
||||
onCallTerminated={function(){}}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
roomState={ROOM_STATES.HAS_PARTICIPANTS}
|
||||
roomStore={desktopRoomStoreLarge} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample
|
||||
dashed={true}
|
||||
height={394}
|
||||
onContentsRendered={desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate}
|
||||
summary="Desktop room conversation local face-mute"
|
||||
width={298}>
|
||||
<div className="fx-embedded">
|
||||
<DesktopRoomConversationView
|
||||
dispatcher={dispatcher}
|
||||
@ -955,7 +1120,9 @@
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
<FramedExample dashed={true} height={394}
|
||||
<FramedExample dashed={true}
|
||||
height={394}
|
||||
onContentsRendered={desktopRemoteFaceMuteRoomStore.activeRoomStore.forcedUpdate}
|
||||
summary="Desktop room conversation remote face-mute"
|
||||
width={298} >
|
||||
<div className="fx-embedded">
|
||||
@ -964,6 +1131,7 @@
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
mozLoop={navigator.mozLoop}
|
||||
onCallTerminated={function(){}}
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
roomStore={desktopRemoteFaceMuteRoomStore} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
@ -1081,8 +1249,7 @@
|
||||
isFirefox={true}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
roomState={ROOM_STATES.HAS_PARTICIPANTS}
|
||||
screenSharePosterUrl="sample-img/video-screen-baz.png" />
|
||||
roomState={ROOM_STATES.HAS_PARTICIPANTS} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
@ -1102,8 +1269,7 @@
|
||||
isFirefox={true}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||
roomState={ROOM_STATES.HAS_PARTICIPANTS}
|
||||
screenSharePosterUrl="sample-img/video-screen-baz.png" />
|
||||
roomState={ROOM_STATES.HAS_PARTICIPANTS} />
|
||||
</div>
|
||||
</FramedExample>
|
||||
|
||||
@ -1171,12 +1337,12 @@
|
||||
cssClass="standalone"
|
||||
dashed={true}
|
||||
height={480}
|
||||
onContentsRendered={updatingActiveRoomStore.forcedUpdate}
|
||||
onContentsRendered={updatingMobileActiveRoomStore.forcedUpdate}
|
||||
summary="Standalone room conversation (has-participants, 600x480)"
|
||||
width={600}>
|
||||
<div className="standalone">
|
||||
<StandaloneRoomView
|
||||
activeRoomStore={updatingActiveRoomStore}
|
||||
activeRoomStore={updatingMobileActiveRoomStore}
|
||||
dispatcher={dispatcher}
|
||||
isFirefox={true}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
@ -1189,12 +1355,12 @@
|
||||
cssClass="standalone"
|
||||
dashed={true}
|
||||
height={480}
|
||||
onContentsRendered={updatingSharingRoomStore.forcedUpdate}
|
||||
onContentsRendered={updatingSharingRoomMobileStore.forcedUpdate}
|
||||
summary="Standalone room convo (has-participants, receivingScreenShare, 600x480)"
|
||||
width={600} >
|
||||
<div className="standalone" cssClass="standalone">
|
||||
<StandaloneRoomView
|
||||
activeRoomStore={updatingSharingRoomStore}
|
||||
activeRoomStore={updatingSharingRoomMobileStore}
|
||||
dispatcher={dispatcher}
|
||||
isFirefox={true}
|
||||
localPosterUrl="sample-img/video-screen-local.png"
|
||||
@ -1282,7 +1448,7 @@
|
||||
|
||||
// This simulates the mocha layout for errors which means we can run
|
||||
// this alongside our other unit tests but use the same harness.
|
||||
var expectedWarningsCount = 23;
|
||||
var expectedWarningsCount = 18;
|
||||
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
||||
if (uncaughtError || warningsMismatch) {
|
||||
$("#results").append("<div class='failures'><em>" +
|
||||
|
@ -4,7 +4,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* globals overlays, StyleInspectorMenu */
|
||||
/* globals overlays, StyleInspectorMenu, loader, clipboardHelper,
|
||||
_Iterator, StopIteration */
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -49,8 +50,7 @@ const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function UpdateProcess(aWin, aGenerator, aOptions)
|
||||
{
|
||||
function UpdateProcess(aWin, aGenerator, aOptions) {
|
||||
this.win = aWin;
|
||||
this.iter = _Iterator(aGenerator);
|
||||
this.onItem = aOptions.onItem || function() {};
|
||||
@ -66,8 +66,7 @@ UpdateProcess.prototype = {
|
||||
/**
|
||||
* Schedule a new batch on the main loop.
|
||||
*/
|
||||
schedule: function UP_schedule()
|
||||
{
|
||||
schedule: function() {
|
||||
if (this.canceled) {
|
||||
return;
|
||||
}
|
||||
@ -78,8 +77,7 @@ UpdateProcess.prototype = {
|
||||
* Cancel the running process. onItem will not be called again,
|
||||
* and onCancel will be called.
|
||||
*/
|
||||
cancel: function UP_cancel()
|
||||
{
|
||||
cancel: function() {
|
||||
if (this._timeout) {
|
||||
this.win.clearTimeout(this._timeout);
|
||||
this._timeout = 0;
|
||||
@ -88,7 +86,7 @@ UpdateProcess.prototype = {
|
||||
this.onCancel();
|
||||
},
|
||||
|
||||
_timeoutHandler: function UP_timeoutHandler() {
|
||||
_timeoutHandler: function() {
|
||||
this._timeout = null;
|
||||
try {
|
||||
this._runBatch();
|
||||
@ -104,10 +102,9 @@ UpdateProcess.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_runBatch: function Y_runBatch()
|
||||
{
|
||||
_runBatch: function() {
|
||||
let time = Date.now();
|
||||
while(!this.canceled) {
|
||||
while (!this.canceled) {
|
||||
// Continue until iter.next() throws...
|
||||
let next = this.iter.next();
|
||||
this.onItem(next[1]);
|
||||
@ -120,9 +117,9 @@ UpdateProcess.prototype = {
|
||||
};
|
||||
|
||||
/**
|
||||
* CssComputedView is a panel that manages the display of a table sorted by style.
|
||||
* There should be one instance of CssComputedView per style display (of which there
|
||||
* will generally only be one).
|
||||
* CssComputedView is a panel that manages the display of a table
|
||||
* sorted by style. There should be one instance of CssComputedView
|
||||
* per style display (of which there will generally only be one).
|
||||
*
|
||||
* @param {Inspector} inspector toolbox panel
|
||||
* @param {Document} document The document that will contain the computed view.
|
||||
@ -142,8 +139,8 @@ function CssComputedView(inspector, document, pageStyle) {
|
||||
|
||||
this._outputParser = new OutputParser();
|
||||
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIXULChromeRegistry);
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry);
|
||||
this.getRTLAttr = chromeReg.isLocaleRTL("global") ? "rtl" : "ltr";
|
||||
|
||||
// Create bound methods.
|
||||
@ -211,8 +208,7 @@ function CssComputedView(inspector, document, pageStyle) {
|
||||
* @param {string} aName The key to lookup.
|
||||
* @returns A localized version of the given key.
|
||||
*/
|
||||
CssComputedView.l10n = function CssComputedView_l10n(aName)
|
||||
{
|
||||
CssComputedView.l10n = function(aName) {
|
||||
try {
|
||||
return CssComputedView._strings.GetStringFromName(aName);
|
||||
} catch (ex) {
|
||||
@ -251,8 +247,7 @@ CssComputedView.prototype = {
|
||||
this.pageStyle = pageStyle;
|
||||
},
|
||||
|
||||
get includeBrowserStyles()
|
||||
{
|
||||
get includeBrowserStyles() {
|
||||
return this.includeBrowserStylesCheckbox.checked;
|
||||
},
|
||||
|
||||
@ -264,8 +259,9 @@ CssComputedView.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the view with a new selected element.
|
||||
* The CssComputedView panel will show the style information for the given element.
|
||||
* Update the view with a new selected element. The CssComputedView panel
|
||||
* will show the style information for the given element.
|
||||
*
|
||||
* @param {NodeFront} aElement The highlighted node to get styles for.
|
||||
* @returns a promise that will be resolved when highlighting is complete.
|
||||
*/
|
||||
@ -383,8 +379,7 @@ CssComputedView.prototype = {
|
||||
return {type, value};
|
||||
},
|
||||
|
||||
_createPropertyViews: function()
|
||||
{
|
||||
_createPropertyViews: function() {
|
||||
if (this._createViewsPromise) {
|
||||
return this._createViewsPromise;
|
||||
}
|
||||
@ -396,7 +391,8 @@ CssComputedView.prototype = {
|
||||
this.numVisibleProperties = 0;
|
||||
let fragment = this.styleDocument.createDocumentFragment();
|
||||
|
||||
this._createViewsProcess = new UpdateProcess(this.styleWindow, CssComputedView.propertyNames, {
|
||||
this._createViewsProcess = new UpdateProcess(
|
||||
this.styleWindow, CssComputedView.propertyNames, {
|
||||
onItem: (aPropertyName) => {
|
||||
// Per-item callback.
|
||||
let propView = new PropertyView(this, aPropertyName);
|
||||
@ -426,8 +422,7 @@ CssComputedView.prototype = {
|
||||
/**
|
||||
* Refresh the panel content.
|
||||
*/
|
||||
refreshPanel: function CssComputedView_refreshPanel()
|
||||
{
|
||||
refreshPanel: function() {
|
||||
if (!this.viewedElement) {
|
||||
return promise.resolve();
|
||||
}
|
||||
@ -443,12 +438,12 @@ CssComputedView.prototype = {
|
||||
onlyMatched: !this.includeBrowserStyles,
|
||||
markMatched: true
|
||||
})
|
||||
]).then(([createViews, computed]) => {
|
||||
]).then(([, computed]) => {
|
||||
if (viewedElement !== this.viewedElement) {
|
||||
return;
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
this._matchedProperties = new Set;
|
||||
this._matchedProperties = new Set();
|
||||
for (let name in computed) {
|
||||
if (computed[name].matched) {
|
||||
this._matchedProperties.add(name);
|
||||
@ -469,7 +464,8 @@ CssComputedView.prototype = {
|
||||
this._darkStripe = true;
|
||||
|
||||
let deferred = promise.defer();
|
||||
this._refreshProcess = new UpdateProcess(this.styleWindow, this.propertyViews, {
|
||||
this._refreshProcess = new UpdateProcess(
|
||||
this.styleWindow, this.propertyViews, {
|
||||
onItem: (aPropView) => {
|
||||
aPropView.refresh();
|
||||
},
|
||||
@ -511,8 +507,7 @@ CssComputedView.prototype = {
|
||||
*
|
||||
* @param {Event} aEvent the DOM Event object.
|
||||
*/
|
||||
_onFilterStyles: function(aEvent)
|
||||
{
|
||||
_onFilterStyles: function(aEvent) {
|
||||
let win = this.styleWindow;
|
||||
|
||||
if (this._filterChangedTimeout) {
|
||||
@ -580,8 +575,7 @@ CssComputedView.prototype = {
|
||||
*
|
||||
* @param {Event} aEvent the DOM Event object.
|
||||
*/
|
||||
_onIncludeBrowserStyles: function(aEvent)
|
||||
{
|
||||
_onIncludeBrowserStyles: function(aEvent) {
|
||||
this.refreshSourceFilter();
|
||||
this.refreshPanel();
|
||||
},
|
||||
@ -592,16 +586,14 @@ CssComputedView.prototype = {
|
||||
* document or one of thedocument's stylesheets. If .checked is false we
|
||||
* display all properties including those that come from UA stylesheets.
|
||||
*/
|
||||
refreshSourceFilter: function CssComputedView_setSourceFilter()
|
||||
{
|
||||
refreshSourceFilter: function() {
|
||||
this._matchedProperties = null;
|
||||
this._sourceFilter = this.includeBrowserStyles ?
|
||||
CssLogic.FILTER.UA :
|
||||
CssLogic.FILTER.USER;
|
||||
},
|
||||
|
||||
_onSourcePrefChanged: function CssComputedView__onSourcePrefChanged()
|
||||
{
|
||||
_onSourcePrefChanged: function() {
|
||||
for (let propView of this.propertyViews) {
|
||||
propView.updateSourceLinks();
|
||||
}
|
||||
@ -611,8 +603,7 @@ CssComputedView.prototype = {
|
||||
/**
|
||||
* The CSS as displayed by the UI.
|
||||
*/
|
||||
createStyleViews: function CssComputedView_createStyleViews()
|
||||
{
|
||||
createStyleViews: function() {
|
||||
if (CssComputedView.propertyNames) {
|
||||
return;
|
||||
}
|
||||
@ -641,8 +632,8 @@ CssComputedView.prototype = {
|
||||
|
||||
this._createPropertyViews().then(null, e => {
|
||||
if (!this._isDestroyed) {
|
||||
console.warn("The creation of property views was cancelled because the " +
|
||||
"computed-view was destroyed before it was done creating views");
|
||||
console.warn("The creation of property views was cancelled because " +
|
||||
"the computed-view was destroyed before it was done creating views");
|
||||
} else {
|
||||
console.error(e);
|
||||
}
|
||||
@ -654,18 +645,16 @@ CssComputedView.prototype = {
|
||||
*
|
||||
* @return {Set} If a property name is in the set, it has matching selectors.
|
||||
*/
|
||||
get matchedProperties()
|
||||
{
|
||||
return this._matchedProperties || new Set;
|
||||
get matchedProperties() {
|
||||
return this._matchedProperties || new Set();
|
||||
},
|
||||
|
||||
/**
|
||||
* Focus the window on mousedown.
|
||||
*
|
||||
* @param aEvent The event object
|
||||
* @param event The event object
|
||||
*/
|
||||
focusWindow: function(aEvent)
|
||||
{
|
||||
focusWindow: function(event) {
|
||||
let win = this.styleDocument.defaultView;
|
||||
win.focus();
|
||||
},
|
||||
@ -707,8 +696,8 @@ CssComputedView.prototype = {
|
||||
let win = this.styleDocument.defaultView;
|
||||
let text = win.getSelection().toString().trim();
|
||||
|
||||
// Tidy up block headings by moving CSS property names and their values onto
|
||||
// the same line and inserting a colon between them.
|
||||
// Tidy up block headings by moving CSS property names and their
|
||||
// values onto the same line and inserting a colon between them.
|
||||
let textArray = text.split(/[\r\n]+/);
|
||||
let result = "";
|
||||
|
||||
@ -737,8 +726,7 @@ CssComputedView.prototype = {
|
||||
/**
|
||||
* Destructor for CssComputedView.
|
||||
*/
|
||||
destroy: function CssComputedView_destroy()
|
||||
{
|
||||
destroy: function() {
|
||||
this.viewedElement = null;
|
||||
this._outputParser = null;
|
||||
|
||||
@ -819,8 +807,7 @@ PropertyInfo.prototype = {
|
||||
* @param {string} aName the CSS property name for which this PropertyView
|
||||
* instance will render the rules.
|
||||
*/
|
||||
function PropertyView(aTree, aName)
|
||||
{
|
||||
function PropertyView(aTree, aName) {
|
||||
this.tree = aTree;
|
||||
this.name = aName;
|
||||
this.getRTLAttr = aTree.getRTLAttr;
|
||||
@ -864,32 +851,28 @@ PropertyView.prototype = {
|
||||
* @return {string} the computed style for the current property of the
|
||||
* currently highlighted element.
|
||||
*/
|
||||
get value()
|
||||
{
|
||||
get value() {
|
||||
return this.propertyInfo.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* An easy way to access the CssPropertyInfo behind this PropertyView.
|
||||
*/
|
||||
get propertyInfo()
|
||||
{
|
||||
get propertyInfo() {
|
||||
return this._propertyInfo;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the property have any matched selectors?
|
||||
*/
|
||||
get hasMatchedSelectors()
|
||||
{
|
||||
get hasMatchedSelectors() {
|
||||
return this.tree.matchedProperties.has(this.name);
|
||||
},
|
||||
|
||||
/**
|
||||
* Should this property be visible?
|
||||
*/
|
||||
get visible()
|
||||
{
|
||||
get visible() {
|
||||
if (!this.tree.viewedElement) {
|
||||
return false;
|
||||
}
|
||||
@ -913,8 +896,7 @@ PropertyView.prototype = {
|
||||
* Returns the className that should be assigned to the propertyView.
|
||||
* @return string
|
||||
*/
|
||||
get propertyHeaderClassName()
|
||||
{
|
||||
get propertyHeaderClassName() {
|
||||
if (this.visible) {
|
||||
let isDark = this.tree._darkStripe = !this.tree._darkStripe;
|
||||
return isDark ? "property-view row-striped" : "property-view";
|
||||
@ -927,8 +909,7 @@ PropertyView.prototype = {
|
||||
* container.
|
||||
* @return string
|
||||
*/
|
||||
get propertyContentClassName()
|
||||
{
|
||||
get propertyContentClassName() {
|
||||
if (this.visible) {
|
||||
let isDark = this.tree._darkStripe;
|
||||
return isDark ? "property-content row-striped" : "property-content";
|
||||
@ -940,8 +921,7 @@ PropertyView.prototype = {
|
||||
* Build the markup for on computed style
|
||||
* @return Element
|
||||
*/
|
||||
buildMain: function PropertyView_buildMain()
|
||||
{
|
||||
buildMain: function() {
|
||||
let doc = this.tree.styleDocument;
|
||||
|
||||
// Build the container element
|
||||
@ -998,8 +978,7 @@ PropertyView.prototype = {
|
||||
return this.element;
|
||||
},
|
||||
|
||||
buildSelectorContainer: function PropertyView_buildSelectorContainer()
|
||||
{
|
||||
buildSelectorContainer: function() {
|
||||
let doc = this.tree.styleDocument;
|
||||
let element = doc.createElementNS(HTML_NS, "div");
|
||||
element.setAttribute("class", this.propertyContentClassName);
|
||||
@ -1013,8 +992,7 @@ PropertyView.prototype = {
|
||||
/**
|
||||
* Refresh the panel's CSS property value.
|
||||
*/
|
||||
refresh: function PropertyView_refresh()
|
||||
{
|
||||
refresh: function() {
|
||||
this.element.className = this.propertyHeaderClassName;
|
||||
this.element.nextElementSibling.className = this.propertyContentClassName;
|
||||
|
||||
@ -1051,8 +1029,7 @@ PropertyView.prototype = {
|
||||
/**
|
||||
* Refresh the panel matched rules.
|
||||
*/
|
||||
refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors()
|
||||
{
|
||||
refreshMatchedSelectors: function() {
|
||||
let hasMatchedSelectors = this.hasMatchedSelectors;
|
||||
this.matchedSelectorsContainer.parentNode.hidden = !hasMatchedSelectors;
|
||||
|
||||
@ -1063,28 +1040,29 @@ PropertyView.prototype = {
|
||||
}
|
||||
|
||||
if (this.matchedExpanded && hasMatchedSelectors) {
|
||||
return this.tree.pageStyle.getMatchedSelectors(this.tree.viewedElement, this.name).then(matched => {
|
||||
if (!this.matchedExpanded) {
|
||||
return;
|
||||
}
|
||||
return this.tree.pageStyle
|
||||
.getMatchedSelectors(this.tree.viewedElement, this.name)
|
||||
.then(matched => {
|
||||
if (!this.matchedExpanded) {
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
this._matchedSelectorResponse = matched;
|
||||
this._matchedSelectorResponse = matched;
|
||||
|
||||
return this._buildMatchedSelectors().then(() => {
|
||||
this.matchedExpander.setAttribute("open", "");
|
||||
this.tree.inspector.emit("computed-view-property-expanded");
|
||||
});
|
||||
}).then(null, console.error);
|
||||
} else {
|
||||
this.matchedSelectorsContainer.innerHTML = "";
|
||||
this.matchedExpander.removeAttribute("open");
|
||||
this.tree.inspector.emit("computed-view-property-collapsed");
|
||||
return promise.resolve(undefined);
|
||||
return this._buildMatchedSelectors().then(() => {
|
||||
this.matchedExpander.setAttribute("open", "");
|
||||
this.tree.inspector.emit("computed-view-property-expanded");
|
||||
});
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
this.matchedSelectorsContainer.innerHTML = "";
|
||||
this.matchedExpander.removeAttribute("open");
|
||||
this.tree.inspector.emit("computed-view-property-collapsed");
|
||||
return promise.resolve(undefined);
|
||||
},
|
||||
|
||||
get matchedSelectors()
|
||||
{
|
||||
get matchedSelectors() {
|
||||
return this._matchedSelectorResponse;
|
||||
},
|
||||
|
||||
@ -1130,13 +1108,13 @@ PropertyView.prototype = {
|
||||
* Provide access to the matched SelectorViews that we are currently
|
||||
* displaying.
|
||||
*/
|
||||
get matchedSelectorViews()
|
||||
{
|
||||
get matchedSelectorViews() {
|
||||
if (!this._matchedSelectorViews) {
|
||||
this._matchedSelectorViews = [];
|
||||
this._matchedSelectorResponse.forEach(
|
||||
function matchedSelectorViews_convert(aSelectorInfo) {
|
||||
this._matchedSelectorViews.push(new SelectorView(this.tree, aSelectorInfo));
|
||||
function(aSelectorInfo) {
|
||||
let selectorView = new SelectorView(this.tree, aSelectorInfo);
|
||||
this._matchedSelectorViews.push(selectorView);
|
||||
}, this);
|
||||
}
|
||||
return this._matchedSelectorViews;
|
||||
@ -1146,8 +1124,7 @@ PropertyView.prototype = {
|
||||
* Update all the selector source links to reflect whether we're linking to
|
||||
* original sources (e.g. Sass files).
|
||||
*/
|
||||
updateSourceLinks: function PropertyView_updateSourceLinks()
|
||||
{
|
||||
updateSourceLinks: function() {
|
||||
if (!this._matchedSelectorViews) {
|
||||
return;
|
||||
}
|
||||
@ -1162,8 +1139,7 @@ PropertyView.prototype = {
|
||||
* @param {Event} aEvent Used to determine the class name of the targets click
|
||||
* event.
|
||||
*/
|
||||
onMatchedToggle: function PropertyView_onMatchedToggle(aEvent)
|
||||
{
|
||||
onMatchedToggle: function(aEvent) {
|
||||
if (aEvent.shiftKey) {
|
||||
return;
|
||||
}
|
||||
@ -1175,8 +1151,7 @@ PropertyView.prototype = {
|
||||
/**
|
||||
* The action when a user clicks on the MDN help link for a property.
|
||||
*/
|
||||
mdnLinkClick: function PropertyView_mdnLinkClick(aEvent)
|
||||
{
|
||||
mdnLinkClick: function(aEvent) {
|
||||
let inspector = this.tree.inspector;
|
||||
|
||||
if (inspector.target.tab) {
|
||||
@ -1189,7 +1164,7 @@ PropertyView.prototype = {
|
||||
/**
|
||||
* Destroy this property view, removing event listeners
|
||||
*/
|
||||
destroy: function PropertyView_destroy() {
|
||||
destroy: function() {
|
||||
this.element.removeEventListener("dblclick", this.onMatchedToggle, false);
|
||||
this.element.removeEventListener("keydown", this.onKeyDown, false);
|
||||
this.element = null;
|
||||
@ -1210,8 +1185,7 @@ PropertyView.prototype = {
|
||||
* @param CssComputedView aTree, the owning CssComputedView
|
||||
* @param aSelectorInfo
|
||||
*/
|
||||
function SelectorView(aTree, aSelectorInfo)
|
||||
{
|
||||
function SelectorView(aTree, aSelectorInfo) {
|
||||
this.tree = aTree;
|
||||
this.selectorInfo = aSelectorInfo;
|
||||
this._cacheStatusNames();
|
||||
@ -1245,8 +1219,7 @@ SelectorView.prototype = {
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
_cacheStatusNames: function SelectorView_cacheStatusNames()
|
||||
{
|
||||
_cacheStatusNames: function() {
|
||||
if (SelectorView.STATUS_NAMES.length) {
|
||||
return;
|
||||
}
|
||||
@ -1256,7 +1229,7 @@ SelectorView.prototype = {
|
||||
if (i > CssLogic.STATUS.UNMATCHED) {
|
||||
let value = CssComputedView.l10n("rule.status." + status);
|
||||
// Replace normal spaces with non-breaking spaces
|
||||
SelectorView.STATUS_NAMES[i] = value.replace(/ /g, '\u00A0');
|
||||
SelectorView.STATUS_NAMES[i] = value.replace(/ /g, "\u00A0");
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1264,21 +1237,18 @@ SelectorView.prototype = {
|
||||
/**
|
||||
* A localized version of cssRule.status
|
||||
*/
|
||||
get statusText()
|
||||
{
|
||||
get statusText() {
|
||||
return SelectorView.STATUS_NAMES[this.selectorInfo.status];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get class name for selector depending on status
|
||||
*/
|
||||
get statusClass()
|
||||
{
|
||||
get statusClass() {
|
||||
return SelectorView.CLASS_NAMES[this.selectorInfo.status - 1];
|
||||
},
|
||||
|
||||
get href()
|
||||
{
|
||||
get href() {
|
||||
if (this._href) {
|
||||
return this._href;
|
||||
}
|
||||
@ -1287,19 +1257,15 @@ SelectorView.prototype = {
|
||||
return this._href;
|
||||
},
|
||||
|
||||
get sourceText()
|
||||
{
|
||||
get sourceText() {
|
||||
return this.selectorInfo.sourceText;
|
||||
},
|
||||
|
||||
|
||||
get value()
|
||||
{
|
||||
get value() {
|
||||
return this.selectorInfo.value;
|
||||
},
|
||||
|
||||
get outputFragment()
|
||||
{
|
||||
get outputFragment() {
|
||||
// Sadly, because this fragment is added to the template by DOM Templater
|
||||
// we lose any events that are attached. This means that URLs will open in a
|
||||
// new window. At some point we should fix this by stopping using the
|
||||
@ -1320,8 +1286,7 @@ SelectorView.prototype = {
|
||||
* Update the text of the source link to reflect whether we're showing
|
||||
* original sources or not.
|
||||
*/
|
||||
updateSourceLink: function()
|
||||
{
|
||||
updateSourceLink: function() {
|
||||
return this.updateSource().then((oldSource) => {
|
||||
if (oldSource != this.source && this.tree.element) {
|
||||
let selector = '[sourcelocation="' + oldSource + '"]';
|
||||
@ -1337,8 +1302,7 @@ SelectorView.prototype = {
|
||||
/**
|
||||
* Update the 'source' store based on our original sources preference.
|
||||
*/
|
||||
updateSource: function()
|
||||
{
|
||||
updateSource: function() {
|
||||
let rule = this.selectorInfo.rule;
|
||||
this.sheet = rule.parentStyleSheet;
|
||||
|
||||
@ -1373,8 +1337,7 @@ SelectorView.prototype = {
|
||||
/**
|
||||
* Open the style editor if the RETURN key was pressed.
|
||||
*/
|
||||
maybeOpenStyleEditor: function(aEvent)
|
||||
{
|
||||
maybeOpenStyleEditor: function(aEvent) {
|
||||
let keyEvent = Ci.nsIDOMKeyEvent;
|
||||
if (aEvent.keyCode == keyEvent.DOM_VK_RETURN) {
|
||||
this.openStyleEditor();
|
||||
@ -1391,8 +1354,7 @@ SelectorView.prototype = {
|
||||
*
|
||||
* @param aEvent The click event
|
||||
*/
|
||||
openStyleEditor: function(aEvent)
|
||||
{
|
||||
openStyleEditor: function(aEvent) {
|
||||
let inspector = this.tree.inspector;
|
||||
let rule = this.selectorInfo.rule;
|
||||
|
||||
@ -1401,15 +1363,8 @@ SelectorView.prototype = {
|
||||
//
|
||||
// If the stylesheet is a content stylesheet we send it to the style
|
||||
// editor else we display it in the view source window.
|
||||
let sheet = rule.parentStyleSheet;
|
||||
if (!sheet || sheet.isSystem) {
|
||||
let contentDoc = null;
|
||||
if (this.tree.viewedElement.isLocal_toBeDeprecated()) {
|
||||
let rawNode = this.tree.viewedElement.rawNode();
|
||||
if (rawNode) {
|
||||
contentDoc = rawNode.ownerDocument;
|
||||
}
|
||||
}
|
||||
let parentStyleSheet = rule.parentStyleSheet;
|
||||
if (!parentStyleSheet || parentStyleSheet.isSystem) {
|
||||
let toolbox = gDevTools.getToolbox(inspector.target);
|
||||
toolbox.viewSource(rule.href, rule.line);
|
||||
return;
|
||||
@ -1447,7 +1402,7 @@ function createChild(aParent, aTag, aAttributes={}) {
|
||||
if (aAttributes.hasOwnProperty(attr)) {
|
||||
if (attr === "textContent") {
|
||||
elt.textContent = aAttributes[attr];
|
||||
} else if(attr === "child") {
|
||||
} else if (attr === "child") {
|
||||
elt.appendChild(aAttributes[attr]);
|
||||
} else {
|
||||
elt.setAttribute(attr, aAttributes[attr]);
|
||||
|
@ -5,7 +5,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* globals overlays, Services, EventEmitter, StyleInspectorMenu,
|
||||
clipboardHelper, _strings, domUtils, AutocompletePopup */
|
||||
clipboardHelper, _strings, domUtils, AutocompletePopup, loader,
|
||||
osString */
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -209,7 +210,7 @@ ElementStyle.prototype = {
|
||||
filter: this.showUserAgentStyles ? "ua" : undefined,
|
||||
}).then(entries => {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Make sure the dummy element has been created before continuing...
|
||||
@ -236,14 +237,12 @@ ElementStyle.prototype = {
|
||||
|
||||
// We're done with the previous list of rules.
|
||||
delete this._refreshRules;
|
||||
|
||||
return null;
|
||||
});
|
||||
}).then(null, e => {
|
||||
// populate is often called after a setTimeout,
|
||||
// the connection may already be closed.
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
return promiseWarn(e);
|
||||
});
|
||||
@ -636,7 +635,7 @@ Rule.prototype = {
|
||||
disabled.delete(this.style);
|
||||
}
|
||||
|
||||
let promise = aModifications.apply().then(() => {
|
||||
let modificationsPromise = aModifications.apply().then(() => {
|
||||
let cssProps = {};
|
||||
for (let cssProp of parseDeclarations(this.style.cssText)) {
|
||||
cssProps[cssProp.name] = cssProp;
|
||||
@ -668,8 +667,8 @@ Rule.prototype = {
|
||||
this.elementStyle._changed();
|
||||
}).then(null, promiseWarn);
|
||||
|
||||
this._applyingModifications = promise;
|
||||
return promise;
|
||||
this._applyingModifications = modificationsPromise;
|
||||
return modificationsPromise;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1111,7 +1110,8 @@ TextProperty.prototype = {
|
||||
*/
|
||||
stringifyProperty: function() {
|
||||
// Get the displayed property value
|
||||
let declaration = this.name + ": " + this.editor.committed.value + ";";
|
||||
let declaration = this.name + ": " + this.editor.valueSpan.textContent +
|
||||
";";
|
||||
|
||||
// Comment out property declarations that are not enabled
|
||||
if (!this.enabled) {
|
||||
@ -1741,7 +1741,7 @@ CssRuleView.prototype = {
|
||||
refreshPanel: function() {
|
||||
// Ignore refreshes during editing or when no element is selected.
|
||||
if (this.isEditing || !this._elementStyle) {
|
||||
return;
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Repopulate the element style once the current modifications are done.
|
||||
@ -1893,9 +1893,10 @@ CssRuleView.prototype = {
|
||||
|
||||
/**
|
||||
* Creates an expandable container in the rule view
|
||||
* @param {String} aLabel The label for the container header
|
||||
* @param {Boolean} isPseudo Whether or not the container will hold
|
||||
* pseudo element rules
|
||||
* @param {String} aLabel
|
||||
* The label for the container header
|
||||
* @param {Boolean} isPseudo
|
||||
* Whether or not the container will hold pseudo element rules
|
||||
* @return {DOMNode} The container element
|
||||
*/
|
||||
createExpandableContainer: function(aLabel, isPseudo = false) {
|
||||
@ -1915,44 +1916,59 @@ CssRuleView.prototype = {
|
||||
container.classList.add("ruleview-expandable-container");
|
||||
this.element.appendChild(container);
|
||||
|
||||
let toggleContainerVisibility = (isPseudo, showPseudo) => {
|
||||
let isOpen = twisty.getAttribute("open");
|
||||
|
||||
if (isPseudo) {
|
||||
this._showPseudoElements = !!showPseudo;
|
||||
|
||||
Services.prefs.setBoolPref("devtools.inspector.show_pseudo_elements",
|
||||
this.showPseudoElements);
|
||||
|
||||
header.classList.toggle("show-expandable-container",
|
||||
this.showPseudoElements);
|
||||
|
||||
isOpen = !this.showPseudoElements;
|
||||
} else {
|
||||
header.classList.toggle("show-expandable-container");
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
twisty.removeAttribute("open");
|
||||
} else {
|
||||
twisty.setAttribute("open", "true");
|
||||
}
|
||||
};
|
||||
|
||||
header.addEventListener("dblclick", () => {
|
||||
toggleContainerVisibility(isPseudo, !this.showPseudoElements);
|
||||
this._toggleContainerVisibility(twisty, header, isPseudo,
|
||||
!this.showPseudoElements);
|
||||
}, false);
|
||||
|
||||
twisty.addEventListener("click", () => {
|
||||
toggleContainerVisibility(isPseudo, !this.showPseudoElements);
|
||||
this._toggleContainerVisibility(twisty, header, isPseudo,
|
||||
!this.showPseudoElements);
|
||||
}, false);
|
||||
|
||||
if (isPseudo) {
|
||||
toggleContainerVisibility(isPseudo, this.showPseudoElements);
|
||||
this._toggleContainerVisibility(twisty, header, isPseudo,
|
||||
this.showPseudoElements);
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle the visibility of an expandable container
|
||||
* @param {DOMNode} twisty
|
||||
* clickable toggle DOM Node
|
||||
* @param {DOMNode} header
|
||||
* expandable container header DOM Node
|
||||
* @param {Boolean} isPseudo
|
||||
* whether or not the container will hold pseudo element rules
|
||||
* @param {Boolean} showPseudo
|
||||
* whether or not pseudo element rules should be displayed
|
||||
*/
|
||||
_toggleContainerVisibility: function(twisty, header, isPseudo, showPseudo) {
|
||||
let isOpen = twisty.getAttribute("open");
|
||||
|
||||
if (isPseudo) {
|
||||
this._showPseudoElements = !!showPseudo;
|
||||
|
||||
Services.prefs.setBoolPref("devtools.inspector.show_pseudo_elements",
|
||||
this.showPseudoElements);
|
||||
|
||||
header.classList.toggle("show-expandable-container",
|
||||
this.showPseudoElements);
|
||||
|
||||
isOpen = !this.showPseudoElements;
|
||||
} else {
|
||||
header.classList.toggle("show-expandable-container");
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
twisty.removeAttribute("open");
|
||||
} else {
|
||||
twisty.setAttribute("open", "true");
|
||||
}
|
||||
},
|
||||
|
||||
_getRuleViewHeaderClassName: function(isPseudo) {
|
||||
let baseClassName = "theme-gutter ruleview-header";
|
||||
return isPseudo ? baseClassName + " ruleview-expandable-header" :
|
||||
|
@ -231,6 +231,7 @@ StyleInspectorMenu.prototype = {
|
||||
this.menuitemCopy.hidden = !this._hasTextSelected();
|
||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrl();
|
||||
this.menuitemCopyUrl.hidden = !this._isImageUrl();
|
||||
|
||||
this.menuitemCopyRule.hidden = true;
|
||||
this.menuitemCopyLocation.hidden = true;
|
||||
@ -378,6 +379,10 @@ StyleInspectorMenu.prototype = {
|
||||
* Retrieve the url for the selected image and copy it to the clipboard
|
||||
*/
|
||||
_onCopyUrl: function() {
|
||||
if (!this._clickedNodeInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(this._clickedNodeInfo.value.url);
|
||||
},
|
||||
|
||||
|
@ -52,6 +52,20 @@ add_task(function*() {
|
||||
copyRule: false
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test Copy Property Value with Priority",
|
||||
node: ruleEditor.rule.textProps[3].editor.valueSpan,
|
||||
menuItem: contextmenu.menuitemCopyPropertyValue,
|
||||
expectedPattern: "#00F !important",
|
||||
hidden: {
|
||||
copyLocation: true,
|
||||
copyPropertyDeclaration: false,
|
||||
copyPropertyName: true,
|
||||
copyPropertyValue: false,
|
||||
copySelector: true,
|
||||
copyRule: false
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test Copy Property Declaration",
|
||||
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
||||
@ -66,6 +80,20 @@ add_task(function*() {
|
||||
copyRule: false
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test Copy Property Declaration with Priority",
|
||||
node: ruleEditor.rule.textProps[3].editor.nameSpan,
|
||||
menuItem: contextmenu.menuitemCopyPropertyDeclaration,
|
||||
expectedPattern: "border-color: #00F !important;",
|
||||
hidden: {
|
||||
copyLocation: true,
|
||||
copyPropertyDeclaration: false,
|
||||
copyPropertyName: false,
|
||||
copyPropertyValue: true,
|
||||
copySelector: true,
|
||||
copyRule: false
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test Copy Rule",
|
||||
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
||||
@ -74,6 +102,7 @@ add_task(function*() {
|
||||
"\tcolor: #F00;[\\r\\n]+" +
|
||||
"\tbackground-color: #00F;[\\r\\n]+" +
|
||||
"\tfont-size: 12px;[\\r\\n]+" +
|
||||
"\tborder-color: #00F !important;[\\r\\n]+" +
|
||||
"}",
|
||||
hidden: {
|
||||
copyLocation: true,
|
||||
@ -124,6 +153,7 @@ add_task(function*() {
|
||||
"\t\/\\* color: #F00; \\*\/[\\r\\n]+" +
|
||||
"\tbackground-color: #00F;[\\r\\n]+" +
|
||||
"\tfont-size: 12px;[\\r\\n]+" +
|
||||
"\tborder-color: #00F !important;[\\r\\n]+" +
|
||||
"}",
|
||||
hidden: {
|
||||
copyLocation: true,
|
||||
|
@ -80,6 +80,7 @@ function* testCopyUrlToClipboard({view, inspector}, type, selector, expected) {
|
||||
yield popup;
|
||||
|
||||
info("Context menu is displayed");
|
||||
ok(!view._contextmenu.menuitemCopyUrl.hidden, "\"Copy URL\" menu entry is displayed");
|
||||
ok(!view._contextmenu.menuitemCopyImageDataUrl.hidden, "\"Copy Image Data-URL\" menu entry is displayed");
|
||||
|
||||
if (type == "data-uri") {
|
||||
|
@ -6,4 +6,5 @@ html, body, #testid {
|
||||
color: #F00;
|
||||
background-color: #00F;
|
||||
font-size: 12px;
|
||||
border-color: #00F !important;
|
||||
}
|
||||
|
@ -558,6 +558,7 @@
|
||||
@RESPATH@/components/AlarmsManager.manifest
|
||||
@RESPATH@/components/Push.js
|
||||
@RESPATH@/components/Push.manifest
|
||||
@RESPATH@/components/PushClient.js
|
||||
@RESPATH@/components/PushNotificationService.js
|
||||
|
||||
@RESPATH@/components/SlowScriptDebug.manifest
|
||||
@ -637,6 +638,7 @@
|
||||
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
||||
@RESPATH@/components/nsUrlClassifierListManager.js
|
||||
@RESPATH@/components/nsUrlClassifierLib.js
|
||||
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||
@RESPATH@/components/url-classifier.xpt
|
||||
#endif
|
||||
|
||||
|
@ -97,6 +97,9 @@ quit-button.tooltiptext.mac = Quit %1$S (%2$S)
|
||||
# approval before you change it.
|
||||
loop-call-button3.label = Hello
|
||||
loop-call-button3.tooltiptext = Start a conversation
|
||||
# LOCALIZATION NOTE(loop-call-button3-pb.tooltiptext): Shown when the button is
|
||||
# placed inside a Private Browsing window. %S is the value of loop-call-button3.label.
|
||||
loop-call-button3-pb.tooltiptext = %S is not available in Private Browsing
|
||||
|
||||
social-share-button.label = Share This Page
|
||||
social-share-button.tooltiptext = Share this page
|
||||
|
@ -206,6 +206,8 @@ active_screenshare_button_title=Stop sharing
|
||||
inactive_screenshare_button_title=Share your screen
|
||||
share_tabs_button_title2=Share your Tabs
|
||||
share_windows_button_title=Share other Windows
|
||||
self_view_hidden_message=Self-view hidden but still being sent; resize window to show
|
||||
|
||||
|
||||
## LOCALIZATION NOTE (call_with_contact_title): The title displayed
|
||||
## when calling a contact. Don't translate the part between {{..}} because
|
||||
|
@ -115,7 +115,7 @@
|
||||
.titlebar-button {
|
||||
border: none;
|
||||
margin: 0 !important;
|
||||
padding: 12px 17px;
|
||||
padding: 10px 17px;
|
||||
}
|
||||
|
||||
#main-window[sizemode=maximized] .titlebar-button {
|
||||
@ -147,6 +147,20 @@
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
|
||||
}
|
||||
|
||||
#titlebar-min:-moz-lwtheme {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-themes);
|
||||
}
|
||||
#titlebar-max:-moz-lwtheme {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize-themes);
|
||||
}
|
||||
#main-window[sizemode="maximized"] #titlebar-max:-moz-lwtheme {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-themes);
|
||||
}
|
||||
#titlebar-close:-moz-lwtheme {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-themes);
|
||||
}
|
||||
|
||||
|
||||
/* the 12px image renders a 10px icon, and the 10px upscaled gets rounded to 12.5, which
|
||||
* rounds up to 13px, which makes the icon one pixel too big on 1.25dppx. Fix: */
|
||||
@media (min-resolution: 1.20dppx) and (max-resolution: 1.45dppx) {
|
||||
@ -222,20 +236,32 @@
|
||||
background-color: Highlight;
|
||||
}
|
||||
|
||||
#titlebar-min {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-highcontrast);
|
||||
}
|
||||
#titlebar-min:hover {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-highlight);
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-highcontrast-hover);
|
||||
}
|
||||
|
||||
#titlebar-max {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize-highcontrast);
|
||||
}
|
||||
#titlebar-max:hover {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize-highlight);
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize-highcontrast-hover);
|
||||
}
|
||||
|
||||
#main-window[sizemode="maximized"] #titlebar-max {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-highcontrast);
|
||||
}
|
||||
#main-window[sizemode="maximized"] #titlebar-max:hover {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-highlight);
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-highcontrast-hover);
|
||||
}
|
||||
|
||||
#titlebar-close {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-highcontrast);
|
||||
}
|
||||
#titlebar-close:hover {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-highlight);
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-highcontrast-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -659,7 +659,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-padding-end: 5px;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1[type=panel]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button),
|
||||
#nav-bar .toolbarbutton-1[type=panel],
|
||||
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
@ -771,8 +771,8 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1[type=panel]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1[type=panel]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1[type=panel] > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1[type=panel] > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
|
||||
@ -1203,6 +1203,11 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
-moz-padding-end: 2px;
|
||||
}
|
||||
|
||||
/* overlap the urlbar's border */
|
||||
#PopupAutoCompleteRichResult {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
@ -1246,6 +1251,11 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
.searchbar-textbox:not(:-moz-lwtheme)[focused] {
|
||||
box-shadow: 0 0 0 1px Highlight inset;
|
||||
}
|
||||
|
||||
/* overlap the urlbar's border and inset box-shadow */
|
||||
#PopupAutoCompleteRichResult:not(:-moz-lwtheme) {
|
||||
margin-top: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
|
@ -9,7 +9,7 @@
|
||||
fill: none;
|
||||
}
|
||||
|
||||
g:not(#close) {
|
||||
g:not([id|="close"]) {
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
@ -21,17 +21,36 @@
|
||||
display: initial;
|
||||
}
|
||||
|
||||
[id$="-highlight"] > g {
|
||||
g.highlight {
|
||||
stroke-width: 1.9px;
|
||||
}
|
||||
|
||||
g.themes {
|
||||
stroke: #fff;
|
||||
stroke-width: 1.9px;
|
||||
}
|
||||
|
||||
.outer-stroke {
|
||||
stroke: #000;
|
||||
stroke-width: 3.6;
|
||||
opacity: .75;
|
||||
}
|
||||
|
||||
.restore-background-window {
|
||||
stroke-width: .9;
|
||||
}
|
||||
|
||||
[id$="-highcontrast-hover"] > g {
|
||||
stroke: HighlightText;
|
||||
}
|
||||
|
||||
[id$="-white"] > g {
|
||||
stroke: #fff;
|
||||
}
|
||||
|
||||
</style>
|
||||
<g id="close">
|
||||
<line x1="1" y1="1" x2="11" y2="11"/>
|
||||
<line x1="11" y1="1" x2="1" y2="11"/>
|
||||
<path d="M1,1 l 10,10 M1,11 l 10,-10"/>
|
||||
</g>
|
||||
<g id="maximize">
|
||||
<rect x="1.5" y="1.5" width="9" height="9"/>
|
||||
@ -43,13 +62,46 @@
|
||||
<rect x="1.5" y="3.5" width="7" height="7"/>
|
||||
<polyline points="3.5,3.5 3.5,1.5 10.5,1.5 10.5,8.5 8.5,8.5"/>
|
||||
</g>
|
||||
<use id="close-highlight" xlink:href="#close"/>
|
||||
<use id="maximize-highlight" xlink:href="#maximize"/>
|
||||
<use id="minimize-highlight" xlink:href="#minimize"/>
|
||||
<use id="restore-highlight" xlink:href="#restore"/>
|
||||
|
||||
<use id="close-white" xlink:href="#close"/>
|
||||
<use id="maximize-white" xlink:href="#maximize"/>
|
||||
<use id="minimize-white" xlink:href="#minimize"/>
|
||||
<use id="restore-white" xlink:href="#restore"/>
|
||||
|
||||
<g id="close-highcontrast" class="highlight">
|
||||
<path d="M1,1 l 10,10 M1,11 l 10,-10"/>
|
||||
</g>
|
||||
<g id="maximize-highcontrast" class="highlight">
|
||||
<rect x="2" y="2" width="8" height="8"/>
|
||||
</g>
|
||||
<g id="minimize-highcontrast" class="highlight">
|
||||
<line x1="1" y1="6" x2="11" y2="6"/>
|
||||
</g>
|
||||
<g id="restore-highcontrast" class="highlight">
|
||||
<rect x="2" y="4" width="6" height="6"/>
|
||||
<polyline points="3.5,1.5 10.5,1.5 10.5,8.5" class="restore-background-window"/>
|
||||
</g>
|
||||
|
||||
<use id="close-highcontrast-hover" xlink:href="#close-highcontrast"/>
|
||||
<use id="maximize-highcontrast-hover" xlink:href="#maximize-highcontrast"/>
|
||||
<use id="minimize-highcontrast-hover" xlink:href="#minimize-highcontrast"/>
|
||||
<use id="restore-highcontrast-hover" xlink:href="#restore-highcontrast"/>
|
||||
|
||||
<g id="close-themes" class="themes">
|
||||
<path d="M1,1 l 10,10 M1,11 l 10,-10" class="outer-stroke" />
|
||||
<path d="M1.75,1.75 l 8.5,8.5 M1.75,10.25 l 8.5,-8.5"/>
|
||||
</g>
|
||||
<g id="maximize-themes" class="themes">
|
||||
<rect x="2" y="2" width="8" height="8" class="outer-stroke"/>
|
||||
<rect x="2" y="2" width="8" height="8"/>
|
||||
</g>
|
||||
<g id="minimize-themes" class="themes">
|
||||
<line x1="0" y1="6" x2="12" y2="6" class="outer-stroke"/>
|
||||
<line x1="1" y1="6" x2="11" y2="6"/>
|
||||
</g>
|
||||
<g id="restore-themes" class="themes">
|
||||
<path d="M2,4 l 6,0 l 0,6 l -6,0z M2.5,1.5 l 8,0 l 0,8" class="outer-stroke"/>
|
||||
<rect x="2" y="4" width="6" height="6"/>
|
||||
<polyline points="3.5,1.5 10.5,1.5 10.5,8.5" class="restore-background-window"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.0 KiB |
@ -1,6 +1,7 @@
|
||||
/* 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 "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
@ -56,7 +57,6 @@ private:
|
||||
ScopeChecker(Scope scope_) :
|
||||
scope(scope_) {}
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
void noteInferred(QualType T, DiagnosticsEngine &Diag);
|
||||
private:
|
||||
Scope scope;
|
||||
};
|
||||
@ -64,7 +64,6 @@ private:
|
||||
class NonHeapClassChecker : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
void noteInferred(QualType T, DiagnosticsEngine &Diag);
|
||||
};
|
||||
|
||||
class ArithmeticArgChecker : public MatchFinder::MatchCallback {
|
||||
@ -97,6 +96,16 @@ private:
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
};
|
||||
|
||||
class NeedsNoVTableTypeChecker : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
};
|
||||
|
||||
class NonMemMovableChecker : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
};
|
||||
|
||||
ScopeChecker stackClassChecker;
|
||||
ScopeChecker globalClassChecker;
|
||||
NonHeapClassChecker nonheapClassChecker;
|
||||
@ -106,6 +115,8 @@ private:
|
||||
NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
|
||||
RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
|
||||
ExplicitOperatorBoolChecker explicitOperatorBoolChecker;
|
||||
NeedsNoVTableTypeChecker needsNoVTableTypeChecker;
|
||||
NonMemMovableChecker nonMemMovableChecker;
|
||||
MatchFinder astMatcher;
|
||||
};
|
||||
|
||||
@ -217,6 +228,51 @@ bool isInterestingDeclForImplicitConversion(const Decl *decl) {
|
||||
|
||||
}
|
||||
|
||||
class CustomTypeAnnotation {
|
||||
enum ReasonKind {
|
||||
RK_None,
|
||||
RK_Direct,
|
||||
RK_ArrayElement,
|
||||
RK_BaseClass,
|
||||
RK_Field,
|
||||
};
|
||||
struct AnnotationReason {
|
||||
QualType Type;
|
||||
ReasonKind Kind;
|
||||
const FieldDecl *Field;
|
||||
|
||||
bool valid() const { return Kind != RK_None; }
|
||||
};
|
||||
typedef DenseMap<void *, AnnotationReason> ReasonCache;
|
||||
|
||||
const char *Spelling;
|
||||
const char *Pretty;
|
||||
ReasonCache Cache;
|
||||
|
||||
public:
|
||||
CustomTypeAnnotation(const char *Spelling, const char *Pretty)
|
||||
: Spelling(Spelling), Pretty(Pretty) {};
|
||||
|
||||
// Checks if this custom annotation "effectively affects" the given type.
|
||||
bool hasEffectiveAnnotation(QualType T) {
|
||||
return directAnnotationReason(T).valid();
|
||||
}
|
||||
void dumpAnnotationReason(DiagnosticsEngine &Diag, QualType T, SourceLocation Loc);
|
||||
|
||||
private:
|
||||
bool hasLiteralAnnotation(QualType T) const;
|
||||
AnnotationReason directAnnotationReason(QualType T);
|
||||
};
|
||||
|
||||
static CustomTypeAnnotation StackClass =
|
||||
CustomTypeAnnotation("moz_stack_class", "stack");
|
||||
static CustomTypeAnnotation GlobalClass =
|
||||
CustomTypeAnnotation("moz_global_class", "global");
|
||||
static CustomTypeAnnotation NonHeapClass =
|
||||
CustomTypeAnnotation("moz_nonheap_class", "non-heap");
|
||||
static CustomTypeAnnotation MustUse =
|
||||
CustomTypeAnnotation("moz_must_use", "must-use");
|
||||
|
||||
class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
|
||||
DiagnosticsEngine &Diag;
|
||||
const CompilerInstance &CI;
|
||||
@ -232,29 +288,29 @@ public:
|
||||
TraverseDecl(ctx.getTranslationUnitDecl());
|
||||
}
|
||||
|
||||
static bool hasCustomAnnotation(const Decl *d, const char *spelling) {
|
||||
AnnotateAttr *attr = d->getAttr<AnnotateAttr>();
|
||||
if (!attr)
|
||||
return false;
|
||||
static bool hasCustomAnnotation(const Decl *D, const char *Spelling) {
|
||||
iterator_range<specific_attr_iterator<AnnotateAttr> > Attrs =
|
||||
D->specific_attrs<AnnotateAttr>();
|
||||
|
||||
return attr->getAnnotation() == spelling;
|
||||
for (AnnotateAttr *Attr : Attrs) {
|
||||
if (Attr->getAnnotation() == Spelling) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandleUnusedExprResult(const Stmt *stmt) {
|
||||
const Expr* E = dyn_cast_or_null<Expr>(stmt);
|
||||
if (E) {
|
||||
// XXX It would be nice if we could use getAsTagDecl,
|
||||
// but our version of clang is too old.
|
||||
// (getAsTagDecl would also cover enums etc.)
|
||||
QualType T = E->getType();
|
||||
CXXRecordDecl *decl = T->getAsCXXRecordDecl();
|
||||
if (decl) {
|
||||
decl = decl->getDefinition();
|
||||
if (decl && hasCustomAnnotation(decl, "moz_must_use")) {
|
||||
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "Unused MOZ_MUST_USE value of type %0");
|
||||
Diag.Report(E->getLocStart(), errorID) << T;
|
||||
}
|
||||
if (MustUse.hasEffectiveAnnotation(T)) {
|
||||
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "Unused value of must-use type %0");
|
||||
|
||||
Diag.Report(E->getLocStart(), errorID) << T;
|
||||
MustUse.dumpAnnotationReason(Diag, T, E->getLocStart());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -378,102 +434,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Where classes may be allocated. Regular classes can be allocated anywhere,
|
||||
* non-heap classes on the stack or as static variables, and stack classes only
|
||||
* on the stack. Note that stack classes subsumes non-heap classes.
|
||||
*/
|
||||
enum ClassAllocationNature {
|
||||
RegularClass = 0,
|
||||
NonHeapClass = 1,
|
||||
StackClass = 2,
|
||||
GlobalClass = 3
|
||||
};
|
||||
|
||||
/// A cached data of whether classes are stack classes, non-heap classes, or
|
||||
/// neither.
|
||||
DenseMap<const CXXRecordDecl *,
|
||||
std::pair<const Decl *, ClassAllocationNature> > inferredAllocCauses;
|
||||
|
||||
ClassAllocationNature getClassAttrs(QualType T);
|
||||
|
||||
ClassAllocationNature getClassAttrs(CXXRecordDecl *D) {
|
||||
// Normalize so that D points to the definition if it exists. If it doesn't,
|
||||
// then we can't allocate it anyways.
|
||||
if (!D->hasDefinition())
|
||||
return RegularClass;
|
||||
D = D->getDefinition();
|
||||
// Base class: anyone with this annotation is obviously a stack class
|
||||
if (MozChecker::hasCustomAnnotation(D, "moz_stack_class"))
|
||||
return StackClass;
|
||||
// Base class: anyone with this annotation is obviously a global class
|
||||
if (MozChecker::hasCustomAnnotation(D, "moz_global_class"))
|
||||
return GlobalClass;
|
||||
|
||||
// See if we cached the result.
|
||||
DenseMap<const CXXRecordDecl *,
|
||||
std::pair<const Decl *, ClassAllocationNature> >::iterator it =
|
||||
inferredAllocCauses.find(D);
|
||||
if (it != inferredAllocCauses.end()) {
|
||||
return it->second.second;
|
||||
}
|
||||
|
||||
// Continue looking, we might be a stack class yet. Even if we're a nonheap
|
||||
// class, it might be possible that we've inferred to be a stack class.
|
||||
ClassAllocationNature type = RegularClass;
|
||||
if (MozChecker::hasCustomAnnotation(D, "moz_nonheap_class")) {
|
||||
type = NonHeapClass;
|
||||
}
|
||||
inferredAllocCauses.insert(std::make_pair(D,
|
||||
std::make_pair((const Decl *)0, type)));
|
||||
|
||||
// Look through all base cases to figure out if the parent is a stack class or
|
||||
// a non-heap class. Since we might later infer to also be a stack class, keep
|
||||
// going.
|
||||
for (CXXRecordDecl::base_class_iterator base = D->bases_begin(),
|
||||
e = D->bases_end(); base != e; ++base) {
|
||||
ClassAllocationNature super = getClassAttrs(base->getType());
|
||||
if (super == StackClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(
|
||||
base->getType()->getAsCXXRecordDecl(), StackClass);
|
||||
return StackClass;
|
||||
} else if (super == GlobalClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(
|
||||
base->getType()->getAsCXXRecordDecl(), GlobalClass);
|
||||
return GlobalClass;
|
||||
} else if (super == NonHeapClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(
|
||||
base->getType()->getAsCXXRecordDecl(), NonHeapClass);
|
||||
type = NonHeapClass;
|
||||
}
|
||||
}
|
||||
|
||||
// Maybe it has a member which is a stack class.
|
||||
for (RecordDecl::field_iterator field = D->field_begin(), e = D->field_end();
|
||||
field != e; ++field) {
|
||||
ClassAllocationNature fieldType = getClassAttrs(field->getType());
|
||||
if (fieldType == StackClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(*field, StackClass);
|
||||
return StackClass;
|
||||
} else if (fieldType == GlobalClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(*field, GlobalClass);
|
||||
return GlobalClass;
|
||||
} else if (fieldType == NonHeapClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(*field, NonHeapClass);
|
||||
type = NonHeapClass;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ClassAllocationNature getClassAttrs(QualType T) {
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
return clazz ? getClassAttrs(clazz) : RegularClass;
|
||||
}
|
||||
|
||||
/// A cached data of whether classes are refcounted or not.
|
||||
typedef DenseMap<const CXXRecordDecl *,
|
||||
std::pair<const Decl *, bool> > RefCountedMap;
|
||||
@ -527,7 +487,88 @@ bool isClassRefCounted(QualType T) {
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
return clazz ? isClassRefCounted(clazz) : RegularClass;
|
||||
return clazz ? isClassRefCounted(clazz) : false;
|
||||
}
|
||||
|
||||
/// A cached data of whether classes are memmovable, and if not, what declaration
|
||||
/// makes them non-movable
|
||||
typedef DenseMap<const CXXRecordDecl *, const CXXRecordDecl *> InferredMovability;
|
||||
InferredMovability inferredMovability;
|
||||
|
||||
bool isClassNonMemMovable(QualType T);
|
||||
const CXXRecordDecl* isClassNonMemMovableWorker(QualType T);
|
||||
|
||||
const CXXRecordDecl* isClassNonMemMovableWorker(const CXXRecordDecl *D) {
|
||||
// If we have a definition, then we want to standardize our reference to point
|
||||
// to the definition node. If we don't have a definition, that means that either
|
||||
// we only have a forward declaration of the type in our file, or we are being
|
||||
// passed a template argument which is not used, and thus never instantiated by
|
||||
// clang.
|
||||
// As the argument isn't used, we can't memmove it (as we don't know it's size),
|
||||
// which means not reporting an error is OK.
|
||||
if (!D->hasDefinition()) {
|
||||
return 0;
|
||||
}
|
||||
D = D->getDefinition();
|
||||
|
||||
// Are we explicitly marked as non-memmovable class?
|
||||
if (MozChecker::hasCustomAnnotation(D, "moz_non_memmovable")) {
|
||||
return D;
|
||||
}
|
||||
|
||||
// Look through all base cases to figure out if the parent is a non-memmovable class.
|
||||
for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin();
|
||||
base != D->bases_end(); ++base) {
|
||||
const CXXRecordDecl *result = isClassNonMemMovableWorker(base->getType());
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Look through all members to figure out if a member is a non-memmovable class.
|
||||
for (RecordDecl::field_iterator field = D->field_begin(), e = D->field_end();
|
||||
field != e; ++field) {
|
||||
const CXXRecordDecl *result = isClassNonMemMovableWorker(field->getType());
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const CXXRecordDecl* isClassNonMemMovableWorker(QualType T) {
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
const CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
return clazz ? isClassNonMemMovableWorker(clazz) : 0;
|
||||
}
|
||||
|
||||
bool isClassNonMemMovable(const CXXRecordDecl *D) {
|
||||
InferredMovability::iterator it =
|
||||
inferredMovability.find(D);
|
||||
if (it != inferredMovability.end())
|
||||
return !!it->second;
|
||||
const CXXRecordDecl *result = isClassNonMemMovableWorker(D);
|
||||
inferredMovability.insert(std::make_pair(D, result));
|
||||
return !!result;
|
||||
}
|
||||
|
||||
bool isClassNonMemMovable(QualType T) {
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
const CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
return clazz ? isClassNonMemMovable(clazz) : false;
|
||||
}
|
||||
|
||||
const CXXRecordDecl* findWhyClassIsNonMemMovable(QualType T) {
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
InferredMovability::iterator it =
|
||||
inferredMovability.find(clazz);
|
||||
assert(it != inferredMovability.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@ -540,6 +581,13 @@ bool IsInSystemHeader(const ASTContext &AC, const T &D) {
|
||||
return SourceManager.isInSystemHeader(ExpansionLoc);
|
||||
}
|
||||
|
||||
bool typeHasVTable(QualType T) {
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl* offender = T->getAsCXXRecordDecl();
|
||||
return offender && offender->hasDefinition() && offender->isDynamicClass();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -548,19 +596,19 @@ namespace ast_matchers {
|
||||
/// This matcher will match any class with the stack class assertion or an
|
||||
/// array of such classes.
|
||||
AST_MATCHER(QualType, stackClassAggregate) {
|
||||
return getClassAttrs(Node) == StackClass;
|
||||
return StackClass.hasEffectiveAnnotation(Node);
|
||||
}
|
||||
|
||||
/// This matcher will match any class with the global class assertion or an
|
||||
/// array of such classes.
|
||||
AST_MATCHER(QualType, globalClassAggregate) {
|
||||
return getClassAttrs(Node) == GlobalClass;
|
||||
return GlobalClass.hasEffectiveAnnotation(Node);
|
||||
}
|
||||
|
||||
/// This matcher will match any class with the stack class assertion or an
|
||||
/// array of such classes.
|
||||
AST_MATCHER(QualType, nonheapClassAggregate) {
|
||||
return getClassAttrs(Node) == NonHeapClass;
|
||||
return NonHeapClass.hasEffectiveAnnotation(Node);
|
||||
}
|
||||
|
||||
/// This matcher will match any function declaration that is declared as a heap
|
||||
@ -694,11 +742,126 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
|
||||
|
||||
#endif
|
||||
|
||||
AST_MATCHER(QualType, hasVTable) {
|
||||
return typeHasVTable(Node);
|
||||
}
|
||||
|
||||
AST_MATCHER(CXXRecordDecl, hasNeedsNoVTableTypeAttr) {
|
||||
return MozChecker::hasCustomAnnotation(&Node, "moz_needs_no_vtable_type");
|
||||
}
|
||||
|
||||
/// This matcher will select classes which are non-memmovable
|
||||
AST_MATCHER(QualType, isNonMemMovable) {
|
||||
return isClassNonMemMovable(Node);
|
||||
}
|
||||
|
||||
/// This matcher will select classes which require a memmovable template arg
|
||||
AST_MATCHER(CXXRecordDecl, needsMemMovable) {
|
||||
return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_type");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void CustomTypeAnnotation::dumpAnnotationReason(DiagnosticsEngine &Diag, QualType T, SourceLocation Loc) {
|
||||
unsigned InheritsID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "%1 is a %0 type because it inherits from a %0 type %2");
|
||||
unsigned MemberID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "%1 is a %0 type because member %2 is a %0 type %3");
|
||||
unsigned ArrayID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "%1 is a %0 type because it is an array of %0 type %2");
|
||||
unsigned TemplID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "%1 is a %0 type because it has a template argument %0 type %2");
|
||||
|
||||
AnnotationReason Reason = directAnnotationReason(T);
|
||||
for (;;) {
|
||||
switch (Reason.Kind) {
|
||||
case RK_ArrayElement:
|
||||
Diag.Report(Loc, ArrayID)
|
||||
<< Pretty << T << Reason.Type;
|
||||
break;
|
||||
case RK_BaseClass:
|
||||
{
|
||||
const CXXRecordDecl *Decl = T->getAsCXXRecordDecl();
|
||||
assert(Decl && "This type should be a C++ class");
|
||||
|
||||
Diag.Report(Decl->getLocation(), InheritsID)
|
||||
<< Pretty << T << Reason.Type;
|
||||
break;
|
||||
}
|
||||
case RK_Field:
|
||||
Diag.Report(Reason.Field->getLocation(), MemberID)
|
||||
<< Pretty << T << Reason.Field << Reason.Type;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
T = Reason.Type;
|
||||
Reason = directAnnotationReason(T);
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomTypeAnnotation::hasLiteralAnnotation(QualType T) const {
|
||||
if (const TagDecl *D = T->getAsTagDecl()) {
|
||||
return MozChecker::hasCustomAnnotation(D, Spelling);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomTypeAnnotation::AnnotationReason CustomTypeAnnotation::directAnnotationReason(QualType T) {
|
||||
if (hasLiteralAnnotation(T)) {
|
||||
AnnotationReason Reason = { T, RK_Direct, nullptr };
|
||||
return Reason;
|
||||
}
|
||||
|
||||
// Check if we have a cached answer
|
||||
void *Key = T.getAsOpaquePtr();
|
||||
ReasonCache::iterator Cached = Cache.find(T.getAsOpaquePtr());
|
||||
if (Cached != Cache.end()) {
|
||||
return Cached->second;
|
||||
}
|
||||
|
||||
// Check if we have a type which we can recurse into
|
||||
if (const ArrayType *Array = T->getAsArrayTypeUnsafe()) {
|
||||
if (hasEffectiveAnnotation(Array->getElementType())) {
|
||||
AnnotationReason Reason = { Array->getElementType(), RK_ArrayElement, nullptr };
|
||||
Cache[Key] = Reason;
|
||||
return Reason;
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into base classes
|
||||
if (const CXXRecordDecl *Decl = T->getAsCXXRecordDecl()) {
|
||||
if (Decl->hasDefinition()) {
|
||||
Decl = Decl->getDefinition();
|
||||
|
||||
for (const CXXBaseSpecifier &Base : Decl->bases()) {
|
||||
if (hasEffectiveAnnotation(Base.getType())) {
|
||||
AnnotationReason Reason = { Base.getType(), RK_BaseClass, nullptr };
|
||||
Cache[Key] = Reason;
|
||||
return Reason;
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into members
|
||||
for (const FieldDecl *Field : Decl->fields()) {
|
||||
if (hasEffectiveAnnotation(Field->getType())) {
|
||||
AnnotationReason Reason = { Field->getType(), RK_Field, Field };
|
||||
Cache[Key] = Reason;
|
||||
return Reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationReason Reason = { QualType(), RK_None, nullptr };
|
||||
Cache[Key] = Reason;
|
||||
return Reason;
|
||||
}
|
||||
|
||||
bool isPlacementNew(const CXXNewExpr *expr) {
|
||||
// Regular new expressions aren't placement new
|
||||
if (expr->getNumPlacementArgs() == 0)
|
||||
@ -816,6 +979,18 @@ DiagnosticsMatcher::DiagnosticsMatcher()
|
||||
astMatcher.addMatcher(methodDecl(anyOf(hasName("operator bool"),
|
||||
hasName("operator _Bool"))).bind("node"),
|
||||
&explicitOperatorBoolChecker);
|
||||
|
||||
astMatcher.addMatcher(classTemplateSpecializationDecl(
|
||||
allOf(hasAnyTemplateArgument(refersToType(hasVTable())),
|
||||
hasNeedsNoVTableTypeAttr())).bind("node"),
|
||||
&needsNoVTableTypeChecker);
|
||||
|
||||
// Handle non-mem-movable template specializations
|
||||
astMatcher.addMatcher(classTemplateSpecializationDecl(
|
||||
allOf(needsMemMovable(),
|
||||
hasAnyTemplateArgument(refersToType(isNonMemMovable())))
|
||||
).bind("specialization"),
|
||||
&nonMemMovableChecker);
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::ScopeChecker::run(
|
||||
@ -825,7 +1000,9 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
|
||||
unsigned globalID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "variable of type %0 only valid as global");
|
||||
unsigned errorID = (scope == eGlobal) ? globalID : stackID;
|
||||
|
||||
SourceLocation Loc;
|
||||
QualType T;
|
||||
if (const VarDecl *d = Result.Nodes.getNodeAs<VarDecl>("node")) {
|
||||
if (scope == eLocal) {
|
||||
// Ignore the match if it's a local variable.
|
||||
@ -840,56 +1017,29 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
return;
|
||||
}
|
||||
|
||||
Diag.Report(d->getLocation(), errorID) << d->getType();
|
||||
noteInferred(d->getType(), Diag);
|
||||
Loc = d->getLocation();
|
||||
T = d->getType();
|
||||
} else if (const CXXNewExpr *expr =
|
||||
Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
|
||||
// If it's placement new, then this match doesn't count.
|
||||
if (scope == eLocal && isPlacementNew(expr))
|
||||
return;
|
||||
Diag.Report(expr->getStartLoc(), errorID) << expr->getAllocatedType();
|
||||
noteInferred(expr->getAllocatedType(), Diag);
|
||||
|
||||
Loc = expr->getStartLoc();
|
||||
T = expr->getAllocatedType();
|
||||
} else if (const CallExpr *expr =
|
||||
Result.Nodes.getNodeAs<CallExpr>("node")) {
|
||||
QualType badType = GetCallReturnType(expr)->getPointeeType();
|
||||
Diag.Report(expr->getLocStart(), errorID) << badType;
|
||||
noteInferred(badType, Diag);
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::ScopeChecker::noteInferred(QualType T,
|
||||
DiagnosticsEngine &Diag) {
|
||||
unsigned inheritsID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note,
|
||||
"%0 is a %2 class because it inherits from a %2 class %1");
|
||||
unsigned memberID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note,
|
||||
"%0 is a %3 class because member %1 is a %3 class %2");
|
||||
const char* attribute = (scope == eGlobal) ?
|
||||
"moz_global_class" : "moz_stack_class";
|
||||
const char* type = (scope == eGlobal) ?
|
||||
"global" : "stack";
|
||||
|
||||
// Find the CXXRecordDecl that is the local/global class of interest
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
|
||||
// Direct result, we're done.
|
||||
if (MozChecker::hasCustomAnnotation(clazz, attribute))
|
||||
return;
|
||||
|
||||
const Decl *cause = inferredAllocCauses[clazz].first;
|
||||
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(cause)) {
|
||||
Diag.Report(clazz->getLocation(), inheritsID) <<
|
||||
T << CRD->getDeclName() << type;
|
||||
} else if (const FieldDecl *FD = dyn_cast<FieldDecl>(cause)) {
|
||||
Diag.Report(FD->getLocation(), memberID) <<
|
||||
T << FD << FD->getType() << type;
|
||||
Loc = expr->getLocStart();
|
||||
T = GetCallReturnType(expr)->getPointeeType();
|
||||
}
|
||||
|
||||
// Recursively follow this back.
|
||||
noteInferred(cast<ValueDecl>(cause)->getType(), Diag);
|
||||
if (scope == eLocal) {
|
||||
Diag.Report(Loc, stackID) << T;
|
||||
StackClass.dumpAnnotationReason(Diag, T, Loc);
|
||||
} else if (scope == eGlobal) {
|
||||
Diag.Report(Loc, globalID) << T;
|
||||
GlobalClass.dumpAnnotationReason(Diag, T, Loc);
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::NonHeapClassChecker::run(
|
||||
@ -897,46 +1047,22 @@ void DiagnosticsMatcher::NonHeapClassChecker::run(
|
||||
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
||||
unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "variable of type %0 is not valid on the heap");
|
||||
|
||||
SourceLocation Loc;
|
||||
QualType T;
|
||||
if (const CXXNewExpr *expr = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
|
||||
// If it's placement new, then this match doesn't count.
|
||||
if (isPlacementNew(expr))
|
||||
return;
|
||||
Diag.Report(expr->getStartLoc(), stackID) << expr->getAllocatedType();
|
||||
noteInferred(expr->getAllocatedType(), Diag);
|
||||
Loc = expr->getLocStart();
|
||||
T = expr->getAllocatedType();
|
||||
} else if (const CallExpr *expr = Result.Nodes.getNodeAs<CallExpr>("node")) {
|
||||
QualType badType = GetCallReturnType(expr)->getPointeeType();
|
||||
Diag.Report(expr->getLocStart(), stackID) << badType;
|
||||
noteInferred(badType, Diag);
|
||||
Loc = expr->getLocStart();
|
||||
T = GetCallReturnType(expr)->getPointeeType();
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::NonHeapClassChecker::noteInferred(QualType T,
|
||||
DiagnosticsEngine &Diag) {
|
||||
unsigned inheritsID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note,
|
||||
"%0 is a non-heap class because it inherits from a non-heap class %1");
|
||||
unsigned memberID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note,
|
||||
"%0 is a non-heap class because member %1 is a non-heap class %2");
|
||||
|
||||
// Find the CXXRecordDecl that is the stack class of interest
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
|
||||
// Direct result, we're done.
|
||||
if (MozChecker::hasCustomAnnotation(clazz, "moz_nonheap_class"))
|
||||
return;
|
||||
|
||||
const Decl *cause = inferredAllocCauses[clazz].first;
|
||||
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(cause)) {
|
||||
Diag.Report(clazz->getLocation(), inheritsID) << T << CRD->getDeclName();
|
||||
} else if (const FieldDecl *FD = dyn_cast<FieldDecl>(cause)) {
|
||||
Diag.Report(FD->getLocation(), memberID) << T << FD << FD->getType();
|
||||
}
|
||||
|
||||
// Recursively follow this back.
|
||||
noteInferred(cast<ValueDecl>(cause)->getType(), Diag);
|
||||
Diag.Report(Loc, stackID) << T;
|
||||
NonHeapClass.dumpAnnotationReason(Diag, T, Loc);
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::ArithmeticArgChecker::run(
|
||||
@ -1047,6 +1173,72 @@ void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run(
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::NeedsNoVTableTypeChecker::run(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
||||
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "%0 cannot be instantiated because %1 has a VTable");
|
||||
unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "bad instantiation of %0 requested here");
|
||||
|
||||
const ClassTemplateSpecializationDecl *specialization =
|
||||
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node");
|
||||
|
||||
// Get the offending template argument
|
||||
QualType offender;
|
||||
const TemplateArgumentList &args =
|
||||
specialization->getTemplateInstantiationArgs();
|
||||
for (unsigned i = 0; i < args.size(); ++i) {
|
||||
offender = args[i].getAsType();
|
||||
if (typeHasVTable(offender)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Diag.Report(specialization->getLocStart(), errorID) << specialization << offender;
|
||||
Diag.Report(specialization->getPointOfInstantiation(), noteID) << specialization;
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::NonMemMovableChecker::run(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
||||
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "Cannot instantiate %0 with non-memmovable template argument %1");
|
||||
unsigned note1ID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "instantiation of %0 requested here");
|
||||
unsigned note2ID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note, "%0 is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on %1");
|
||||
unsigned note3ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, "%0");
|
||||
|
||||
// Get the specialization
|
||||
const ClassTemplateSpecializationDecl *specialization =
|
||||
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
|
||||
SourceLocation requestLoc = specialization->getPointOfInstantiation();
|
||||
const CXXRecordDecl *templ =
|
||||
specialization->getSpecializedTemplate()->getTemplatedDecl();
|
||||
|
||||
// Report an error for every template argument which is non-memmovable
|
||||
const TemplateArgumentList &args =
|
||||
specialization->getTemplateInstantiationArgs();
|
||||
for (unsigned i = 0; i < args.size(); ++i) {
|
||||
QualType argType = args[i].getAsType();
|
||||
if (isClassNonMemMovable(args[i].getAsType())) {
|
||||
const CXXRecordDecl *reason = findWhyClassIsNonMemMovable(argType);
|
||||
Diag.Report(specialization->getLocation(), errorID)
|
||||
<< specialization << argType;
|
||||
// XXX It would be really nice if we could get the instantiation stack information
|
||||
// from Sema such that we could print a full template instantiation stack, however,
|
||||
// it seems as though that information is thrown out by the time we get here so we
|
||||
// can only report one level of template specialization (which in many cases won't
|
||||
// be useful)
|
||||
Diag.Report(requestLoc, note1ID)
|
||||
<< specialization;
|
||||
Diag.Report(reason->getLocation(), note2ID)
|
||||
<< argType << reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MozCheckAction : public PluginASTAction {
|
||||
public:
|
||||
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {
|
||||
|
@ -16,9 +16,9 @@ void gobble(void *) { }
|
||||
|
||||
void misuseGlobalClass(int len) {
|
||||
Global notValid; // expected-error {{variable of type 'Global' only valid as global}}
|
||||
Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}}
|
||||
Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}}
|
||||
static Global valid; // expected-error {{variable of type 'Global' only valid as global}}
|
||||
static Global alsoValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}}
|
||||
static Global alsoValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}}
|
||||
|
||||
gobble(&valid);
|
||||
gobble(¬Valid);
|
||||
@ -35,7 +35,7 @@ void misuseGlobalClass(int len) {
|
||||
|
||||
Global valid;
|
||||
struct RandomClass {
|
||||
Global nonstaticMember; // expected-note {{'RandomClass' is a global class because member 'nonstaticMember' is a global class 'Global'}}
|
||||
Global nonstaticMember; // expected-note {{'RandomClass' is a global type because member 'nonstaticMember' is a global type 'Global'}}
|
||||
static Global staticMember;
|
||||
};
|
||||
struct MOZ_GLOBAL_CLASS RandomGlobalClass {
|
||||
@ -43,7 +43,7 @@ struct MOZ_GLOBAL_CLASS RandomGlobalClass {
|
||||
static Global staticMember;
|
||||
};
|
||||
|
||||
struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global class because it inherits from a global class 'Global'}}
|
||||
struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global type because it inherits from a global type 'Global'}}
|
||||
struct MOZ_GLOBAL_CLASS GoodInherit : Global {};
|
||||
|
||||
void misuseGlobalClassEvenMore(int len) {
|
||||
|
17
build/clang-plugin/tests/TestMultipleAnnotations.cpp
Normal file
17
build/clang-plugin/tests/TestMultipleAnnotations.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#define MOZ_MUST_USE __attribute__((annotate("moz_must_use")))
|
||||
#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
|
||||
|
||||
class MOZ_MUST_USE MOZ_STACK_CLASS TestClass {};
|
||||
|
||||
TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}}
|
||||
|
||||
TestClass f()
|
||||
{
|
||||
TestClass bar;
|
||||
return bar;
|
||||
}
|
||||
|
||||
void g()
|
||||
{
|
||||
f(); // expected-error {{Unused value of must-use type 'TestClass'}}
|
||||
}
|
@ -20,42 +20,42 @@ void use(MayUse&&);
|
||||
void use(bool);
|
||||
|
||||
void foo() {
|
||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
{
|
||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
}
|
||||
if (true) {
|
||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
} else {
|
||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
}
|
||||
|
||||
if(true) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
else producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
if(true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
else producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
if(true) producesMustUsePointer();
|
||||
else producesMustUsePointer();
|
||||
if(true) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
else producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
if(true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
else producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
if(true) producesMayUse();
|
||||
else producesMayUse();
|
||||
if(true) producesMayUsePointer();
|
||||
@ -63,18 +63,18 @@ void foo() {
|
||||
if(true) producesMayUseRef();
|
||||
else producesMayUseRef();
|
||||
|
||||
while (true) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
while (true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
while (true) producesMustUsePointer();
|
||||
while (true) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
while (true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
while (true) producesMayUse();
|
||||
while (true) producesMayUsePointer();
|
||||
while (true) producesMayUseRef();
|
||||
|
||||
do producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
do producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
while (true);
|
||||
do producesMustUsePointer();
|
||||
while (true);
|
||||
do producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
do producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
while (true);
|
||||
do producesMayUse();
|
||||
while (true);
|
||||
@ -83,48 +83,48 @@ void foo() {
|
||||
do producesMayUseRef();
|
||||
while (true);
|
||||
|
||||
for (;;) producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
for (;;) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (;;) producesMustUsePointer();
|
||||
for (;;) producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
for (;;) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (;;) producesMayUse();
|
||||
for (;;) producesMayUsePointer();
|
||||
for (;;) producesMayUseRef();
|
||||
|
||||
for (producesMustUse();;); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
for (producesMustUse();;); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (producesMustUsePointer();;);
|
||||
for (producesMustUseRef();;); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
for (producesMustUseRef();;); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (producesMayUse();;);
|
||||
for (producesMayUsePointer();;);
|
||||
for (producesMayUseRef();;);
|
||||
|
||||
for (;;producesMustUse()); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
for (;;producesMustUse()); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (;;producesMustUsePointer());
|
||||
for (;;producesMustUseRef()); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
for (;;producesMustUseRef()); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
for (;;producesMayUse());
|
||||
for (;;producesMayUsePointer());
|
||||
for (;;producesMayUseRef());
|
||||
|
||||
use((producesMustUse(), false)); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
use((producesMustUse(), false)); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
use((producesMustUsePointer(), false));
|
||||
use((producesMustUseRef(), false)); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
use((producesMustUseRef(), false)); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
use((producesMayUse(), false));
|
||||
use((producesMayUsePointer(), false));
|
||||
use((producesMayUseRef(), false));
|
||||
|
||||
switch (1) {
|
||||
case 1:
|
||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
case 2:
|
||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
case 3:
|
||||
producesMustUsePointer();
|
||||
case 4:
|
||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
case 5:
|
||||
producesMayUse();
|
||||
case 6:
|
||||
@ -132,9 +132,9 @@ void foo() {
|
||||
case 7:
|
||||
producesMayUseRef();
|
||||
default:
|
||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMustUsePointer();
|
||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
||||
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||
producesMayUse();
|
||||
producesMayUsePointer();
|
||||
producesMayUseRef();
|
||||
|
94
build/clang-plugin/tests/TestNeedsNoVTableType.cpp
Normal file
94
build/clang-plugin/tests/TestNeedsNoVTableType.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer { // expected-error {{'PickyConsumer<B>' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer<E>' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer<F>' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer<G>' cannot be instantiated because 'G' has a VTable}}
|
||||
T *m;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_A { // expected-error {{'PickyConsumer_A<B>' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_A<E>' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_A<F>' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_A<G>' cannot be instantiated because 'G' has a VTable}}
|
||||
T *m;
|
||||
};
|
||||
template <class T>
|
||||
struct PickyConsumerWrapper {
|
||||
PickyConsumer_A<T> m; // expected-note {{bad instantiation of 'PickyConsumer_A<B>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A<E>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A<F>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A<G>' requested here}}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_B { // expected-error {{'PickyConsumer_B<B>' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_B<E>' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_B<F>' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_B<G>' cannot be instantiated because 'G' has a VTable}}
|
||||
T *m;
|
||||
};
|
||||
template <class T>
|
||||
struct PickyConsumerSubclass : PickyConsumer_B<T> {}; // expected-note {{bad instantiation of 'PickyConsumer_B<B>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B<E>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B<F>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B<G>' requested here}}
|
||||
|
||||
template <class T>
|
||||
struct NonPickyConsumer {
|
||||
T *m;
|
||||
};
|
||||
|
||||
struct A {};
|
||||
struct B : virtual A {};
|
||||
struct C : A {};
|
||||
struct D {
|
||||
void d();
|
||||
};
|
||||
struct E {
|
||||
virtual void e();
|
||||
};
|
||||
struct F : E {
|
||||
virtual void e() final;
|
||||
};
|
||||
struct G {
|
||||
virtual void e() = 0;
|
||||
};
|
||||
|
||||
void f() {
|
||||
{
|
||||
PickyConsumer<A> a1;
|
||||
PickyConsumerWrapper<A> a2;
|
||||
PickyConsumerSubclass<A> a3;
|
||||
NonPickyConsumer<A> a4;
|
||||
}
|
||||
|
||||
{
|
||||
PickyConsumer<B> a1; // expected-note {{bad instantiation of 'PickyConsumer<B>' requested here}}
|
||||
PickyConsumerWrapper<B> a2;
|
||||
PickyConsumerSubclass<B> a3;
|
||||
NonPickyConsumer<B> a4;
|
||||
}
|
||||
|
||||
{
|
||||
PickyConsumer<C> a1;
|
||||
PickyConsumerWrapper<C> a2;
|
||||
PickyConsumerSubclass<C> a3;
|
||||
NonPickyConsumer<C> a4;
|
||||
}
|
||||
|
||||
{
|
||||
PickyConsumer<D> a1;
|
||||
PickyConsumerWrapper<D> a2;
|
||||
PickyConsumerSubclass<D> a3;
|
||||
NonPickyConsumer<D> a4;
|
||||
}
|
||||
|
||||
{
|
||||
PickyConsumer<E> a1; // expected-note {{bad instantiation of 'PickyConsumer<E>' requested here}}
|
||||
PickyConsumerWrapper<E> a2;
|
||||
PickyConsumerSubclass<E> a3;
|
||||
NonPickyConsumer<E> a4;
|
||||
}
|
||||
|
||||
{
|
||||
PickyConsumer<F> a1; // expected-note {{bad instantiation of 'PickyConsumer<F>' requested here}}
|
||||
PickyConsumerWrapper<F> a2;
|
||||
PickyConsumerSubclass<F> a3;
|
||||
NonPickyConsumer<F> a4;
|
||||
}
|
||||
|
||||
{
|
||||
PickyConsumer<G> a1; // expected-note {{bad instantiation of 'PickyConsumer<G>' requested here}}
|
||||
PickyConsumerWrapper<G> a2;
|
||||
PickyConsumerSubclass<G> a3;
|
||||
NonPickyConsumer<G> a4;
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ void misuseNonHeapClass(int len) {
|
||||
|
||||
NonHeap validStatic;
|
||||
struct RandomClass {
|
||||
NonHeap nonstaticMember; // expected-note {{'RandomClass' is a non-heap class because member 'nonstaticMember' is a non-heap class 'NonHeap'}}
|
||||
NonHeap nonstaticMember; // expected-note {{'RandomClass' is a non-heap type because member 'nonstaticMember' is a non-heap type 'NonHeap'}}
|
||||
static NonHeap staticMember;
|
||||
};
|
||||
struct MOZ_NONHEAP_CLASS RandomNonHeapClass {
|
||||
@ -44,7 +44,7 @@ struct MOZ_NONHEAP_CLASS RandomNonHeapClass {
|
||||
static NonHeap staticMember;
|
||||
};
|
||||
|
||||
struct BadInherit : NonHeap {}; // expected-note {{'BadInherit' is a non-heap class because it inherits from a non-heap class 'NonHeap'}}
|
||||
struct BadInherit : NonHeap {}; // expected-note {{'BadInherit' is a non-heap type because it inherits from a non-heap type 'NonHeap'}}
|
||||
struct MOZ_NONHEAP_CLASS GoodInherit : NonHeap {};
|
||||
|
||||
void useStuffWrongly() {
|
||||
@ -52,11 +52,11 @@ void useStuffWrongly() {
|
||||
gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}}
|
||||
}
|
||||
|
||||
// Stack class overrides non-heap classes.
|
||||
// Stack class overrides non-heap typees.
|
||||
struct MOZ_STACK_CLASS StackClass {};
|
||||
struct MOZ_NONHEAP_CLASS InferredStackClass : GoodInherit {
|
||||
NonHeap nonstaticMember;
|
||||
StackClass stackClass; // expected-note {{'InferredStackClass' is a stack class because member 'stackClass' is a stack class 'StackClass'}}
|
||||
StackClass stackClass; // expected-note {{'InferredStackClass' is a stack type because member 'stackClass' is a stack type 'StackClass'}}
|
||||
};
|
||||
|
||||
InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}}
|
||||
|
812
build/clang-plugin/tests/TestNonMemMovable.cpp
Normal file
812
build/clang-plugin/tests/TestNonMemMovable.cpp
Normal file
@ -0,0 +1,812 @@
|
||||
#define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
|
||||
#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
|
||||
|
||||
/*
|
||||
These are a bunch of structs with variable levels of memmovability.
|
||||
They will be used as template parameters to the various NeedyTemplates
|
||||
*/
|
||||
struct MOZ_NON_MEMMOVABLE NonMovable {}; // expected-note-re + {{'{{.*}}' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'NonMovable'}}
|
||||
struct Movable {};
|
||||
|
||||
// Subclasses
|
||||
struct S_NonMovable : NonMovable {};
|
||||
struct S_Movable : Movable {};
|
||||
|
||||
// Members
|
||||
struct W_NonMovable {
|
||||
NonMovable m;
|
||||
};
|
||||
struct W_Movable {
|
||||
Movable m;
|
||||
};
|
||||
|
||||
// Wrapped Subclasses
|
||||
struct WS_NonMovable {
|
||||
S_NonMovable m;
|
||||
};
|
||||
struct WS_Movable {
|
||||
S_Movable m;
|
||||
};
|
||||
|
||||
// Combinations of the above
|
||||
struct SW_NonMovable : W_NonMovable {};
|
||||
struct SW_Movable : W_Movable {};
|
||||
|
||||
struct SWS_NonMovable : WS_NonMovable {};
|
||||
struct SWS_Movable : WS_Movable {};
|
||||
|
||||
// Basic templated wrapper
|
||||
template <class T>
|
||||
struct Template_Inline {
|
||||
T m;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Template_Ref {
|
||||
T* m;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Template_Unused {};
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NON_MEMMOVABLE Template_NonMovable {}; // expected-note-re + {{'{{.*}}' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'Template_NonMovable<{{.*}}>'}}
|
||||
|
||||
/*
|
||||
These tests take the following form:
|
||||
DECLARATIONS => Declarations of the templates which are either marked with MOZ_NEEDS_MEMMOVABLE_TYPE
|
||||
or which instantiate a MOZ_NEEDS_MEMMOVABLE_TYPE through some mechanism.
|
||||
BAD N => Instantiations of the wrapper template with each of the non-memmovable types.
|
||||
The prefix S_ means subclass, W_ means wrapped. Each of these rows should produce an error
|
||||
on the NeedyTemplate in question, and a note at the instantiation location of that template.
|
||||
Unfortunately, on every case more complicated than bad1, the instantiation location is
|
||||
within another template. Thus, the notes are expected on the template in question which
|
||||
actually instantiates the MOZ_NEEDS_MEMMOVABLE_TYPE template.
|
||||
GOOD N => Instantiations of the wrapper template with each of the memmovable types.
|
||||
This is meant as a sanity check to ensure that we don't reject valid instantiations of
|
||||
templates.
|
||||
|
||||
|
||||
Note 1: Each set uses it's own types to ensure that they don't re-use each-other's template specializations.
|
||||
If they did, then some of the error messages would not be emitted (as error messages are emitted for template
|
||||
specializations, rather than for variable declarations)
|
||||
|
||||
Note 2: Every instance of NeedyTemplate contains a member of type T. This is to ensure that T is actually
|
||||
instantiated (if T is a template) by clang. If T isn't instantiated, then we can't actually tell if it is
|
||||
NON_MEMMOVABLE. (This is OK in practice, as you cannot memmove a type which you don't know the size of).
|
||||
|
||||
Note 3: There are a set of tests for specializations of NeedyTemplate at the bottom. For each set of tests,
|
||||
these tests contribute two expected errors to the templates.
|
||||
*/
|
||||
|
||||
//
|
||||
// 1 - Unwrapped MOZ_NEEDS_MEMMOVABLE_TYPE
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate1 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate1<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
|
||||
void bad1() {
|
||||
NeedyTemplate1<NonMovable> a1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<S_NonMovable> a2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<W_NonMovable> a3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<WS_NonMovable> a4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<SW_NonMovable> a5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<SWS_NonMovable> a6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
|
||||
NeedyTemplate1<Template_Inline<NonMovable> > b1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_Inline<S_NonMovable> > b2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_Inline<W_NonMovable> > b3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_Inline<WS_NonMovable> > b4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_Inline<SW_NonMovable> > b5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_Inline<SWS_NonMovable> > b6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
|
||||
NeedyTemplate1<Template_NonMovable<NonMovable> > c1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<S_NonMovable> > c2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<W_NonMovable> > c3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<WS_NonMovable> > c4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<SW_NonMovable> > c5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<SWS_NonMovable> > c6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<Movable> > c7; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<S_Movable> > c8; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<W_Movable> > c9; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<WS_Movable> > c10; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<SW_Movable> > c11; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
NeedyTemplate1<Template_NonMovable<SWS_Movable> > c12; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}}
|
||||
}
|
||||
|
||||
void good1() {
|
||||
NeedyTemplate1<Movable> a1;
|
||||
NeedyTemplate1<S_Movable> a2;
|
||||
NeedyTemplate1<W_Movable> a3;
|
||||
NeedyTemplate1<WS_Movable> a4;
|
||||
NeedyTemplate1<SW_Movable> a5;
|
||||
NeedyTemplate1<SWS_Movable> a6;
|
||||
|
||||
NeedyTemplate1<Template_Inline<Movable> > b1;
|
||||
NeedyTemplate1<Template_Inline<S_Movable> > b2;
|
||||
NeedyTemplate1<Template_Inline<W_Movable> > b3;
|
||||
NeedyTemplate1<Template_Inline<WS_Movable> > b4;
|
||||
NeedyTemplate1<Template_Inline<SW_Movable> > b5;
|
||||
NeedyTemplate1<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
NeedyTemplate1<Template_Unused<Movable> > c1;
|
||||
NeedyTemplate1<Template_Unused<S_Movable> > c2;
|
||||
NeedyTemplate1<Template_Unused<W_Movable> > c3;
|
||||
NeedyTemplate1<Template_Unused<WS_Movable> > c4;
|
||||
NeedyTemplate1<Template_Unused<SW_Movable> > c5;
|
||||
NeedyTemplate1<Template_Unused<SWS_Movable> > c6;
|
||||
NeedyTemplate1<Template_Unused<NonMovable> > c7;
|
||||
NeedyTemplate1<Template_Unused<S_NonMovable> > c8;
|
||||
NeedyTemplate1<Template_Unused<W_NonMovable> > c9;
|
||||
NeedyTemplate1<Template_Unused<WS_NonMovable> > c10;
|
||||
NeedyTemplate1<Template_Unused<SW_NonMovable> > c11;
|
||||
NeedyTemplate1<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
NeedyTemplate1<Template_Ref<Movable> > d1;
|
||||
NeedyTemplate1<Template_Ref<S_Movable> > d2;
|
||||
NeedyTemplate1<Template_Ref<W_Movable> > d3;
|
||||
NeedyTemplate1<Template_Ref<WS_Movable> > d4;
|
||||
NeedyTemplate1<Template_Ref<SW_Movable> > d5;
|
||||
NeedyTemplate1<Template_Ref<SWS_Movable> > d6;
|
||||
NeedyTemplate1<Template_Ref<NonMovable> > d7;
|
||||
NeedyTemplate1<Template_Ref<S_NonMovable> > d8;
|
||||
NeedyTemplate1<Template_Ref<W_NonMovable> > d9;
|
||||
NeedyTemplate1<Template_Ref<WS_NonMovable> > d10;
|
||||
NeedyTemplate1<Template_Ref<SW_NonMovable> > d11;
|
||||
NeedyTemplate1<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
//
|
||||
// 2 - Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate2 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate2<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
template <class T>
|
||||
struct S_NeedyTemplate2 : NeedyTemplate2<T> {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate2<{{.*}}>' requested here}}
|
||||
|
||||
void bad2() {
|
||||
S_NeedyTemplate2<NonMovable> a1;
|
||||
S_NeedyTemplate2<S_NonMovable> a2;
|
||||
S_NeedyTemplate2<W_NonMovable> a3;
|
||||
S_NeedyTemplate2<WS_NonMovable> a4;
|
||||
S_NeedyTemplate2<SW_NonMovable> a5;
|
||||
S_NeedyTemplate2<SWS_NonMovable> a6;
|
||||
|
||||
S_NeedyTemplate2<Template_Inline<NonMovable> > b1;
|
||||
S_NeedyTemplate2<Template_Inline<S_NonMovable> > b2;
|
||||
S_NeedyTemplate2<Template_Inline<W_NonMovable> > b3;
|
||||
S_NeedyTemplate2<Template_Inline<WS_NonMovable> > b4;
|
||||
S_NeedyTemplate2<Template_Inline<SW_NonMovable> > b5;
|
||||
S_NeedyTemplate2<Template_Inline<SWS_NonMovable> > b6;
|
||||
|
||||
S_NeedyTemplate2<Template_NonMovable<NonMovable> > c1;
|
||||
S_NeedyTemplate2<Template_NonMovable<S_NonMovable> > c2;
|
||||
S_NeedyTemplate2<Template_NonMovable<W_NonMovable> > c3;
|
||||
S_NeedyTemplate2<Template_NonMovable<WS_NonMovable> > c4;
|
||||
S_NeedyTemplate2<Template_NonMovable<SW_NonMovable> > c5;
|
||||
S_NeedyTemplate2<Template_NonMovable<SWS_NonMovable> > c6;
|
||||
S_NeedyTemplate2<Template_NonMovable<Movable> > c7;
|
||||
S_NeedyTemplate2<Template_NonMovable<S_Movable> > c8;
|
||||
S_NeedyTemplate2<Template_NonMovable<W_Movable> > c9;
|
||||
S_NeedyTemplate2<Template_NonMovable<WS_Movable> > c10;
|
||||
S_NeedyTemplate2<Template_NonMovable<SW_Movable> > c11;
|
||||
S_NeedyTemplate2<Template_NonMovable<SWS_Movable> > c12;
|
||||
}
|
||||
|
||||
void good2() {
|
||||
S_NeedyTemplate2<Movable> a1;
|
||||
S_NeedyTemplate2<S_Movable> a2;
|
||||
S_NeedyTemplate2<W_Movable> a3;
|
||||
S_NeedyTemplate2<WS_Movable> a4;
|
||||
S_NeedyTemplate2<SW_Movable> a5;
|
||||
S_NeedyTemplate2<SWS_Movable> a6;
|
||||
|
||||
S_NeedyTemplate2<Template_Inline<Movable> > b1;
|
||||
S_NeedyTemplate2<Template_Inline<S_Movable> > b2;
|
||||
S_NeedyTemplate2<Template_Inline<W_Movable> > b3;
|
||||
S_NeedyTemplate2<Template_Inline<WS_Movable> > b4;
|
||||
S_NeedyTemplate2<Template_Inline<SW_Movable> > b5;
|
||||
S_NeedyTemplate2<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
S_NeedyTemplate2<Template_Unused<Movable> > c1;
|
||||
S_NeedyTemplate2<Template_Unused<S_Movable> > c2;
|
||||
S_NeedyTemplate2<Template_Unused<W_Movable> > c3;
|
||||
S_NeedyTemplate2<Template_Unused<WS_Movable> > c4;
|
||||
S_NeedyTemplate2<Template_Unused<SW_Movable> > c5;
|
||||
S_NeedyTemplate2<Template_Unused<SWS_Movable> > c6;
|
||||
S_NeedyTemplate2<Template_Unused<NonMovable> > c7;
|
||||
S_NeedyTemplate2<Template_Unused<S_NonMovable> > c8;
|
||||
S_NeedyTemplate2<Template_Unused<W_NonMovable> > c9;
|
||||
S_NeedyTemplate2<Template_Unused<WS_NonMovable> > c10;
|
||||
S_NeedyTemplate2<Template_Unused<SW_NonMovable> > c11;
|
||||
S_NeedyTemplate2<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
S_NeedyTemplate2<Template_Ref<Movable> > d1;
|
||||
S_NeedyTemplate2<Template_Ref<S_Movable> > d2;
|
||||
S_NeedyTemplate2<Template_Ref<W_Movable> > d3;
|
||||
S_NeedyTemplate2<Template_Ref<WS_Movable> > d4;
|
||||
S_NeedyTemplate2<Template_Ref<SW_Movable> > d5;
|
||||
S_NeedyTemplate2<Template_Ref<SWS_Movable> > d6;
|
||||
S_NeedyTemplate2<Template_Ref<NonMovable> > d7;
|
||||
S_NeedyTemplate2<Template_Ref<S_NonMovable> > d8;
|
||||
S_NeedyTemplate2<Template_Ref<W_NonMovable> > d9;
|
||||
S_NeedyTemplate2<Template_Ref<WS_NonMovable> > d10;
|
||||
S_NeedyTemplate2<Template_Ref<SW_NonMovable> > d11;
|
||||
S_NeedyTemplate2<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
//
|
||||
// 3 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate3 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate3<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
template <class T>
|
||||
struct W_NeedyTemplate3 {
|
||||
NeedyTemplate3<T> m; // expected-note-re 26 {{instantiation of 'NeedyTemplate3<{{.*}}>' requested here}}
|
||||
};
|
||||
void bad3() {
|
||||
W_NeedyTemplate3<NonMovable> a1;
|
||||
W_NeedyTemplate3<S_NonMovable> a2;
|
||||
W_NeedyTemplate3<W_NonMovable> a3;
|
||||
W_NeedyTemplate3<WS_NonMovable> a4;
|
||||
W_NeedyTemplate3<SW_NonMovable> a5;
|
||||
W_NeedyTemplate3<SWS_NonMovable> a6;
|
||||
|
||||
W_NeedyTemplate3<Template_Inline<NonMovable> > b1;
|
||||
W_NeedyTemplate3<Template_Inline<S_NonMovable> > b2;
|
||||
W_NeedyTemplate3<Template_Inline<W_NonMovable> > b3;
|
||||
W_NeedyTemplate3<Template_Inline<WS_NonMovable> > b4;
|
||||
W_NeedyTemplate3<Template_Inline<SW_NonMovable> > b5;
|
||||
W_NeedyTemplate3<Template_Inline<SWS_NonMovable> > b6;
|
||||
|
||||
W_NeedyTemplate3<Template_NonMovable<NonMovable> > c1;
|
||||
W_NeedyTemplate3<Template_NonMovable<S_NonMovable> > c2;
|
||||
W_NeedyTemplate3<Template_NonMovable<W_NonMovable> > c3;
|
||||
W_NeedyTemplate3<Template_NonMovable<WS_NonMovable> > c4;
|
||||
W_NeedyTemplate3<Template_NonMovable<SW_NonMovable> > c5;
|
||||
W_NeedyTemplate3<Template_NonMovable<SWS_NonMovable> > c6;
|
||||
W_NeedyTemplate3<Template_NonMovable<Movable> > c7;
|
||||
W_NeedyTemplate3<Template_NonMovable<S_Movable> > c8;
|
||||
W_NeedyTemplate3<Template_NonMovable<W_Movable> > c9;
|
||||
W_NeedyTemplate3<Template_NonMovable<WS_Movable> > c10;
|
||||
W_NeedyTemplate3<Template_NonMovable<SW_Movable> > c11;
|
||||
W_NeedyTemplate3<Template_NonMovable<SWS_Movable> > c12;
|
||||
}
|
||||
|
||||
void good3() {
|
||||
W_NeedyTemplate3<Movable> a1;
|
||||
W_NeedyTemplate3<S_Movable> a2;
|
||||
W_NeedyTemplate3<W_Movable> a3;
|
||||
W_NeedyTemplate3<WS_Movable> a4;
|
||||
W_NeedyTemplate3<SW_Movable> a5;
|
||||
W_NeedyTemplate3<SWS_Movable> a6;
|
||||
|
||||
W_NeedyTemplate3<Template_Inline<Movable> > b1;
|
||||
W_NeedyTemplate3<Template_Inline<S_Movable> > b2;
|
||||
W_NeedyTemplate3<Template_Inline<W_Movable> > b3;
|
||||
W_NeedyTemplate3<Template_Inline<WS_Movable> > b4;
|
||||
W_NeedyTemplate3<Template_Inline<SW_Movable> > b5;
|
||||
W_NeedyTemplate3<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
W_NeedyTemplate3<Template_Unused<Movable> > c1;
|
||||
W_NeedyTemplate3<Template_Unused<S_Movable> > c2;
|
||||
W_NeedyTemplate3<Template_Unused<W_Movable> > c3;
|
||||
W_NeedyTemplate3<Template_Unused<WS_Movable> > c4;
|
||||
W_NeedyTemplate3<Template_Unused<SW_Movable> > c5;
|
||||
W_NeedyTemplate3<Template_Unused<SWS_Movable> > c6;
|
||||
W_NeedyTemplate3<Template_Unused<NonMovable> > c7;
|
||||
W_NeedyTemplate3<Template_Unused<S_NonMovable> > c8;
|
||||
W_NeedyTemplate3<Template_Unused<W_NonMovable> > c9;
|
||||
W_NeedyTemplate3<Template_Unused<WS_NonMovable> > c10;
|
||||
W_NeedyTemplate3<Template_Unused<SW_NonMovable> > c11;
|
||||
W_NeedyTemplate3<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
W_NeedyTemplate3<Template_Ref<Movable> > d1;
|
||||
W_NeedyTemplate3<Template_Ref<S_Movable> > d2;
|
||||
W_NeedyTemplate3<Template_Ref<W_Movable> > d3;
|
||||
W_NeedyTemplate3<Template_Ref<WS_Movable> > d4;
|
||||
W_NeedyTemplate3<Template_Ref<SW_Movable> > d5;
|
||||
W_NeedyTemplate3<Template_Ref<SWS_Movable> > d6;
|
||||
W_NeedyTemplate3<Template_Ref<NonMovable> > d7;
|
||||
W_NeedyTemplate3<Template_Ref<S_NonMovable> > d8;
|
||||
W_NeedyTemplate3<Template_Ref<W_NonMovable> > d9;
|
||||
W_NeedyTemplate3<Template_Ref<WS_NonMovable> > d10;
|
||||
W_NeedyTemplate3<Template_Ref<SW_NonMovable> > d11;
|
||||
W_NeedyTemplate3<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
//
|
||||
// 4 - Wrapped Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate4 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate4<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
template <class T>
|
||||
struct S_NeedyTemplate4 : NeedyTemplate4<T> {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate4<{{.*}}>' requested here}}
|
||||
template <class T>
|
||||
struct WS_NeedyTemplate4 {
|
||||
S_NeedyTemplate4<T> m;
|
||||
};
|
||||
void bad4() {
|
||||
WS_NeedyTemplate4<NonMovable> a1;
|
||||
WS_NeedyTemplate4<S_NonMovable> a2;
|
||||
WS_NeedyTemplate4<W_NonMovable> a3;
|
||||
WS_NeedyTemplate4<WS_NonMovable> a4;
|
||||
WS_NeedyTemplate4<SW_NonMovable> a5;
|
||||
WS_NeedyTemplate4<SWS_NonMovable> a6;
|
||||
|
||||
WS_NeedyTemplate4<Template_Inline<NonMovable> > b1;
|
||||
WS_NeedyTemplate4<Template_Inline<S_NonMovable> > b2;
|
||||
WS_NeedyTemplate4<Template_Inline<W_NonMovable> > b3;
|
||||
WS_NeedyTemplate4<Template_Inline<WS_NonMovable> > b4;
|
||||
WS_NeedyTemplate4<Template_Inline<SW_NonMovable> > b5;
|
||||
WS_NeedyTemplate4<Template_Inline<SWS_NonMovable> > b6;
|
||||
|
||||
WS_NeedyTemplate4<Template_NonMovable<NonMovable> > c1;
|
||||
WS_NeedyTemplate4<Template_NonMovable<S_NonMovable> > c2;
|
||||
WS_NeedyTemplate4<Template_NonMovable<W_NonMovable> > c3;
|
||||
WS_NeedyTemplate4<Template_NonMovable<WS_NonMovable> > c4;
|
||||
WS_NeedyTemplate4<Template_NonMovable<SW_NonMovable> > c5;
|
||||
WS_NeedyTemplate4<Template_NonMovable<SWS_NonMovable> > c6;
|
||||
WS_NeedyTemplate4<Template_NonMovable<Movable> > c7;
|
||||
WS_NeedyTemplate4<Template_NonMovable<S_Movable> > c8;
|
||||
WS_NeedyTemplate4<Template_NonMovable<W_Movable> > c9;
|
||||
WS_NeedyTemplate4<Template_NonMovable<WS_Movable> > c10;
|
||||
WS_NeedyTemplate4<Template_NonMovable<SW_Movable> > c11;
|
||||
WS_NeedyTemplate4<Template_NonMovable<SWS_Movable> > c12;
|
||||
}
|
||||
|
||||
void good4() {
|
||||
WS_NeedyTemplate4<Movable> a1;
|
||||
WS_NeedyTemplate4<S_Movable> a2;
|
||||
WS_NeedyTemplate4<W_Movable> a3;
|
||||
WS_NeedyTemplate4<WS_Movable> a4;
|
||||
WS_NeedyTemplate4<SW_Movable> a5;
|
||||
WS_NeedyTemplate4<SWS_Movable> a6;
|
||||
|
||||
WS_NeedyTemplate4<Template_Inline<Movable> > b1;
|
||||
WS_NeedyTemplate4<Template_Inline<S_Movable> > b2;
|
||||
WS_NeedyTemplate4<Template_Inline<W_Movable> > b3;
|
||||
WS_NeedyTemplate4<Template_Inline<WS_Movable> > b4;
|
||||
WS_NeedyTemplate4<Template_Inline<SW_Movable> > b5;
|
||||
WS_NeedyTemplate4<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
WS_NeedyTemplate4<Template_Unused<Movable> > c1;
|
||||
WS_NeedyTemplate4<Template_Unused<S_Movable> > c2;
|
||||
WS_NeedyTemplate4<Template_Unused<W_Movable> > c3;
|
||||
WS_NeedyTemplate4<Template_Unused<WS_Movable> > c4;
|
||||
WS_NeedyTemplate4<Template_Unused<SW_Movable> > c5;
|
||||
WS_NeedyTemplate4<Template_Unused<SWS_Movable> > c6;
|
||||
WS_NeedyTemplate4<Template_Unused<NonMovable> > c7;
|
||||
WS_NeedyTemplate4<Template_Unused<S_NonMovable> > c8;
|
||||
WS_NeedyTemplate4<Template_Unused<W_NonMovable> > c9;
|
||||
WS_NeedyTemplate4<Template_Unused<WS_NonMovable> > c10;
|
||||
WS_NeedyTemplate4<Template_Unused<SW_NonMovable> > c11;
|
||||
WS_NeedyTemplate4<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
WS_NeedyTemplate4<Template_Ref<Movable> > d1;
|
||||
WS_NeedyTemplate4<Template_Ref<S_Movable> > d2;
|
||||
WS_NeedyTemplate4<Template_Ref<W_Movable> > d3;
|
||||
WS_NeedyTemplate4<Template_Ref<WS_Movable> > d4;
|
||||
WS_NeedyTemplate4<Template_Ref<SW_Movable> > d5;
|
||||
WS_NeedyTemplate4<Template_Ref<SWS_Movable> > d6;
|
||||
WS_NeedyTemplate4<Template_Ref<NonMovable> > d7;
|
||||
WS_NeedyTemplate4<Template_Ref<S_NonMovable> > d8;
|
||||
WS_NeedyTemplate4<Template_Ref<W_NonMovable> > d9;
|
||||
WS_NeedyTemplate4<Template_Ref<WS_NonMovable> > d10;
|
||||
WS_NeedyTemplate4<Template_Ref<SW_NonMovable> > d11;
|
||||
WS_NeedyTemplate4<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
//
|
||||
// 5 - Subclassed Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate5 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate5<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
template <class T>
|
||||
struct W_NeedyTemplate5 {
|
||||
NeedyTemplate5<T> m; // expected-note-re 26 {{instantiation of 'NeedyTemplate5<{{.*}}>' requested here}}
|
||||
};
|
||||
template <class T>
|
||||
struct SW_NeedyTemplate5 : W_NeedyTemplate5<T> {};
|
||||
void bad5() {
|
||||
SW_NeedyTemplate5<NonMovable> a1;
|
||||
SW_NeedyTemplate5<S_NonMovable> a2;
|
||||
SW_NeedyTemplate5<W_NonMovable> a3;
|
||||
SW_NeedyTemplate5<WS_NonMovable> a4;
|
||||
SW_NeedyTemplate5<SW_NonMovable> a5;
|
||||
SW_NeedyTemplate5<SWS_NonMovable> a6;
|
||||
|
||||
SW_NeedyTemplate5<Template_Inline<NonMovable> > b1;
|
||||
SW_NeedyTemplate5<Template_Inline<S_NonMovable> > b2;
|
||||
SW_NeedyTemplate5<Template_Inline<W_NonMovable> > b3;
|
||||
SW_NeedyTemplate5<Template_Inline<WS_NonMovable> > b4;
|
||||
SW_NeedyTemplate5<Template_Inline<SW_NonMovable> > b5;
|
||||
SW_NeedyTemplate5<Template_Inline<SWS_NonMovable> > b6;
|
||||
|
||||
SW_NeedyTemplate5<Template_NonMovable<NonMovable> > c1;
|
||||
SW_NeedyTemplate5<Template_NonMovable<S_NonMovable> > c2;
|
||||
SW_NeedyTemplate5<Template_NonMovable<W_NonMovable> > c3;
|
||||
SW_NeedyTemplate5<Template_NonMovable<WS_NonMovable> > c4;
|
||||
SW_NeedyTemplate5<Template_NonMovable<SW_NonMovable> > c5;
|
||||
SW_NeedyTemplate5<Template_NonMovable<SWS_NonMovable> > c6;
|
||||
SW_NeedyTemplate5<Template_NonMovable<Movable> > c7;
|
||||
SW_NeedyTemplate5<Template_NonMovable<S_Movable> > c8;
|
||||
SW_NeedyTemplate5<Template_NonMovable<W_Movable> > c9;
|
||||
SW_NeedyTemplate5<Template_NonMovable<WS_Movable> > c10;
|
||||
SW_NeedyTemplate5<Template_NonMovable<SW_Movable> > c11;
|
||||
SW_NeedyTemplate5<Template_NonMovable<SWS_Movable> > c12;
|
||||
}
|
||||
|
||||
void good5() {
|
||||
SW_NeedyTemplate5<Movable> a1;
|
||||
SW_NeedyTemplate5<S_Movable> a2;
|
||||
SW_NeedyTemplate5<W_Movable> a3;
|
||||
SW_NeedyTemplate5<WS_Movable> a4;
|
||||
SW_NeedyTemplate5<SW_Movable> a5;
|
||||
SW_NeedyTemplate5<SWS_Movable> a6;
|
||||
|
||||
SW_NeedyTemplate5<Template_Inline<Movable> > b1;
|
||||
SW_NeedyTemplate5<Template_Inline<S_Movable> > b2;
|
||||
SW_NeedyTemplate5<Template_Inline<W_Movable> > b3;
|
||||
SW_NeedyTemplate5<Template_Inline<WS_Movable> > b4;
|
||||
SW_NeedyTemplate5<Template_Inline<SW_Movable> > b5;
|
||||
SW_NeedyTemplate5<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
SW_NeedyTemplate5<Template_Unused<Movable> > c1;
|
||||
SW_NeedyTemplate5<Template_Unused<S_Movable> > c2;
|
||||
SW_NeedyTemplate5<Template_Unused<W_Movable> > c3;
|
||||
SW_NeedyTemplate5<Template_Unused<WS_Movable> > c4;
|
||||
SW_NeedyTemplate5<Template_Unused<SW_Movable> > c5;
|
||||
SW_NeedyTemplate5<Template_Unused<SWS_Movable> > c6;
|
||||
SW_NeedyTemplate5<Template_Unused<NonMovable> > c7;
|
||||
SW_NeedyTemplate5<Template_Unused<S_NonMovable> > c8;
|
||||
SW_NeedyTemplate5<Template_Unused<W_NonMovable> > c9;
|
||||
SW_NeedyTemplate5<Template_Unused<WS_NonMovable> > c10;
|
||||
SW_NeedyTemplate5<Template_Unused<SW_NonMovable> > c11;
|
||||
SW_NeedyTemplate5<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
SW_NeedyTemplate5<Template_Ref<Movable> > d1;
|
||||
SW_NeedyTemplate5<Template_Ref<S_Movable> > d2;
|
||||
SW_NeedyTemplate5<Template_Ref<W_Movable> > d3;
|
||||
SW_NeedyTemplate5<Template_Ref<WS_Movable> > d4;
|
||||
SW_NeedyTemplate5<Template_Ref<SW_Movable> > d5;
|
||||
SW_NeedyTemplate5<Template_Ref<SWS_Movable> > d6;
|
||||
SW_NeedyTemplate5<Template_Ref<NonMovable> > d7;
|
||||
SW_NeedyTemplate5<Template_Ref<S_NonMovable> > d8;
|
||||
SW_NeedyTemplate5<Template_Ref<W_NonMovable> > d9;
|
||||
SW_NeedyTemplate5<Template_Ref<WS_NonMovable> > d10;
|
||||
SW_NeedyTemplate5<Template_Ref<SW_NonMovable> > d11;
|
||||
SW_NeedyTemplate5<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
//
|
||||
// 6 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated with default template argument
|
||||
//
|
||||
// Note: This has an extra error, because it also includes a test with the default template argument.
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate6 {T m;}; // expected-error-re 27 {{Cannot instantiate 'NeedyTemplate6<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
template <class T>
|
||||
struct W_NeedyTemplate6 {
|
||||
NeedyTemplate6<T> m; // expected-note-re 27 {{instantiation of 'NeedyTemplate6<{{.*}}>' requested here}}
|
||||
};
|
||||
template <class T>
|
||||
struct SW_NeedyTemplate6 : W_NeedyTemplate6<T> {};
|
||||
// We create a different NonMovable type here, as NeedyTemplate6 will already be instantiated with NonMovable
|
||||
struct MOZ_NON_MEMMOVABLE NonMovable2 {}; // expected-note {{'NonMovable2' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'NonMovable2'}}
|
||||
template <class T = NonMovable2>
|
||||
struct Defaulted_SW_NeedyTemplate6 {
|
||||
SW_NeedyTemplate6<T> m;
|
||||
};
|
||||
void bad6() {
|
||||
Defaulted_SW_NeedyTemplate6<NonMovable> a1;
|
||||
Defaulted_SW_NeedyTemplate6<S_NonMovable> a2;
|
||||
Defaulted_SW_NeedyTemplate6<W_NonMovable> a3;
|
||||
Defaulted_SW_NeedyTemplate6<WS_NonMovable> a4;
|
||||
Defaulted_SW_NeedyTemplate6<SW_NonMovable> a5;
|
||||
Defaulted_SW_NeedyTemplate6<SWS_NonMovable> a6;
|
||||
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<NonMovable> > b1;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<S_NonMovable> > b2;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<W_NonMovable> > b3;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<WS_NonMovable> > b4;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<SW_NonMovable> > b5;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<SWS_NonMovable> > b6;
|
||||
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<NonMovable> > c1;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<S_NonMovable> > c2;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<W_NonMovable> > c3;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<WS_NonMovable> > c4;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<SW_NonMovable> > c5;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<SWS_NonMovable> > c6;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<Movable> > c7;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<S_Movable> > c8;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<W_Movable> > c9;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<WS_Movable> > c10;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<SW_Movable> > c11;
|
||||
Defaulted_SW_NeedyTemplate6<Template_NonMovable<SWS_Movable> > c12;
|
||||
|
||||
Defaulted_SW_NeedyTemplate6<> c13;
|
||||
}
|
||||
|
||||
void good6() {
|
||||
Defaulted_SW_NeedyTemplate6<Movable> a1;
|
||||
Defaulted_SW_NeedyTemplate6<S_Movable> a2;
|
||||
Defaulted_SW_NeedyTemplate6<W_Movable> a3;
|
||||
Defaulted_SW_NeedyTemplate6<WS_Movable> a4;
|
||||
Defaulted_SW_NeedyTemplate6<SW_Movable> a5;
|
||||
Defaulted_SW_NeedyTemplate6<SWS_Movable> a6;
|
||||
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<Movable> > b1;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<S_Movable> > b2;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<W_Movable> > b3;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<WS_Movable> > b4;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<SW_Movable> > b5;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<Movable> > c1;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<S_Movable> > c2;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<W_Movable> > c3;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<WS_Movable> > c4;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<SW_Movable> > c5;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<SWS_Movable> > c6;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<NonMovable> > c7;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<S_NonMovable> > c8;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<W_NonMovable> > c9;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<WS_NonMovable> > c10;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<SW_NonMovable> > c11;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<Movable> > d1;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<S_Movable> > d2;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<W_Movable> > d3;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<WS_Movable> > d4;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<SW_Movable> > d5;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<SWS_Movable> > d6;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<NonMovable> > d7;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<S_NonMovable> > d8;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<W_NonMovable> > d9;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<WS_NonMovable> > d10;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<SW_NonMovable> > d11;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
//
|
||||
// 7 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate7 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate7<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
template <class T, class Q = NeedyTemplate7<T> >
|
||||
struct Defaulted_Templated_NeedyTemplate7 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate7<{{.*}}>' requested here}}
|
||||
void bad7() {
|
||||
Defaulted_Templated_NeedyTemplate7<NonMovable> a1;
|
||||
Defaulted_Templated_NeedyTemplate7<S_NonMovable> a2;
|
||||
Defaulted_Templated_NeedyTemplate7<W_NonMovable> a3;
|
||||
Defaulted_Templated_NeedyTemplate7<WS_NonMovable> a4;
|
||||
Defaulted_Templated_NeedyTemplate7<SW_NonMovable> a5;
|
||||
Defaulted_Templated_NeedyTemplate7<SWS_NonMovable> a6;
|
||||
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<NonMovable> > b1;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<S_NonMovable> > b2;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<W_NonMovable> > b3;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<WS_NonMovable> > b4;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<SW_NonMovable> > b5;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<SWS_NonMovable> > b6;
|
||||
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<NonMovable> > c1;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<S_NonMovable> > c2;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<W_NonMovable> > c3;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<WS_NonMovable> > c4;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SW_NonMovable> > c5;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SWS_NonMovable> > c6;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<Movable> > c7;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<S_Movable> > c8;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<W_Movable> > c9;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<WS_Movable> > c10;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SW_Movable> > c11;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SWS_Movable> > c12;
|
||||
}
|
||||
|
||||
void good7() {
|
||||
Defaulted_Templated_NeedyTemplate7<Movable> a1;
|
||||
Defaulted_Templated_NeedyTemplate7<S_Movable> a2;
|
||||
Defaulted_Templated_NeedyTemplate7<W_Movable> a3;
|
||||
Defaulted_Templated_NeedyTemplate7<WS_Movable> a4;
|
||||
Defaulted_Templated_NeedyTemplate7<SW_Movable> a5;
|
||||
Defaulted_Templated_NeedyTemplate7<SWS_Movable> a6;
|
||||
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<Movable> > b1;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<S_Movable> > b2;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<W_Movable> > b3;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<WS_Movable> > b4;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<SW_Movable> > b5;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<Movable> > c1;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<S_Movable> > c2;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<W_Movable> > c3;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<WS_Movable> > c4;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<SW_Movable> > c5;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<SWS_Movable> > c6;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<NonMovable> > c7;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<S_NonMovable> > c8;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<W_NonMovable> > c9;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<WS_NonMovable> > c10;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<SW_NonMovable> > c11;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<Movable> > d1;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<S_Movable> > d2;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<W_Movable> > d3;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<WS_Movable> > d4;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<SW_Movable> > d5;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<SWS_Movable> > d6;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<NonMovable> > d7;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<S_NonMovable> > d8;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<W_NonMovable> > d9;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<WS_NonMovable> > d10;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<SW_NonMovable> > d11;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
//
|
||||
// 8 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate8 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate8<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
|
||||
template <class T, class Q = NeedyTemplate8<T> >
|
||||
struct Defaulted_Templated_NeedyTemplate8 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate8<{{.*}}>' requested here}}
|
||||
template <class T>
|
||||
struct W_Defaulted_Templated_NeedyTemplate8 {
|
||||
Defaulted_Templated_NeedyTemplate8<T> m;
|
||||
};
|
||||
void bad8() {
|
||||
W_Defaulted_Templated_NeedyTemplate8<NonMovable> a1;
|
||||
W_Defaulted_Templated_NeedyTemplate8<S_NonMovable> a2;
|
||||
W_Defaulted_Templated_NeedyTemplate8<W_NonMovable> a3;
|
||||
W_Defaulted_Templated_NeedyTemplate8<WS_NonMovable> a4;
|
||||
W_Defaulted_Templated_NeedyTemplate8<SW_NonMovable> a5;
|
||||
W_Defaulted_Templated_NeedyTemplate8<SWS_NonMovable> a6;
|
||||
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<NonMovable> > b1;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<S_NonMovable> > b2;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<W_NonMovable> > b3;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<WS_NonMovable> > b4;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SW_NonMovable> > b5;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SWS_NonMovable> > b6;
|
||||
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<NonMovable> > c1;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<S_NonMovable> > c2;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<W_NonMovable> > c3;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<WS_NonMovable> > c4;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SW_NonMovable> > c5;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SWS_NonMovable> > c6;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<Movable> > c7;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<S_Movable> > c8;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<W_Movable> > c9;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<WS_Movable> > c10;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SW_Movable> > c11;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SWS_Movable> > c12;
|
||||
}
|
||||
|
||||
void good8() {
|
||||
W_Defaulted_Templated_NeedyTemplate8<Movable> a1;
|
||||
W_Defaulted_Templated_NeedyTemplate8<S_Movable> a2;
|
||||
W_Defaulted_Templated_NeedyTemplate8<W_Movable> a3;
|
||||
W_Defaulted_Templated_NeedyTemplate8<WS_Movable> a4;
|
||||
W_Defaulted_Templated_NeedyTemplate8<SW_Movable> a5;
|
||||
W_Defaulted_Templated_NeedyTemplate8<SWS_Movable> a6;
|
||||
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<Movable> > b1;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<S_Movable> > b2;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<W_Movable> > b3;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<WS_Movable> > b4;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SW_Movable> > b5;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SWS_Movable> > b6;
|
||||
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<Movable> > c1;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<S_Movable> > c2;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<W_Movable> > c3;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<WS_Movable> > c4;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SW_Movable> > c5;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SWS_Movable> > c6;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<NonMovable> > c7;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<S_NonMovable> > c8;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<W_NonMovable> > c9;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<WS_NonMovable> > c10;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SW_NonMovable> > c11;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SWS_NonMovable> > c12;
|
||||
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<Movable> > d1;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<S_Movable> > d2;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<W_Movable> > d3;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<WS_Movable> > d4;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SW_Movable> > d5;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SWS_Movable> > d6;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<NonMovable> > d7;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<S_NonMovable> > d8;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<W_NonMovable> > d9;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<WS_NonMovable> > d10;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SW_NonMovable> > d11;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SWS_NonMovable> > d12;
|
||||
}
|
||||
|
||||
/*
|
||||
SpecializedNonMovable is a non-movable class which has an explicit specialization of NeedyTemplate
|
||||
for it. Instantiations of NeedyTemplateN<SpecializedNonMovable> should be legal as the explicit
|
||||
specialization isn't annotated with MOZ_NEEDS_MEMMOVABLE_TYPE.
|
||||
|
||||
However, as it is MOZ_NON_MEMMOVABLE, derived classes and members shouldn't be able to be used to
|
||||
instantiate NeedyTemplate.
|
||||
*/
|
||||
|
||||
struct MOZ_NON_MEMMOVABLE SpecializedNonMovable {}; // expected-note 8 {{'S_SpecializedNonMovable' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'SpecializedNonMovable'}} expected-note 8 {{'Template_Inline<SpecializedNonMovable>' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'SpecializedNonMovable'}}
|
||||
struct S_SpecializedNonMovable : SpecializedNonMovable {};
|
||||
|
||||
// Specialize all of the NeedyTemplates with SpecializedNonMovable.
|
||||
template <>
|
||||
struct NeedyTemplate1<SpecializedNonMovable> {};
|
||||
template <>
|
||||
struct NeedyTemplate2<SpecializedNonMovable> {};
|
||||
template <>
|
||||
struct NeedyTemplate3<SpecializedNonMovable> {};
|
||||
template <>
|
||||
struct NeedyTemplate4<SpecializedNonMovable> {};
|
||||
template <>
|
||||
struct NeedyTemplate5<SpecializedNonMovable> {};
|
||||
template <>
|
||||
struct NeedyTemplate6<SpecializedNonMovable> {};
|
||||
template <>
|
||||
struct NeedyTemplate7<SpecializedNonMovable> {};
|
||||
template <>
|
||||
struct NeedyTemplate8<SpecializedNonMovable> {};
|
||||
|
||||
void specialization() {
|
||||
/*
|
||||
SpecializedNonMovable has a specialization for every variant of NeedyTemplate,
|
||||
so these templates are valid, even though SpecializedNonMovable isn't
|
||||
memmovable
|
||||
*/
|
||||
NeedyTemplate1<SpecializedNonMovable> a1;
|
||||
S_NeedyTemplate2<SpecializedNonMovable> a2;
|
||||
W_NeedyTemplate3<SpecializedNonMovable> a3;
|
||||
WS_NeedyTemplate4<SpecializedNonMovable> a4;
|
||||
SW_NeedyTemplate5<SpecializedNonMovable> a5;
|
||||
Defaulted_SW_NeedyTemplate6<SpecializedNonMovable> a6;
|
||||
Defaulted_Templated_NeedyTemplate7<SpecializedNonMovable> a7;
|
||||
W_Defaulted_Templated_NeedyTemplate8<SpecializedNonMovable> a8;
|
||||
|
||||
/*
|
||||
These entries contain an element which is SpecializedNonMovable, and are non-movable
|
||||
as there is no valid specialization, and their member is non-memmovable
|
||||
*/
|
||||
NeedyTemplate1<Template_Inline<SpecializedNonMovable> > b1; // expected-note {{instantiation of 'NeedyTemplate1<Template_Inline<SpecializedNonMovable> >' requested here}}
|
||||
S_NeedyTemplate2<Template_Inline<SpecializedNonMovable> > b2;
|
||||
W_NeedyTemplate3<Template_Inline<SpecializedNonMovable> > b3;
|
||||
WS_NeedyTemplate4<Template_Inline<SpecializedNonMovable> > b4;
|
||||
SW_NeedyTemplate5<Template_Inline<SpecializedNonMovable> > b5;
|
||||
Defaulted_SW_NeedyTemplate6<Template_Inline<SpecializedNonMovable> > b6;
|
||||
Defaulted_Templated_NeedyTemplate7<Template_Inline<SpecializedNonMovable> > b7;
|
||||
W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SpecializedNonMovable> > b8;
|
||||
|
||||
/*
|
||||
The subclass of SpecializedNonMovable, is also non-memmovable,
|
||||
as there is no valid specialization.
|
||||
*/
|
||||
NeedyTemplate1<S_SpecializedNonMovable> c1; // expected-note {{instantiation of 'NeedyTemplate1<S_SpecializedNonMovable>' requested here}}
|
||||
S_NeedyTemplate2<S_SpecializedNonMovable> c2;
|
||||
W_NeedyTemplate3<S_SpecializedNonMovable> c3;
|
||||
WS_NeedyTemplate4<S_SpecializedNonMovable> c4;
|
||||
SW_NeedyTemplate5<S_SpecializedNonMovable> c5;
|
||||
Defaulted_SW_NeedyTemplate6<S_SpecializedNonMovable> c6;
|
||||
Defaulted_Templated_NeedyTemplate7<S_SpecializedNonMovable> c7;
|
||||
W_Defaulted_Templated_NeedyTemplate8<S_SpecializedNonMovable> c8;
|
||||
}
|
@ -18,7 +18,7 @@ void misuseStackClass(int len) {
|
||||
Stack valid;
|
||||
Stack alsoValid[2];
|
||||
static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}}
|
||||
static Stack alsoNotValid[2]; // expected-error {{variable of type 'Stack [2]' only valid on the stack}}
|
||||
static Stack alsoNotValid[2]; // expected-error {{variable of type 'Stack [2]' only valid on the stack}} expected-note {{'Stack [2]' is a stack type because it is an array of stack type 'Stack'}}
|
||||
|
||||
gobble(&valid);
|
||||
gobble(¬Valid);
|
||||
@ -35,7 +35,7 @@ void misuseStackClass(int len) {
|
||||
|
||||
Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}}
|
||||
struct RandomClass {
|
||||
Stack nonstaticMember; // expected-note {{'RandomClass' is a stack class because member 'nonstaticMember' is a stack class 'Stack'}}
|
||||
Stack nonstaticMember; // expected-note {{'RandomClass' is a stack type because member 'nonstaticMember' is a stack type 'Stack'}}
|
||||
static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}}
|
||||
};
|
||||
struct MOZ_STACK_CLASS RandomStackClass {
|
||||
@ -43,7 +43,7 @@ struct MOZ_STACK_CLASS RandomStackClass {
|
||||
static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}}
|
||||
};
|
||||
|
||||
struct BadInherit : Stack {}; // expected-note {{'BadInherit' is a stack class because it inherits from a stack class 'Stack'}}
|
||||
struct BadInherit : Stack {}; // expected-note {{'BadInherit' is a stack type because it inherits from a stack type 'Stack'}}
|
||||
struct MOZ_STACK_CLASS GoodInherit : Stack {};
|
||||
|
||||
BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}}
|
||||
|
@ -9,13 +9,16 @@ SOURCES += [
|
||||
'TestCustomHeap.cpp',
|
||||
'TestExplicitOperatorBool.cpp',
|
||||
'TestGlobalClass.cpp',
|
||||
'TestMultipleAnnotations.cpp',
|
||||
'TestMustOverride.cpp',
|
||||
'TestMustUse.cpp',
|
||||
'TestNANTestingExpr.cpp',
|
||||
'TestNANTestingExprC.c',
|
||||
'TestNeedsNoVTableType.cpp',
|
||||
'TestNoAddRefReleaseOnReturn.cpp',
|
||||
'TestNoArithmeticExprInArgument.cpp',
|
||||
'TestNonHeapClass.cpp',
|
||||
'TestNonMemMovable.cpp',
|
||||
'TestNoRefcountedInsideLambdas.cpp',
|
||||
'TestStackClass.cpp',
|
||||
'TestTrivialCtorDtor.cpp',
|
||||
|
@ -109,6 +109,7 @@ class MachCommands(MachCommandBase):
|
||||
'--show-possibly-lost=no',
|
||||
'--track-origins=yes',
|
||||
'--trace-children=yes',
|
||||
'-v', # Enable verbosity to get the list of used suppressions
|
||||
]
|
||||
|
||||
for s in suppressions:
|
||||
|
@ -1710,20 +1710,22 @@ nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
|
||||
}
|
||||
|
||||
uint32_t loadType = LOAD_NORMAL;
|
||||
nsCOMPtr<nsIPrincipal> requestingPrincipal;
|
||||
if (aLoadInfo) {
|
||||
nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
|
||||
(void)aLoadInfo->GetLoadType(<);
|
||||
// Get the appropriate LoadType from nsIDocShellLoadInfo type
|
||||
loadType = ConvertDocShellLoadInfoToLoadType(lt);
|
||||
|
||||
nsCOMPtr<nsISupports> owner;
|
||||
aLoadInfo->GetOwner(getter_AddRefs(owner));
|
||||
requestingPrincipal = do_QueryInterface(owner);
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
|
||||
|
||||
mLoadType = loadType;
|
||||
|
||||
nsCOMPtr<nsISupports> owner;
|
||||
aLoadInfo->GetOwner(getter_AddRefs(owner));
|
||||
nsCOMPtr<nsIPrincipal> requestingPrincipal = do_QueryInterface(owner);
|
||||
if (!requestingPrincipal) {
|
||||
requestingPrincipal = nsContentUtils::GetSystemPrincipal();
|
||||
}
|
||||
@ -2953,129 +2955,16 @@ nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
|
||||
nsresult
|
||||
nsDocShell::PopProfileTimelineMarkers(
|
||||
JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aProfileTimelineMarkers)
|
||||
JS::MutableHandle<JS::Value> aOut)
|
||||
{
|
||||
// Looping over all markers gathered so far at the docShell level, whenever a
|
||||
// START marker is found, look for the corresponding END marker and build a
|
||||
// {name,start,end} JS object.
|
||||
// Paint markers are different because paint is handled at root docShell level
|
||||
// in the information that a paint was done is then stored at each sub
|
||||
// docShell level but we can only be sure that a paint did happen in a
|
||||
// docShell if an Layer marker type was recorded too.
|
||||
nsTArray<dom::ProfileTimelineMarker> store;
|
||||
SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
|
||||
|
||||
nsTArray<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
|
||||
SequenceRooter<mozilla::dom::ProfileTimelineMarker> rooter(
|
||||
aCx, &profileTimelineMarkers);
|
||||
|
||||
if (!IsObserved()) {
|
||||
if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
if (IsObserved()) {
|
||||
mObserved->PopMarkers(aCx, store);
|
||||
}
|
||||
|
||||
nsTArray<UniquePtr<TimelineMarker>>& markersStore = mObserved.get()->mTimelineMarkers;
|
||||
|
||||
// If we see an unpaired START, we keep it around for the next call
|
||||
// to PopProfileTimelineMarkers. We store the kept START objects in
|
||||
// this array.
|
||||
nsTArray<UniquePtr<TimelineMarker>> keptMarkers;
|
||||
|
||||
for (uint32_t i = 0; i < markersStore.Length(); ++i) {
|
||||
UniquePtr<TimelineMarker>& startPayload = markersStore[i];
|
||||
const char* startMarkerName = startPayload->GetName();
|
||||
|
||||
bool hasSeenPaintedLayer = false;
|
||||
bool isPaint = strcmp(startMarkerName, "Paint") == 0;
|
||||
|
||||
// If we are processing a Paint marker, we append information from
|
||||
// all the embedded Layer markers to this array.
|
||||
dom::Sequence<dom::ProfileTimelineLayerRect> layerRectangles;
|
||||
|
||||
// If this is a TRACING_TIMESTAMP marker, there's no corresponding "end"
|
||||
// marker, as it's a single unit of time, not a duration, create the final
|
||||
// marker here.
|
||||
if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
|
||||
mozilla::dom::ProfileTimelineMarker* marker =
|
||||
profileTimelineMarkers.AppendElement();
|
||||
|
||||
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
|
||||
marker->mStart = startPayload->GetTime();
|
||||
marker->mEnd = startPayload->GetTime();
|
||||
marker->mStack = startPayload->GetStack();
|
||||
startPayload->AddDetails(aCx, *marker);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
|
||||
bool hasSeenEnd = false;
|
||||
|
||||
// DOM events can be nested, so we must take care when searching
|
||||
// for the matching end. It doesn't hurt to apply this logic to
|
||||
// all event types.
|
||||
uint32_t markerDepth = 0;
|
||||
|
||||
// The assumption is that the devtools timeline flushes markers frequently
|
||||
// enough for the amount of markers to always be small enough that the
|
||||
// nested for loop isn't going to be a performance problem.
|
||||
for (uint32_t j = i + 1; j < markersStore.Length(); ++j) {
|
||||
UniquePtr<TimelineMarker>& endPayload = markersStore[j];
|
||||
const char* endMarkerName = endPayload->GetName();
|
||||
|
||||
// Look for Layer markers to stream out paint markers.
|
||||
if (isPaint && strcmp(endMarkerName, "Layer") == 0) {
|
||||
hasSeenPaintedLayer = true;
|
||||
endPayload->AddLayerRectangles(layerRectangles);
|
||||
}
|
||||
|
||||
if (!startPayload->Equals(*endPayload)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Pair start and end markers.
|
||||
if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
|
||||
++markerDepth;
|
||||
} else if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
|
||||
if (markerDepth > 0) {
|
||||
--markerDepth;
|
||||
} else {
|
||||
// But ignore paint start/end if no layer has been painted.
|
||||
if (!isPaint || (isPaint && hasSeenPaintedLayer)) {
|
||||
mozilla::dom::ProfileTimelineMarker* marker =
|
||||
profileTimelineMarkers.AppendElement();
|
||||
|
||||
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
|
||||
marker->mStart = startPayload->GetTime();
|
||||
marker->mEnd = endPayload->GetTime();
|
||||
marker->mStack = startPayload->GetStack();
|
||||
if (isPaint) {
|
||||
marker->mRectangles.Construct(layerRectangles);
|
||||
}
|
||||
startPayload->AddDetails(aCx, *marker);
|
||||
endPayload->AddDetails(aCx, *marker);
|
||||
}
|
||||
|
||||
// We want the start to be dropped either way.
|
||||
hasSeenEnd = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we did not see the corresponding END, keep the START.
|
||||
if (!hasSeenEnd) {
|
||||
keptMarkers.AppendElement(Move(markersStore[i]));
|
||||
markersStore.RemoveElementAt(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
markersStore.SwapElements(keptMarkers);
|
||||
|
||||
if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
|
||||
if (!ToJSValue(aCx, store, aOut)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
@ -34,4 +34,101 @@ ObservedDocShell::ClearMarkers()
|
||||
mTimelineMarkers.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
ObservedDocShell::PopMarkers(JSContext* aCx,
|
||||
nsTArray<dom::ProfileTimelineMarker>& aStore)
|
||||
{
|
||||
// If we see an unpaired START, we keep it around for the next call
|
||||
// to ObservedDocShell::PopMarkers. We store the kept START objects here.
|
||||
nsTArray<UniquePtr<TimelineMarker>> keptStartMarkers;
|
||||
|
||||
for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
|
||||
UniquePtr<TimelineMarker>& startPayload = mTimelineMarkers[i];
|
||||
|
||||
// If this is a TRACING_TIMESTAMP marker, there's no corresponding END
|
||||
// as it's a single unit of time, not a duration.
|
||||
if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
|
||||
dom::ProfileTimelineMarker* marker = aStore.AppendElement();
|
||||
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
|
||||
marker->mStart = startPayload->GetTime();
|
||||
marker->mEnd = startPayload->GetTime();
|
||||
marker->mStack = startPayload->GetStack();
|
||||
startPayload->AddDetails(aCx, *marker);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Whenever a START marker is found, look for the corresponding END
|
||||
// and build a {name,start,end} JS object.
|
||||
if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
|
||||
bool hasSeenEnd = false;
|
||||
|
||||
// "Paint" markers are different because painting is handled at root
|
||||
// docshell level. The information that a paint was done is stored at
|
||||
// sub-docshell level, but we can only be sure that a paint did actually
|
||||
// happen in if a "Layer" marker was recorded too.
|
||||
bool startIsPaintType = strcmp(startPayload->GetName(), "Paint") == 0;
|
||||
bool hasSeenLayerType = false;
|
||||
|
||||
// If we are processing a "Paint" marker, we append information from
|
||||
// all the embedded "Layer" markers to this array.
|
||||
dom::Sequence<dom::ProfileTimelineLayerRect> layerRectangles;
|
||||
|
||||
// DOM events can be nested, so we must take care when searching
|
||||
// for the matching end. It doesn't hurt to apply this logic to
|
||||
// all event types.
|
||||
uint32_t markerDepth = 0;
|
||||
|
||||
// The assumption is that the devtools timeline flushes markers frequently
|
||||
// enough for the amount of markers to always be small enough that the
|
||||
// nested for loop isn't going to be a performance problem.
|
||||
for (uint32_t j = i + 1; j < mTimelineMarkers.Length(); ++j) {
|
||||
UniquePtr<TimelineMarker>& endPayload = mTimelineMarkers[j];
|
||||
bool endIsLayerType = strcmp(endPayload->GetName(), "Layer") == 0;
|
||||
|
||||
// Look for "Layer" markers to stream out "Paint" markers.
|
||||
if (startIsPaintType && endIsLayerType) {
|
||||
hasSeenLayerType = true;
|
||||
endPayload->AddLayerRectangles(layerRectangles);
|
||||
}
|
||||
if (!startPayload->Equals(*endPayload)) {
|
||||
continue;
|
||||
}
|
||||
if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
|
||||
++markerDepth;
|
||||
continue;
|
||||
}
|
||||
if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
|
||||
if (markerDepth > 0) {
|
||||
--markerDepth;
|
||||
continue;
|
||||
}
|
||||
if (!startIsPaintType || (startIsPaintType && hasSeenLayerType)) {
|
||||
dom::ProfileTimelineMarker* marker = aStore.AppendElement();
|
||||
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
|
||||
marker->mStart = startPayload->GetTime();
|
||||
marker->mEnd = endPayload->GetTime();
|
||||
marker->mStack = startPayload->GetStack();
|
||||
if (hasSeenLayerType) {
|
||||
marker->mRectangles.Construct(layerRectangles);
|
||||
}
|
||||
startPayload->AddDetails(aCx, *marker);
|
||||
endPayload->AddDetails(aCx, *marker);
|
||||
}
|
||||
hasSeenEnd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we did not see the corresponding END, keep the START.
|
||||
if (!hasSeenEnd) {
|
||||
keptStartMarkers.AppendElement(Move(mTimelineMarkers[i]));
|
||||
mTimelineMarkers.RemoveElementAt(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mTimelineMarkers.SwapElements(keptStartMarkers);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -15,6 +15,9 @@ class nsDocShell;
|
||||
class TimelineMarker;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
struct ProfileTimelineMarker;
|
||||
}
|
||||
|
||||
// # ObservedDocShell
|
||||
//
|
||||
@ -24,18 +27,16 @@ class ObservedDocShell : public LinkedListElement<ObservedDocShell>
|
||||
{
|
||||
private:
|
||||
nsRefPtr<nsDocShell> mDocShell;
|
||||
|
||||
public:
|
||||
// FIXME: make this private once all marker-specific logic has been
|
||||
// moved out of nsDocShell.
|
||||
nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
|
||||
|
||||
public:
|
||||
explicit ObservedDocShell(nsDocShell* aDocShell);
|
||||
nsDocShell* operator*() const { return mDocShell.get(); }
|
||||
|
||||
void AddMarker(const char* aName, TracingMetadata aMetaData);
|
||||
void AddMarker(UniquePtr<TimelineMarker>&& aMarker);
|
||||
void ClearMarkers();
|
||||
void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -2728,8 +2728,52 @@ Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
|
||||
const Optional<Sequence<MediaKeySystemOptions>>& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString logMsg;
|
||||
logMsg.AppendPrintf("Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=[",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
if (aOptions.WasPassed()) {
|
||||
const Sequence<MediaKeySystemOptions>& options = aOptions.Value();
|
||||
for (size_t i = 0; i < options.Length(); i++) {
|
||||
const MediaKeySystemOptions& op = options[i];
|
||||
if (i > 0) {
|
||||
logMsg.AppendLiteral(",");
|
||||
}
|
||||
logMsg.AppendLiteral("{");
|
||||
logMsg.AppendPrintf("stateful='%s'",
|
||||
MediaKeysRequirementValues::strings[(size_t)op.mStateful].value);
|
||||
|
||||
logMsg.AppendPrintf(", uniqueIdentifier='%s'",
|
||||
MediaKeysRequirementValues::strings[(size_t)op.mUniqueidentifier].value);
|
||||
|
||||
if (!op.mAudioCapability.IsEmpty()) {
|
||||
logMsg.AppendPrintf(", audioCapability='%s'",
|
||||
NS_ConvertUTF16toUTF8(op.mAudioCapability).get());
|
||||
}
|
||||
if (!op.mAudioType.IsEmpty()) {
|
||||
logMsg.AppendPrintf(", audioType='%s'",
|
||||
NS_ConvertUTF16toUTF8(op.mAudioType).get());
|
||||
}
|
||||
if (!op.mInitDataType.IsEmpty()) {
|
||||
logMsg.AppendPrintf(", initDataType='%s'",
|
||||
NS_ConvertUTF16toUTF8(op.mInitDataType).get());
|
||||
}
|
||||
if (!op.mVideoCapability.IsEmpty()) {
|
||||
logMsg.AppendPrintf(", videoCapability='%s'",
|
||||
NS_ConvertUTF16toUTF8(op.mVideoCapability).get());
|
||||
}
|
||||
if (!op.mVideoType.IsEmpty()) {
|
||||
logMsg.AppendPrintf(", videoType='%s'",
|
||||
NS_ConvertUTF16toUTF8(op.mVideoType).get());
|
||||
}
|
||||
logMsg.AppendLiteral("}");
|
||||
}
|
||||
}
|
||||
logMsg.AppendPrintf("])");
|
||||
EME_LOG(logMsg.get());
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
|
||||
nsRefPtr<DetailedPromise> promise = DetailedPromise::Create(go, aRv);
|
||||
nsRefPtr<DetailedPromise> promise = DetailedPromise::Create(go, aRv,
|
||||
NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess"));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -9,11 +9,13 @@
|
||||
#include "mozilla/dom/MimeTypeArrayBinding.h"
|
||||
#include "mozilla/dom/MimeTypeBinding.h"
|
||||
#include "nsIDOMNavigator.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPluginArray.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "Navigator.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsPluginTags.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -216,19 +218,22 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeType, mWindow, mPluginElement)
|
||||
|
||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
|
||||
uint32_t aPluginTagMimeIndex, const nsAString& aType)
|
||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow,
|
||||
nsPluginElement* aPluginElement,
|
||||
const nsAString& aType,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aExtension)
|
||||
: mWindow(aWindow),
|
||||
mPluginElement(aPluginElement),
|
||||
mPluginTagMimeIndex(aPluginTagMimeIndex),
|
||||
mType(aType)
|
||||
mType(aType),
|
||||
mDescription(aDescription),
|
||||
mExtension(aExtension)
|
||||
{
|
||||
}
|
||||
|
||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aType)
|
||||
: mWindow(aWindow),
|
||||
mPluginElement(nullptr),
|
||||
mPluginTagMimeIndex(0),
|
||||
mType(aType)
|
||||
{
|
||||
}
|
||||
@ -251,14 +256,9 @@ nsMimeType::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
}
|
||||
|
||||
void
|
||||
nsMimeType::GetDescription(nsString& retval) const
|
||||
nsMimeType::GetDescription(nsString& aRetval) const
|
||||
{
|
||||
retval.Truncate();
|
||||
|
||||
if (mPluginElement) {
|
||||
CopyUTF8toUTF16(mPluginElement->PluginTag()->
|
||||
mMimeDescriptions[mPluginTagMimeIndex], retval);
|
||||
}
|
||||
aRetval = mDescription;
|
||||
}
|
||||
|
||||
nsPluginElement*
|
||||
@ -269,14 +269,9 @@ nsMimeType::GetEnabledPlugin() const
|
||||
}
|
||||
|
||||
void
|
||||
nsMimeType::GetSuffixes(nsString& retval) const
|
||||
nsMimeType::GetSuffixes(nsString& aRetval) const
|
||||
{
|
||||
retval.Truncate();
|
||||
|
||||
if (mPluginElement) {
|
||||
CopyUTF8toUTF16(mPluginElement->PluginTag()->
|
||||
mExtensions[mPluginTagMimeIndex], retval);
|
||||
}
|
||||
aRetval = mExtension;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -58,8 +58,11 @@ public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsMimeType)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsMimeType)
|
||||
|
||||
nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
|
||||
uint32_t aPluginTagMimeIndex, const nsAString& aMimeType);
|
||||
nsMimeType(nsPIDOMWindow* aWindow,
|
||||
nsPluginElement* aPluginElement,
|
||||
const nsAString& aType,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aExtension);
|
||||
nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aMimeType);
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
@ -85,8 +88,9 @@ protected:
|
||||
// mimetype array. We rely on the cycle collector to break this
|
||||
// cycle.
|
||||
nsRefPtr<nsPluginElement> mPluginElement;
|
||||
uint32_t mPluginTagMimeIndex;
|
||||
nsString mType;
|
||||
nsString mDescription;
|
||||
nsString mExtension;
|
||||
};
|
||||
|
||||
#endif /* nsMimeTypeArray_h___ */
|
||||
|
@ -130,7 +130,7 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
||||
// that plugins did not change and was not reloaded
|
||||
if (pluginHost->ReloadPlugins() ==
|
||||
NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
|
||||
nsTArray<nsRefPtr<nsPluginTag> > newPluginTags;
|
||||
nsTArray<nsCOMPtr<nsIInternalPluginTag> > newPluginTags;
|
||||
pluginHost->GetPlugins(newPluginTags);
|
||||
|
||||
// Check if the number of plugins we know about are different from
|
||||
@ -279,7 +279,7 @@ operator<(const nsRefPtr<nsPluginElement>& lhs,
|
||||
const nsRefPtr<nsPluginElement>& rhs)
|
||||
{
|
||||
// Sort plugins alphabetically by name.
|
||||
return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
|
||||
return lhs->PluginTag()->Name() < rhs->PluginTag()->Name();
|
||||
}
|
||||
|
||||
void
|
||||
@ -296,14 +296,13 @@ nsPluginArray::EnsurePlugins()
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
|
||||
nsTArray<nsCOMPtr<nsIInternalPluginTag> > pluginTags;
|
||||
pluginHost->GetPlugins(pluginTags);
|
||||
|
||||
// need to wrap each of these with a nsPluginElement, which is
|
||||
// scriptable.
|
||||
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
||||
nsPluginTag* pluginTag = pluginTags[i];
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTag));
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
}
|
||||
|
||||
// Alphabetize the enumeration order of non-hidden plugins to reduce
|
||||
@ -323,7 +322,7 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
|
||||
|
||||
nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
|
||||
nsPluginTag* aPluginTag)
|
||||
nsIInternalPluginTag* aPluginTag)
|
||||
: mWindow(aWindow),
|
||||
mPluginTag(aPluginTag)
|
||||
{
|
||||
@ -349,25 +348,25 @@ nsPluginElement::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
void
|
||||
nsPluginElement::GetDescription(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mDescription, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->Description(), retval);
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginElement::GetFilename(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mFileName, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->FileName(), retval);
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginElement::GetVersion(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mVersion, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->Version(), retval);
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginElement::GetName(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mName, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->Name(), retval);
|
||||
}
|
||||
|
||||
nsMimeType*
|
||||
@ -452,8 +451,18 @@ nsPluginElement::EnsurePluginMimeTypes()
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) {
|
||||
NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]);
|
||||
mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type));
|
||||
if (mPluginTag->MimeTypes().Length() != mPluginTag->MimeDescriptions().Length() ||
|
||||
mPluginTag->MimeTypes().Length() != mPluginTag->Extensions().Length()) {
|
||||
MOZ_ASSERT(false, "mime type arrays expected to be the same length");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPluginTag->MimeTypes().Length(); ++i) {
|
||||
NS_ConvertUTF8toUTF16 type(mPluginTag->MimeTypes()[i]);
|
||||
NS_ConvertUTF8toUTF16 description(mPluginTag->MimeDescriptions()[i]);
|
||||
NS_ConvertUTF8toUTF16 extension(mPluginTag->Extensions()[i]);
|
||||
|
||||
mMimeTypes.AppendElement(new nsMimeType(mWindow, this, type, description,
|
||||
extension));
|
||||
}
|
||||
}
|
||||
|
@ -11,11 +11,11 @@
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsPluginTags.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
class nsPluginElement;
|
||||
class nsMimeType;
|
||||
class nsIInternalPluginTag;
|
||||
|
||||
class nsPluginArray final : public nsIObserver,
|
||||
public nsSupportsWeakReference,
|
||||
@ -70,12 +70,12 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPluginElement)
|
||||
|
||||
nsPluginElement(nsPIDOMWindow* aWindow, nsPluginTag* aPluginTag);
|
||||
nsPluginElement(nsPIDOMWindow* aWindow, nsIInternalPluginTag* aPluginTag);
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsPluginTag* PluginTag() const
|
||||
nsIInternalPluginTag* PluginTag() const
|
||||
{
|
||||
return mPluginTag;
|
||||
}
|
||||
@ -102,7 +102,7 @@ protected:
|
||||
void EnsurePluginMimeTypes();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
nsRefPtr<nsPluginTag> mPluginTag;
|
||||
nsCOMPtr<nsIInternalPluginTag> mPluginTag;
|
||||
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
|
||||
};
|
||||
|
||||
|
@ -960,6 +960,25 @@ DOMInterfaces = {
|
||||
'workers': True
|
||||
},
|
||||
|
||||
'PushManager': [{
|
||||
'workers': False,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::PushManager',
|
||||
}, {
|
||||
'workers': True,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::WorkerPushManager',
|
||||
}],
|
||||
|
||||
'PushSubscription': [{
|
||||
'workers': False,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
}, {
|
||||
'workers': True,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::WorkerPushSubscription',
|
||||
}],
|
||||
|
||||
'Range': {
|
||||
'nativeType': 'nsRange',
|
||||
'binaryNames': {
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
|
||||
@ -299,50 +298,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class PrefEnabledRunnable final : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
explicit PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate)
|
||||
, mEnabled(false)
|
||||
{ }
|
||||
|
||||
bool MainThreadRun() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
mEnabled = Preferences::GetBool("dom.broadcastChannel.enabled", false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsEnabled() const
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mEnabled;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/* static */ bool
|
||||
BroadcastChannel::IsEnabled(JSContext* aCx, JSObject* aGlobal)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
return Preferences::GetBool("dom.broadcastChannel.enabled", false);
|
||||
}
|
||||
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<PrefEnabledRunnable> runnable =
|
||||
new PrefEnabledRunnable(workerPrivate);
|
||||
runnable->Dispatch(workerPrivate->GetJSContext());
|
||||
|
||||
return runnable->IsEnabled();
|
||||
}
|
||||
|
||||
BroadcastChannel::BroadcastChannel(nsPIDOMWindow* aWindow,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
const nsACString& aOrigin,
|
||||
|
@ -47,8 +47,6 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BroadcastChannel,
|
||||
DOMEventTargetHelper)
|
||||
|
||||
static bool IsEnabled(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
onmessage = function() {
|
||||
var exists = true;
|
||||
try {
|
||||
var bc = new BroadcastChannel('foobar');
|
||||
} catch(e) {
|
||||
exists = false;
|
||||
}
|
||||
|
||||
postMessage({ exists: exists });
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
iframe_broadcastchannel.html
|
||||
broadcastchannel_pref_worker.js
|
||||
broadcastchannel_sharedWorker.js
|
||||
broadcastchannel_worker.js
|
||||
broadcastchannel_worker_alive.js
|
||||
@ -17,7 +16,6 @@ support-files =
|
||||
[test_broadcastchannel_basic.html]
|
||||
[test_broadcastchannel_close.html]
|
||||
[test_broadcastchannel_self.html]
|
||||
[test_broadcastchannel_pref.html]
|
||||
[test_broadcastchannel_sharedWorker.html]
|
||||
[test_broadcastchannel_worker.html]
|
||||
[test_broadcastchannel_worker_alive.html]
|
||||
|
@ -130,7 +130,7 @@ function runTest() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -55,7 +55,7 @@ function runTest() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -54,7 +54,7 @@ function runTest() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -84,8 +84,7 @@ var steps = [
|
||||
},
|
||||
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
SpecialPowers.pushPrefEnv({"set": [["network.disable.ipc.security", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", false],
|
||||
|
@ -84,8 +84,7 @@ var steps = [
|
||||
},
|
||||
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
|
||||
["network.disable.ipc.security", true],
|
||||
SpecialPowers.pushPrefEnv({"set": [["network.disable.ipc.security", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", false],
|
||||
|
@ -1,72 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for BroadcastChannel</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="content"></div>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
function testNoPref() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", false]]}, function() {
|
||||
ok(!("BroadcastChannel" in window), "BroadcastChannel should not exist");
|
||||
runTests();
|
||||
});
|
||||
}
|
||||
|
||||
function testPref() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, function() {
|
||||
ok("BroadcastChannel" in window, "BroadcastChannel should exist");
|
||||
runTests();
|
||||
});
|
||||
}
|
||||
|
||||
function testNoPrefWorker() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", false]]}, function() {
|
||||
var worker = new Worker("broadcastchannel_pref_worker.js");
|
||||
worker.onmessage = function(event) {
|
||||
ok(!event.data.exists, "BroadcastChannel should not exist in workers");
|
||||
runTests();
|
||||
}
|
||||
worker.postMessage('go!');
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefWorker() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, function() {
|
||||
var worker = new Worker("broadcastchannel_pref_worker.js");
|
||||
worker.onmessage = function(event) {
|
||||
ok(event.data.exists, "BroadcastChannel should exist in workers");
|
||||
runTests();
|
||||
}
|
||||
worker.postMessage('go!');
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
testNoPref,
|
||||
testPref,
|
||||
testNoPrefWorker,
|
||||
testPrefWorker
|
||||
];
|
||||
|
||||
function runTests() {
|
||||
if (tests.length == 0) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTests();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -109,7 +109,7 @@ function runTest() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -30,7 +30,7 @@ function runTest() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -44,8 +44,7 @@ function runTests() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
|
||||
["dom.workers.sharedWorkers.enabled", true]]}, runTests);
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.workers.sharedWorkers.enabled", true]]}, runTests);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -54,7 +54,7 @@ function runTests() {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTests);
|
||||
runTests();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user