зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound. a=merge
This commit is contained in:
Коммит
7941dfa396
|
@ -355,10 +355,12 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||||
{
|
{
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||||
|
|
||||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
|
||||||
if (accWrap) {
|
Accessible* child = accWrap->GetChildAt(i);
|
||||||
Accessible* acc = accWrap->GetChildAt(i);
|
return child ? GetNativeFromGeckoAccessible(child) : nil;
|
||||||
return acc ? GetNativeFromGeckoAccessible(acc) : nil;
|
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
|
||||||
|
ProxyAccessible* child = proxy->ChildAt(i);
|
||||||
|
return child ? GetNativeFromProxy(child) : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -849,12 +851,14 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||||
{
|
{
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||||
|
|
||||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
nsIntRect rect;
|
||||||
if (!accWrap)
|
if (AccessibleWrap* accWrap = [self getGeckoAccessible])
|
||||||
|
rect = accWrap->Bounds();
|
||||||
|
else if (ProxyAccessible* proxy = [self getProxyAccessible])
|
||||||
|
rect = proxy->Bounds();
|
||||||
|
else
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
nsIntRect rect = accWrap->Bounds();
|
|
||||||
|
|
||||||
NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
|
NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
|
||||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView);
|
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView);
|
||||||
NSPoint p = NSMakePoint(static_cast<CGFloat>(rect.x) / scaleFactor,
|
NSPoint p = NSMakePoint(static_cast<CGFloat>(rect.x) / scaleFactor,
|
||||||
|
@ -869,11 +873,14 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||||
{
|
{
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||||
|
|
||||||
AccessibleWrap* accWrap = [self getGeckoAccessible];
|
nsIntRect rect;
|
||||||
if (!accWrap)
|
if (AccessibleWrap* accWrap = [self getGeckoAccessible])
|
||||||
|
rect = accWrap->Bounds();
|
||||||
|
else if (ProxyAccessible* proxy = [self getProxyAccessible])
|
||||||
|
rect = proxy->Bounds();
|
||||||
|
else
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
nsIntRect rect = accWrap->Bounds();
|
|
||||||
CGFloat scaleFactor =
|
CGFloat scaleFactor =
|
||||||
nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]);
|
nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]);
|
||||||
return [NSValue valueWithSize:NSMakeSize(static_cast<CGFloat>(rect.width) / scaleFactor,
|
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);
|
pref("dom.mapped_arraybuffer.enabled", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BroadcastChannel API
|
|
||||||
pref("dom.broadcastChannel.enabled", true);
|
|
||||||
|
|
||||||
// SystemUpdate API
|
// SystemUpdate API
|
||||||
pref("dom.system_update.enabled", true);
|
pref("dom.system_update.enabled", true);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||||
|
|
|
@ -34,7 +34,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||||
FXOS_SIMULATOR=1
|
FXOS_SIMULATOR=1
|
||||||
|
|
|
@ -35,6 +35,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||||
|
|
|
@ -34,7 +34,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||||
FXOS_SIMULATOR=1
|
FXOS_SIMULATOR=1
|
||||||
|
|
|
@ -32,6 +32,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||||
|
|
|
@ -30,7 +30,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||||
FXOS_SIMULATOR=1
|
FXOS_SIMULATOR=1
|
||||||
|
|
|
@ -29,6 +29,6 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
||||||
|
|
|
@ -27,7 +27,7 @@ export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||||
GAIADIR=$topsrcdir/gaia
|
GAIADIR=$topsrcdir/gaia
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
# Build simulator xpi and phone tweaks for b2g-desktop
|
# Build simulator xpi and phone tweaks for b2g-desktop
|
||||||
FXOS_SIMULATOR=1
|
FXOS_SIMULATOR=1
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
"unpack": true
|
"unpack": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size": 31057326,
|
"size": 31078810,
|
||||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
"filename": "moztt.tar.bz2",
|
"filename": "moz-tt.tar.bz2",
|
||||||
"unpack": true
|
"unpack": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
"unpack": true
|
"unpack": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size": 31057326,
|
"size": 31078810,
|
||||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
"filename": "moztt.tar.bz2",
|
"filename": "moz-tt.tar.bz2",
|
||||||
"unpack": true
|
"unpack": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
"unpack": true
|
"unpack": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size": 31057326,
|
"size": 31078810,
|
||||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
"filename": "moztt.tar.bz2",
|
"filename": "moz-tt.tar.bz2",
|
||||||
"unpack": true
|
"unpack": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
"filename": "mozmake.exe"
|
"filename": "mozmake.exe"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size": 31057326,
|
"size": 31078810,
|
||||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
"filename": "moztt.tar.bz2",
|
"filename": "moz-tt.tar.bz2",
|
||||||
"unpack": true
|
"unpack": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,4 +8,4 @@ ac_add_options --enable-default-toolkit=cairo-gtk2
|
||||||
ac_add_options --enable-application=b2g/dev
|
ac_add_options --enable-application=b2g/dev
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# 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
|
export MOZ_PACKAGE_JSSHELL=1
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
||||||
. "$topsrcdir/build/mozconfig.common.override"
|
. "$topsrcdir/build/mozconfig.common.override"
|
||||||
. "$topsrcdir/build/mozconfig.cache"
|
. "$topsrcdir/build/mozconfig.cache"
|
||||||
|
|
|
@ -10,4 +10,4 @@ MOZ_AUTOMATION_SDK=0
|
||||||
ac_add_options --enable-application=b2g/dev
|
ac_add_options --enable-application=b2g/dev
|
||||||
|
|
||||||
# Include Firefox OS fonts.
|
# Include Firefox OS fonts.
|
||||||
MOZTTDIR=$topsrcdir/moztt
|
MOZTTDIR=$topsrcdir/moz-tt
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
"unpack": true
|
"unpack": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size": 31057326,
|
"size": 31078810,
|
||||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
"filename": "moztt.tar.bz2",
|
"filename": "moz-tt.tar.bz2",
|
||||||
"unpack": true
|
"unpack": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
"unpack": true
|
"unpack": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size": 31057326,
|
"size": 31078810,
|
||||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
"filename": "moztt.tar.bz2",
|
"filename": "moz-tt.tar.bz2",
|
||||||
"unpack": true
|
"unpack": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
"unpack": true
|
"unpack": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size": 31057326,
|
"size": 31078810,
|
||||||
"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
|
"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c",
|
||||||
"algorithm": "sha512",
|
"algorithm": "sha512",
|
||||||
"filename": "moztt.tar.bz2",
|
"filename": "moz-tt.tar.bz2",
|
||||||
"unpack": true
|
"unpack": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -644,6 +644,7 @@
|
||||||
@RESPATH@/components/AppsService.manifest
|
@RESPATH@/components/AppsService.manifest
|
||||||
@RESPATH@/components/Push.js
|
@RESPATH@/components/Push.js
|
||||||
@RESPATH@/components/Push.manifest
|
@RESPATH@/components/Push.manifest
|
||||||
|
@RESPATH@/components/PushClient.js
|
||||||
@RESPATH@/components/PushNotificationService.js
|
@RESPATH@/components/PushNotificationService.js
|
||||||
@RESPATH@/components/PushServiceLauncher.js
|
@RESPATH@/components/PushServiceLauncher.js
|
||||||
|
|
||||||
|
@ -710,6 +711,7 @@
|
||||||
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
||||||
@RESPATH@/components/nsUrlClassifierListManager.js
|
@RESPATH@/components/nsUrlClassifierListManager.js
|
||||||
@RESPATH@/components/nsUrlClassifierLib.js
|
@RESPATH@/components/nsUrlClassifierLib.js
|
||||||
|
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||||
@RESPATH@/components/url-classifier.xpt
|
@RESPATH@/components/url-classifier.xpt
|
||||||
|
|
||||||
; GNOME hooks
|
; GNOME hooks
|
||||||
|
|
|
@ -148,8 +148,13 @@ let wrapper = {
|
||||||
|
|
||||||
if (accountData.customizeSync) {
|
if (accountData.customizeSync) {
|
||||||
Services.prefs.setBoolPref(PREF_SYNC_SHOW_CUSTOMIZATION, true);
|
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
|
// We need to confirm a relink - see shouldAllowRelink for more
|
||||||
let newAccountEmail = accountData.email;
|
let newAccountEmail = accountData.email;
|
||||||
|
|
|
@ -116,8 +116,12 @@ let TrackingProtection = {
|
||||||
// Add the current host in the 'trackingprotection' consumer of
|
// Add the current host in the 'trackingprotection' consumer of
|
||||||
// the permission manager using a normalized URI. This effectively
|
// the permission manager using a normalized URI. This effectively
|
||||||
// places this host on the tracking protection allowlist.
|
// places this host on the tracking protection allowlist.
|
||||||
|
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
|
||||||
|
PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl);
|
||||||
|
} else {
|
||||||
Services.perms.add(normalizedUrl,
|
Services.perms.add(normalizedUrl,
|
||||||
"trackingprotection", Services.perms.ALLOW_ACTION);
|
"trackingprotection", Services.perms.ALLOW_ACTION);
|
||||||
|
}
|
||||||
|
|
||||||
// Telemetry for disable protection.
|
// Telemetry for disable protection.
|
||||||
this.eventsHistogram.add(1);
|
this.eventsHistogram.add(1);
|
||||||
|
@ -133,8 +137,11 @@ let TrackingProtection = {
|
||||||
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
|
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
|
||||||
null, null);
|
null, null);
|
||||||
|
|
||||||
Services.perms.remove(normalizedUrl,
|
if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
|
||||||
"trackingprotection");
|
PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl);
|
||||||
|
} else {
|
||||||
|
Services.perms.remove(normalizedUrl, "trackingprotection");
|
||||||
|
}
|
||||||
|
|
||||||
// Telemetry for enable protection.
|
// Telemetry for enable protection.
|
||||||
this.eventsHistogram.add(2);
|
this.eventsHistogram.add(2);
|
||||||
|
|
|
@ -431,6 +431,10 @@ tags = trackingprotection
|
||||||
support-files =
|
support-files =
|
||||||
trackingPage.html
|
trackingPage.html
|
||||||
benignPage.html
|
benignPage.html
|
||||||
|
[browser_trackingUI_5.js]
|
||||||
|
tags = trackingprotection
|
||||||
|
support-files =
|
||||||
|
trackingPage.html
|
||||||
[browser_typeAheadFind.js]
|
[browser_typeAheadFind.js]
|
||||||
skip-if = buildapp == 'mulet'
|
skip-if = buildapp == 'mulet'
|
||||||
[browser_unknownContentType_title.js]
|
[browser_unknownContentType_title.js]
|
||||||
|
|
|
@ -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");
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
|
||||||
"resource://gre/modules/Promise.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||||
|
@ -35,18 +33,14 @@ function promiseInitContentBlocklistSvc(aBrowser)
|
||||||
* @returns a Promise that resolves to true after the time has elapsed
|
* @returns a Promise that resolves to true after the time has elapsed
|
||||||
*/
|
*/
|
||||||
function waitForMs(aMs) {
|
function waitForMs(aMs) {
|
||||||
let deferred = Promise.defer();
|
return new Promise((resolve) => {
|
||||||
let startTime = Date.now();
|
|
||||||
setTimeout(done, aMs);
|
setTimeout(done, aMs);
|
||||||
function done() {
|
function done() {
|
||||||
deferred.resolve(true);
|
resolve(true);
|
||||||
}
|
}
|
||||||
return deferred.promise;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// DOM Promise fails for unknown reasons here, so we're using
|
|
||||||
// resource://gre/modules/Promise.jsm.
|
|
||||||
function waitForEvent(subject, eventName, checkFn, useCapture, useUntrusted) {
|
function waitForEvent(subject, eventName, checkFn, useCapture, useUntrusted) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
subject.addEventListener(eventName, function listener(event) {
|
subject.addEventListener(eventName, function listener(event) {
|
||||||
|
@ -84,7 +78,7 @@ function waitForEvent(subject, eventName, checkFn, useCapture, useUntrusted) {
|
||||||
* @rejects if a valid load event is not received within a meaningful interval
|
* @rejects if a valid load event is not received within a meaningful interval
|
||||||
*/
|
*/
|
||||||
function promiseTabLoadEvent(tab, url, eventType="load") {
|
function promiseTabLoadEvent(tab, url, eventType="load") {
|
||||||
let deferred = Promise.defer();
|
return new Promise((resolve, reject) => {
|
||||||
info("Wait tab event: " + eventType);
|
info("Wait tab event: " + eventType);
|
||||||
|
|
||||||
function handle(event) {
|
function handle(event) {
|
||||||
|
@ -98,19 +92,19 @@ function promiseTabLoadEvent(tab, url, eventType="load") {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||||
info("Tab event received: " + eventType);
|
info("Tab event received: " + eventType);
|
||||||
deferred.resolve(event);
|
resolve(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeout = setTimeout(() => {
|
let timeout = setTimeout(() => {
|
||||||
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
tab.linkedBrowser.removeEventListener(eventType, handle, true);
|
||||||
deferred.reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
|
reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
|
||||||
}, 30000);
|
}, 30000);
|
||||||
|
|
||||||
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
|
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
|
||||||
if (url) {
|
if (url) {
|
||||||
tab.linkedBrowser.loadURI(url);
|
tab.linkedBrowser.loadURI(url);
|
||||||
}
|
}
|
||||||
return deferred.promise;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForCondition(condition, nextTest, errorMsg, aTries, aWait) {
|
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.
|
// Waits for a conditional function defined by the caller to return true.
|
||||||
function promiseForCondition(aConditionFn, aMessage, aTries, aWait) {
|
function promiseForCondition(aConditionFn, aMessage, aTries, aWait) {
|
||||||
let deferred = Promise.defer();
|
return new Promise((resolve) => {
|
||||||
waitForCondition(aConditionFn, deferred.resolve,
|
waitForCondition(aConditionFn, resolve,
|
||||||
(aMessage || "Condition didn't pass."),
|
(aMessage || "Condition didn't pass."),
|
||||||
aTries, aWait);
|
aTries, aWait);
|
||||||
return deferred.promise;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the chrome side nsIPluginTag for this plugin
|
// 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
|
// Insure there's a popup notification present. This test does not indicate
|
||||||
// open state. aBrowser can be undefined.
|
// open state. aBrowser can be undefined.
|
||||||
function promisePopupNotification(aName, aBrowser) {
|
function promisePopupNotification(aName, aBrowser) {
|
||||||
let deferred = Promise.defer();
|
return new Promise((resolve) => {
|
||||||
|
|
||||||
waitForCondition(() => PopupNotifications.getNotification(aName, aBrowser),
|
waitForCondition(() => PopupNotifications.getNotification(aName, aBrowser),
|
||||||
() => {
|
() => {
|
||||||
ok(!!PopupNotifications.getNotification(aName, aBrowser),
|
ok(!!PopupNotifications.getNotification(aName, aBrowser),
|
||||||
aName + " notification appeared");
|
aName + " notification appeared");
|
||||||
|
|
||||||
deferred.resolve();
|
resolve();
|
||||||
}, "timeout waiting for popup notification " + aName);
|
}, "timeout waiting for popup notification " + aName);
|
||||||
|
});
|
||||||
return deferred.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -361,9 +353,9 @@ function waitForNotificationBar(notificationID, browser, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function promiseForNotificationBar(notificationID, browser) {
|
function promiseForNotificationBar(notificationID, browser) {
|
||||||
let deferred = Promise.defer();
|
return new Promise((resolve) => {
|
||||||
waitForNotificationBar(notificationID, browser, deferred.resolve);
|
waitForNotificationBar(notificationID, browser, resolve);
|
||||||
return deferred.promise;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -386,9 +378,9 @@ function waitForNotificationShown(notification, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function promiseForNotificationShown(notification) {
|
function promiseForNotificationShown(notification) {
|
||||||
let deferred = Promise.defer();
|
return new Promise((resolve) => {
|
||||||
waitForNotificationShown(notification, deferred.resolve);
|
waitForNotificationShown(notification, resolve);
|
||||||
return deferred.promise;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -957,9 +957,8 @@ const CustomizableWidgets = [
|
||||||
type: "custom",
|
type: "custom",
|
||||||
label: "loop-call-button3.label",
|
label: "loop-call-button3.label",
|
||||||
tooltiptext: "loop-call-button3.tooltiptext",
|
tooltiptext: "loop-call-button3.tooltiptext",
|
||||||
|
privateBrowsingTooltiptext: "loop-call-button3-pb.tooltiptext",
|
||||||
defaultArea: CustomizableUI.AREA_NAVBAR,
|
defaultArea: CustomizableUI.AREA_NAVBAR,
|
||||||
// Not in private browsing, see bug 1108187.
|
|
||||||
showInPrivateBrowsing: false,
|
|
||||||
introducedInVersion: 4,
|
introducedInVersion: 4,
|
||||||
onBuild: function(aDocument) {
|
onBuild: function(aDocument) {
|
||||||
// If we're not supposed to see the button, return zip.
|
// If we're not supposed to see the button, return zip.
|
||||||
|
@ -967,13 +966,21 @@ const CustomizableWidgets = [
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(aDocument.defaultView);
|
||||||
|
|
||||||
let node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
|
let node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
|
||||||
node.setAttribute("id", this.id);
|
node.setAttribute("id", this.id);
|
||||||
node.classList.add("toolbarbutton-1");
|
node.classList.add("toolbarbutton-1");
|
||||||
node.classList.add("chromeclass-toolbar-additional");
|
node.classList.add("chromeclass-toolbar-additional");
|
||||||
node.classList.add("badged-button");
|
node.classList.add("badged-button");
|
||||||
node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
|
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.setAttribute("removable", "true");
|
||||||
node.addEventListener("command", function(event) {
|
node.addEventListener("command", function(event) {
|
||||||
aDocument.defaultView.LoopUI.togglePanel(event);
|
aDocument.defaultView.LoopUI.togglePanel(event);
|
||||||
|
|
|
@ -119,7 +119,7 @@ function configureFxAccountIdentity() {
|
||||||
let storageManager = new MockFxaStorageManager();
|
let storageManager = new MockFxaStorageManager();
|
||||||
// and init storage with our user.
|
// and init storage with our user.
|
||||||
storageManager.initialize(user);
|
storageManager.initialize(user);
|
||||||
return new AccountState(this, storageManager);
|
return new AccountState(storageManager);
|
||||||
},
|
},
|
||||||
getCertificate(data, keyPair, mustBeValidUntil) {
|
getCertificate(data, keyPair, mustBeValidUntil) {
|
||||||
this.cert = {
|
this.cert = {
|
||||||
|
|
|
@ -570,13 +570,15 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
|
|
||||||
var OngoingConversationView = React.createClass({displayName: "OngoingConversationView",
|
var OngoingConversationView = React.createClass({displayName: "OngoingConversationView",
|
||||||
mixins: [
|
mixins: [
|
||||||
loop.store.StoreMixin("conversationStore"),
|
|
||||||
sharedMixins.MediaSetupMixin
|
sharedMixins.MediaSetupMixin
|
||||||
],
|
],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
// local
|
// local
|
||||||
audio: React.PropTypes.object,
|
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,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
// The poster URLs are for UI-showcase testing and development.
|
// The poster URLs are for UI-showcase testing and development.
|
||||||
localPosterUrl: React.PropTypes.string,
|
localPosterUrl: React.PropTypes.string,
|
||||||
|
@ -597,7 +599,17 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
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() {
|
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() {
|
shouldRenderRemoteVideo: function() {
|
||||||
if (this.props.mediaConnected) {
|
if (this.props.mediaConnected) {
|
||||||
// If remote video is not enabled, we're muted, so we'll show an avatar
|
// If remote video is not enabled, we're muted, so we'll show an avatar
|
||||||
|
@ -646,33 +682,25 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var localStreamClasses = React.addons.classSet({
|
|
||||||
local: true,
|
|
||||||
"local-stream": true,
|
|
||||||
"local-stream-audio": !this.props.video.enabled
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
React.createElement("div", {className: "video-layout-wrapper"},
|
React.createElement("div", {className: "desktop-call-wrapper"},
|
||||||
React.createElement("div", {className: "conversation"},
|
React.createElement(sharedViews.MediaLayoutView, {
|
||||||
React.createElement("div", {className: "media nested"},
|
dispatcher: this.props.dispatcher,
|
||||||
React.createElement("div", {className: "video_wrapper remote_wrapper"},
|
displayScreenShare: false,
|
||||||
React.createElement("div", {className: "video_inner remote focus-stream"},
|
isLocalLoading: this._isLocalLoading(),
|
||||||
React.createElement(sharedViews.MediaView, {displayAvatar: !this.shouldRenderRemoteVideo(),
|
isRemoteLoading: this._isRemoteLoading(),
|
||||||
isLoading: false,
|
isScreenShareLoading: false,
|
||||||
mediaType: "remote",
|
localPosterUrl: this.props.localPosterUrl,
|
||||||
posterUrl: this.props.remotePosterUrl,
|
localSrcVideoObject: this.state.localSrcVideoObject,
|
||||||
srcVideoObject: this.state.remoteSrcVideoObject})
|
localVideoMuted: !this.props.video.enabled,
|
||||||
)
|
matchMedia: this.state.matchMedia || window.matchMedia.bind(window),
|
||||||
),
|
remotePosterUrl: this.props.remotePosterUrl,
|
||||||
React.createElement("div", {className: localStreamClasses},
|
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
||||||
React.createElement(sharedViews.MediaView, {displayAvatar: !this.props.video.enabled,
|
renderRemoteVideo: this.shouldRenderRemoteVideo(),
|
||||||
isLoading: false,
|
screenSharePosterUrl: null,
|
||||||
mediaType: "local",
|
screenShareVideoObject: this.state.screenShareVideoObject,
|
||||||
posterUrl: this.props.localPosterUrl,
|
showContextRoomName: false,
|
||||||
srcVideoObject: this.state.localSrcVideoObject})
|
useDesktopPaths: true}),
|
||||||
)
|
|
||||||
),
|
|
||||||
React.createElement(loop.shared.views.ConversationToolbar, {
|
React.createElement(loop.shared.views.ConversationToolbar, {
|
||||||
audio: this.props.audio,
|
audio: this.props.audio,
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
|
@ -681,7 +709,6 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
publishStream: this.publishStream,
|
publishStream: this.publishStream,
|
||||||
video: this.props.video})
|
video: this.props.video})
|
||||||
)
|
)
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -778,6 +805,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
case CALL_STATES.ONGOING: {
|
case CALL_STATES.ONGOING: {
|
||||||
return (React.createElement(OngoingConversationView, {
|
return (React.createElement(OngoingConversationView, {
|
||||||
audio: {enabled: !this.state.audioMuted},
|
audio: {enabled: !this.state.audioMuted},
|
||||||
|
conversationStore: this.getStore(),
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
mediaConnected: this.state.mediaConnected,
|
mediaConnected: this.state.mediaConnected,
|
||||||
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
||||||
|
|
|
@ -570,13 +570,15 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
|
|
||||||
var OngoingConversationView = React.createClass({
|
var OngoingConversationView = React.createClass({
|
||||||
mixins: [
|
mixins: [
|
||||||
loop.store.StoreMixin("conversationStore"),
|
|
||||||
sharedMixins.MediaSetupMixin
|
sharedMixins.MediaSetupMixin
|
||||||
],
|
],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
// local
|
// local
|
||||||
audio: React.PropTypes.object,
|
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,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
// The poster URLs are for UI-showcase testing and development.
|
// The poster URLs are for UI-showcase testing and development.
|
||||||
localPosterUrl: React.PropTypes.string,
|
localPosterUrl: React.PropTypes.string,
|
||||||
|
@ -597,7 +599,17 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
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() {
|
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() {
|
shouldRenderRemoteVideo: function() {
|
||||||
if (this.props.mediaConnected) {
|
if (this.props.mediaConnected) {
|
||||||
// If remote video is not enabled, we're muted, so we'll show an avatar
|
// If remote video is not enabled, we're muted, so we'll show an avatar
|
||||||
|
@ -646,33 +682,25 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var localStreamClasses = React.addons.classSet({
|
|
||||||
local: true,
|
|
||||||
"local-stream": true,
|
|
||||||
"local-stream-audio": !this.props.video.enabled
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="video-layout-wrapper">
|
<div className="desktop-call-wrapper">
|
||||||
<div className="conversation">
|
<sharedViews.MediaLayoutView
|
||||||
<div className="media nested">
|
dispatcher={this.props.dispatcher}
|
||||||
<div className="video_wrapper remote_wrapper">
|
displayScreenShare={false}
|
||||||
<div className="video_inner remote focus-stream">
|
isLocalLoading={this._isLocalLoading()}
|
||||||
<sharedViews.MediaView displayAvatar={!this.shouldRenderRemoteVideo()}
|
isRemoteLoading={this._isRemoteLoading()}
|
||||||
isLoading={false}
|
isScreenShareLoading={false}
|
||||||
mediaType="remote"
|
localPosterUrl={this.props.localPosterUrl}
|
||||||
posterUrl={this.props.remotePosterUrl}
|
localSrcVideoObject={this.state.localSrcVideoObject}
|
||||||
srcVideoObject={this.state.remoteSrcVideoObject} />
|
localVideoMuted={!this.props.video.enabled}
|
||||||
</div>
|
matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
|
||||||
</div>
|
remotePosterUrl={this.props.remotePosterUrl}
|
||||||
<div className={localStreamClasses}>
|
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
||||||
<sharedViews.MediaView displayAvatar={!this.props.video.enabled}
|
renderRemoteVideo={this.shouldRenderRemoteVideo()}
|
||||||
isLoading={false}
|
screenSharePosterUrl={null}
|
||||||
mediaType="local"
|
screenShareVideoObject={this.state.screenShareVideoObject}
|
||||||
posterUrl={this.props.localPosterUrl}
|
showContextRoomName={false}
|
||||||
srcVideoObject={this.state.localSrcVideoObject} />
|
useDesktopPaths={true} />
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<loop.shared.views.ConversationToolbar
|
<loop.shared.views.ConversationToolbar
|
||||||
audio={this.props.audio}
|
audio={this.props.audio}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
|
@ -681,7 +709,6 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
publishStream={this.publishStream}
|
publishStream={this.publishStream}
|
||||||
video={this.props.video} />
|
video={this.props.video} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -778,6 +805,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||||
case CALL_STATES.ONGOING: {
|
case CALL_STATES.ONGOING: {
|
||||||
return (<OngoingConversationView
|
return (<OngoingConversationView
|
||||||
audio={{enabled: !this.state.audioMuted}}
|
audio={{enabled: !this.state.audioMuted}}
|
||||||
|
conversationStore={this.getStore()}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
mediaConnected={this.state.mediaConnected}
|
mediaConnected={this.state.mediaConnected}
|
||||||
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
||||||
|
|
|
@ -665,7 +665,7 @@ loop.roomViews = (function(mozL10n) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_shouldRenderLocalLoading: function () {
|
_isLocalLoading: function () {
|
||||||
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
|
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
|
||||||
!this.state.localSrcVideoObject;
|
!this.state.localSrcVideoObject;
|
||||||
},
|
},
|
||||||
|
@ -677,7 +677,7 @@ loop.roomViews = (function(mozL10n) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_shouldRenderRemoteLoading: function() {
|
_isRemoteLoading: function() {
|
||||||
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
|
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
|
||||||
!this.state.remoteSrcVideoObject &&
|
!this.state.remoteSrcVideoObject &&
|
||||||
!this.state.mediaConnected);
|
!this.state.mediaConnected);
|
||||||
|
@ -741,12 +741,25 @@ loop.roomViews = (function(mozL10n) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
React.createElement("div", {className: "room-conversation-wrapper"},
|
React.createElement("div", {className: "room-conversation-wrapper desktop-room-wrapper"},
|
||||||
React.createElement("div", {className: "video-layout-wrapper"},
|
React.createElement(sharedViews.MediaLayoutView, {
|
||||||
React.createElement("div", {className: "conversation room-conversation"},
|
dispatcher: this.props.dispatcher,
|
||||||
React.createElement("div", {className: "media nested"},
|
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, {
|
React.createElement(DesktopRoomInvitationView, {
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
error: this.state.error,
|
error: this.state.error,
|
||||||
|
@ -758,22 +771,6 @@ loop.roomViews = (function(mozL10n) {
|
||||||
show: shouldRenderInvitationOverlay,
|
show: shouldRenderInvitationOverlay,
|
||||||
showEditContext: shouldRenderInvitationOverlay && shouldRenderEditContextView,
|
showEditContext: shouldRenderInvitationOverlay && shouldRenderEditContextView,
|
||||||
socialShareProviders: this.state.socialShareProviders}),
|
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, {
|
React.createElement(DesktopRoomEditContextView, {
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
error: this.state.error,
|
error: this.state.error,
|
||||||
|
@ -793,12 +790,6 @@ loop.roomViews = (function(mozL10n) {
|
||||||
screenShare: screenShareData,
|
screenShare: screenShareData,
|
||||||
video: {enabled: !this.state.videoMuted, visible: true}})
|
video: {enabled: !this.state.videoMuted, visible: true}})
|
||||||
)
|
)
|
||||||
),
|
|
||||||
React.createElement(sharedViews.chat.TextChatView, {
|
|
||||||
dispatcher: this.props.dispatcher,
|
|
||||||
showRoomName: false,
|
|
||||||
useDesktopPaths: true})
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -665,7 +665,7 @@ loop.roomViews = (function(mozL10n) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_shouldRenderLocalLoading: function () {
|
_isLocalLoading: function () {
|
||||||
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
|
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
|
||||||
!this.state.localSrcVideoObject;
|
!this.state.localSrcVideoObject;
|
||||||
},
|
},
|
||||||
|
@ -677,7 +677,7 @@ loop.roomViews = (function(mozL10n) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_shouldRenderRemoteLoading: function() {
|
_isRemoteLoading: function() {
|
||||||
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
|
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
|
||||||
!this.state.remoteSrcVideoObject &&
|
!this.state.remoteSrcVideoObject &&
|
||||||
!this.state.mediaConnected);
|
!this.state.mediaConnected);
|
||||||
|
@ -741,12 +741,25 @@ loop.roomViews = (function(mozL10n) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="room-conversation-wrapper">
|
<div className="room-conversation-wrapper desktop-room-wrapper">
|
||||||
<div className="video-layout-wrapper">
|
<sharedViews.MediaLayoutView
|
||||||
<div className="conversation room-conversation">
|
dispatcher={this.props.dispatcher}
|
||||||
<div className="media nested">
|
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
|
<DesktopRoomInvitationView
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
error={this.state.error}
|
error={this.state.error}
|
||||||
|
@ -758,22 +771,6 @@ loop.roomViews = (function(mozL10n) {
|
||||||
show={shouldRenderInvitationOverlay}
|
show={shouldRenderInvitationOverlay}
|
||||||
showEditContext={shouldRenderInvitationOverlay && shouldRenderEditContextView}
|
showEditContext={shouldRenderInvitationOverlay && shouldRenderEditContextView}
|
||||||
socialShareProviders={this.state.socialShareProviders} />
|
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
|
<DesktopRoomEditContextView
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
error={this.state.error}
|
error={this.state.error}
|
||||||
|
@ -782,7 +779,7 @@ loop.roomViews = (function(mozL10n) {
|
||||||
roomData={roomData}
|
roomData={roomData}
|
||||||
savingContext={this.state.savingContext}
|
savingContext={this.state.savingContext}
|
||||||
show={!shouldRenderInvitationOverlay && shouldRenderEditContextView} />
|
show={!shouldRenderInvitationOverlay && shouldRenderEditContextView} />
|
||||||
</div>
|
</sharedViews.MediaLayoutView>
|
||||||
<sharedViews.ConversationToolbar
|
<sharedViews.ConversationToolbar
|
||||||
audio={{enabled: !this.state.audioMuted, visible: true}}
|
audio={{enabled: !this.state.audioMuted, visible: true}}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
|
@ -793,12 +790,6 @@ loop.roomViews = (function(mozL10n) {
|
||||||
screenShare={screenShareData}
|
screenShare={screenShareData}
|
||||||
video={{enabled: !this.state.videoMuted, visible: true}} />
|
video={{enabled: !this.state.videoMuted, visible: true}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<sharedViews.chat.TextChatView
|
|
||||||
dispatcher={this.props.dispatcher}
|
|
||||||
showRoomName={false}
|
|
||||||
useDesktopPaths={true} />
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -504,28 +504,6 @@
|
||||||
text-align: center;
|
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 {
|
.conversation .media.nested .focus-stream {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: absolute; /* workaround for lack of object-fit; see bug 1020445 */
|
position: absolute; /* workaround for lack of object-fit; see bug 1020445 */
|
||||||
|
@ -592,15 +570,11 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.remote .avatar {
|
.remote > .avatar {
|
||||||
/* make visually distinct from local avatar */
|
/* make visually distinct from local avatar */
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fx-embedded .media.nested {
|
|
||||||
min-height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fx-embedded-call-identifier {
|
.fx-embedded-call-identifier {
|
||||||
display: inline;
|
display: inline;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -675,7 +649,9 @@
|
||||||
* */
|
* */
|
||||||
html, .fx-embedded, #main,
|
html, .fx-embedded, #main,
|
||||||
.video-layout-wrapper,
|
.video-layout-wrapper,
|
||||||
.conversation {
|
.conversation,
|
||||||
|
.desktop-call-wrapper,
|
||||||
|
.desktop-room-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,7 +911,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
||||||
border-top: 2px solid #444;
|
border-top: 2px solid #444;
|
||||||
border-bottom: 2px solid #444;
|
border-bottom: 2px solid #444;
|
||||||
padding: .5rem;
|
padding: .5rem;
|
||||||
max-height: 400px;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -951,7 +926,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
/* Make the context view float atop the video elements. */
|
/* Make the context view float atop the video elements. */
|
||||||
z-index: 2;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.room-invitation-overlay .room-context {
|
.room-invitation-overlay .room-context {
|
||||||
|
@ -1087,12 +1062,12 @@ html[dir="rtl"] .room-context-btn-close {
|
||||||
.standalone-room-wrapper > .media-layout {
|
.standalone-room-wrapper > .media-layout {
|
||||||
/* 50px is the header, 64px for toolbar, 3em is the footer. */
|
/* 50px is the header, 64px for toolbar, 3em is the footer. */
|
||||||
height: calc(100% - 50px - 64px - 3em);
|
height: calc(100% - 50px - 64px - 3em);
|
||||||
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-layout > .media-wrapper {
|
.media-layout > .media-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column wrap;
|
flex-flow: column wrap;
|
||||||
margin: 0 10px;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,6 +1114,14 @@ html[dir="rtl"] .room-context-btn-close {
|
||||||
height: calc(100% - 300px);
|
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
|
/* Temporarily slaved from .media-wrapper until we use it in more places
|
||||||
to avoid affecting the conversation window on desktop. */
|
to avoid affecting the conversation window on desktop. */
|
||||||
.media-wrapper > .text-chat-view > .text-chat-entries {
|
.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
|
/* Temporarily slaved from .media-wrapper until we use it in more places
|
||||||
to avoid affecting the conversation window on desktop. */
|
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. */
|
/* 40px is the height of .text-chat-box. */
|
||||||
height: calc(100% - 40px);
|
height: calc(100% - 40px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -1215,20 +1198,26 @@ html[dir="rtl"] .room-context-btn-close {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-wrapper > .local {
|
.media-wrapper > .focus-stream > .local {
|
||||||
/* Position over the remote video */
|
/* Position over the remote video */
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* Make sure its on top */
|
/* Make sure its on top */
|
||||||
z-index: 1001;
|
z-index: 2;
|
||||||
margin: 3px;
|
margin: 3px;
|
||||||
right: 0;
|
right: 0;
|
||||||
/* 29px is (30% of 50px high header) + (height toolbar (38px) +
|
/* 29px is (30% of 50px high header) + (height toolbar (38px) +
|
||||||
height footer (25px) - height header (50px)) */
|
height footer (25px) - height header (50px)) */
|
||||||
bottom: calc(30% + 29px);
|
bottom: 0;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
height: 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 {
|
html[dir="rtl"] .media-wrapper > .local {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -1247,6 +1236,15 @@ html[dir="rtl"] .room-context-btn-close {
|
||||||
height: 30%;
|
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 {
|
.media-wrapper.receiving-screen-share > .screen {
|
||||||
order: 1;
|
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 {
|
.standalone > #main > .room-conversation-wrapper > .media-layout > .conversation-toolbar {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
@ -1415,37 +1454,12 @@ html[dir="rtl"] .standalone .room-conversation-wrapper .room-inner-info-area {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Text chat in rooms styles */
|
/* Text chat in styles */
|
||||||
|
|
||||||
.fx-embedded .room-conversation-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fx-embedded .video-layout-wrapper {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-chat-view {
|
.text-chat-view {
|
||||||
background: white;
|
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 {
|
.text-chat-box {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
max-height: 40px;
|
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 {
|
.self-view-hidden-message {
|
||||||
/* Not displayed by default; display is turned on elsewhere when the
|
/* Not displayed by default; display is turned on elsewhere when the
|
||||||
* self-view is actually hidden.
|
* self-view is actually hidden.
|
||||||
|
|
|
@ -580,21 +580,6 @@ loop.store.ActiveRoomStore = (function() {
|
||||||
* @param {sharedActions.ConnectionFailure} actionData
|
* @param {sharedActions.ConnectionFailure} actionData
|
||||||
*/
|
*/
|
||||||
connectionFailure: function(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 ?
|
var exitState = this._storeState.roomState === ROOM_STATES.FAILED ?
|
||||||
this._storeState.failureExitState : this._storeState.roomState;
|
this._storeState.failureExitState : this._storeState.roomState;
|
||||||
|
|
||||||
|
|
|
@ -146,21 +146,6 @@ loop.store = loop.store || {};
|
||||||
* @param {sharedActions.ConnectionFailure} actionData The action data.
|
* @param {sharedActions.ConnectionFailure} actionData The action data.
|
||||||
*/
|
*/
|
||||||
connectionFailure: function(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._endSession();
|
this._endSession();
|
||||||
this.setStoreState({
|
this.setStoreState({
|
||||||
callState: CALL_STATES.TERMINATED,
|
callState: CALL_STATES.TERMINATED,
|
||||||
|
|
|
@ -61,15 +61,26 @@ loop.OTSdkDriver = (function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XXX This is a workaround for desktop machines that do not have a
|
* XXX This is a workaround for desktop machines that do not have a
|
||||||
* camera installed. As we don't yet have device enumeration, when
|
* camera installed. The SDK doesn't currently do use the new device
|
||||||
* we do, this can be removed (bug 1138851), and the sdk should handle it.
|
* 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
|
// 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
|
// the result. So here we define our own one which wraps around the
|
||||||
// we can change it later.
|
// real device enumeration api.
|
||||||
window.MediaStreamTrack.getSources = function(callback) {
|
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));
|
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 expect the local video to be muted automatically by the SDK. Hence
|
||||||
// we don't mute it manually here.
|
// we don't mute it manually here.
|
||||||
this._mockPublisherEl = document.createElement("div");
|
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,
|
this.publisher = this.sdk.initPublisher(this._mockPublisherEl,
|
||||||
_.extend(this._getDataChannelSettings, this._getCopyPublisherConfig));
|
_.extend(this._getDataChannelSettings, this._getCopyPublisherConfig));
|
||||||
|
|
||||||
|
@ -135,17 +138,6 @@ loop.OTSdkDriver = (function() {
|
||||||
this._onAccessDialogOpened.bind(this));
|
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
|
* Handles the setMute action. Informs the published stream to mute
|
||||||
* or unmute audio as appropriate.
|
* or unmute audio as appropriate.
|
||||||
|
|
|
@ -150,8 +150,7 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||||
var lastTimestamp = 0;
|
var lastTimestamp = 0;
|
||||||
|
|
||||||
var entriesClasses = React.addons.classSet({
|
var entriesClasses = React.addons.classSet({
|
||||||
"text-chat-entries": true,
|
"text-chat-entries": true
|
||||||
"text-chat-entries-empty": !this.props.messageList.length
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -382,7 +381,8 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||||
|
|
||||||
var textChatViewClasses = React.addons.classSet({
|
var textChatViewClasses = React.addons.classSet({
|
||||||
"text-chat-view": true,
|
"text-chat-view": true,
|
||||||
"text-chat-disabled": !this.state.textChatEnabled
|
"text-chat-disabled": !this.state.textChatEnabled,
|
||||||
|
"text-chat-entries-empty": !messageList.length
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -150,8 +150,7 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||||
var lastTimestamp = 0;
|
var lastTimestamp = 0;
|
||||||
|
|
||||||
var entriesClasses = React.addons.classSet({
|
var entriesClasses = React.addons.classSet({
|
||||||
"text-chat-entries": true,
|
"text-chat-entries": true
|
||||||
"text-chat-entries-empty": !this.props.messageList.length
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -382,7 +381,8 @@ loop.shared.views.chat = (function(mozL10n) {
|
||||||
|
|
||||||
var textChatViewClasses = React.addons.classSet({
|
var textChatViewClasses = React.addons.classSet({
|
||||||
"text-chat-view": true,
|
"text-chat-view": true,
|
||||||
"text-chat-disabled": !this.state.textChatEnabled
|
"text-chat-disabled": !this.state.textChatEnabled,
|
||||||
|
"text-chat-entries-empty": !messageList.length
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -946,6 +946,7 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
|
|
||||||
var MediaLayoutView = React.createClass({displayName: "MediaLayoutView",
|
var MediaLayoutView = React.createClass({displayName: "MediaLayoutView",
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
children: React.PropTypes.node,
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
displayScreenShare: React.PropTypes.bool.isRequired,
|
displayScreenShare: React.PropTypes.bool.isRequired,
|
||||||
isLocalLoading: React.PropTypes.bool.isRequired,
|
isLocalLoading: React.PropTypes.bool.isRequired,
|
||||||
|
@ -955,6 +956,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
localPosterUrl: React.PropTypes.string,
|
localPosterUrl: React.PropTypes.string,
|
||||||
localSrcVideoObject: React.PropTypes.object,
|
localSrcVideoObject: React.PropTypes.object,
|
||||||
localVideoMuted: React.PropTypes.bool.isRequired,
|
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,
|
remotePosterUrl: React.PropTypes.string,
|
||||||
remoteSrcVideoObject: React.PropTypes.object,
|
remoteSrcVideoObject: React.PropTypes.object,
|
||||||
renderRemoteVideo: React.PropTypes.bool.isRequired,
|
renderRemoteVideo: React.PropTypes.bool.isRequired,
|
||||||
|
@ -964,6 +968,60 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
useDesktopPaths: React.PropTypes.bool.isRequired
|
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() {
|
render: function() {
|
||||||
var remoteStreamClasses = React.addons.classSet({
|
var remoteStreamClasses = React.addons.classSet({
|
||||||
"remote": true,
|
"remote": true,
|
||||||
|
@ -979,7 +1037,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
"media-wrapper": true,
|
"media-wrapper": true,
|
||||||
"receiving-screen-share": this.props.displayScreenShare,
|
"receiving-screen-share": this.props.displayScreenShare,
|
||||||
"showing-local-streams": this.props.localSrcVideoObject ||
|
"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 (
|
return (
|
||||||
|
@ -993,7 +1053,10 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
isLoading: this.props.isRemoteLoading,
|
isLoading: this.props.isRemoteLoading,
|
||||||
mediaType: "remote",
|
mediaType: "remote",
|
||||||
posterUrl: this.props.remotePosterUrl,
|
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("div", {className: screenShareStreamClasses},
|
||||||
React.createElement(MediaView, {displayAvatar: false,
|
React.createElement(MediaView, {displayAvatar: false,
|
||||||
|
@ -1006,13 +1069,8 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
showRoomName: this.props.showContextRoomName,
|
showRoomName: this.props.showContextRoomName,
|
||||||
useDesktopPaths: false}),
|
useDesktopPaths: false}),
|
||||||
React.createElement("div", {className: "local"},
|
this.state.localMediaAboslutelyPositioned ?
|
||||||
React.createElement(MediaView, {displayAvatar: this.props.localVideoMuted,
|
null : this.renderLocalVideo()
|
||||||
isLoading: this.props.isLocalLoading,
|
|
||||||
mediaType: "local",
|
|
||||||
posterUrl: this.props.localPosterUrl,
|
|
||||||
srcVideoObject: this.props.localSrcVideoObject})
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -946,6 +946,7 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
|
|
||||||
var MediaLayoutView = React.createClass({
|
var MediaLayoutView = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
children: React.PropTypes.node,
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||||
displayScreenShare: React.PropTypes.bool.isRequired,
|
displayScreenShare: React.PropTypes.bool.isRequired,
|
||||||
isLocalLoading: React.PropTypes.bool.isRequired,
|
isLocalLoading: React.PropTypes.bool.isRequired,
|
||||||
|
@ -955,6 +956,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
localPosterUrl: React.PropTypes.string,
|
localPosterUrl: React.PropTypes.string,
|
||||||
localSrcVideoObject: React.PropTypes.object,
|
localSrcVideoObject: React.PropTypes.object,
|
||||||
localVideoMuted: React.PropTypes.bool.isRequired,
|
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,
|
remotePosterUrl: React.PropTypes.string,
|
||||||
remoteSrcVideoObject: React.PropTypes.object,
|
remoteSrcVideoObject: React.PropTypes.object,
|
||||||
renderRemoteVideo: React.PropTypes.bool.isRequired,
|
renderRemoteVideo: React.PropTypes.bool.isRequired,
|
||||||
|
@ -964,6 +968,60 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
useDesktopPaths: React.PropTypes.bool.isRequired
|
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() {
|
render: function() {
|
||||||
var remoteStreamClasses = React.addons.classSet({
|
var remoteStreamClasses = React.addons.classSet({
|
||||||
"remote": true,
|
"remote": true,
|
||||||
|
@ -979,7 +1037,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
"media-wrapper": true,
|
"media-wrapper": true,
|
||||||
"receiving-screen-share": this.props.displayScreenShare,
|
"receiving-screen-share": this.props.displayScreenShare,
|
||||||
"showing-local-streams": this.props.localSrcVideoObject ||
|
"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 (
|
return (
|
||||||
|
@ -994,6 +1054,9 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
mediaType="remote"
|
mediaType="remote"
|
||||||
posterUrl={this.props.remotePosterUrl}
|
posterUrl={this.props.remotePosterUrl}
|
||||||
srcVideoObject={this.props.remoteSrcVideoObject} />
|
srcVideoObject={this.props.remoteSrcVideoObject} />
|
||||||
|
{ this.state.localMediaAboslutelyPositioned ?
|
||||||
|
this.renderLocalVideo() : null }
|
||||||
|
{ this.props.children }
|
||||||
</div>
|
</div>
|
||||||
<div className={screenShareStreamClasses}>
|
<div className={screenShareStreamClasses}>
|
||||||
<MediaView displayAvatar={false}
|
<MediaView displayAvatar={false}
|
||||||
|
@ -1006,13 +1069,8 @@ loop.shared.views = (function(_, mozL10n) {
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
showRoomName={this.props.showContextRoomName}
|
showRoomName={this.props.showContextRoomName}
|
||||||
useDesktopPaths={false} />
|
useDesktopPaths={false} />
|
||||||
<div className="local">
|
{ this.state.localMediaAboslutelyPositioned ?
|
||||||
<MediaView displayAvatar={this.props.localVideoMuted}
|
null : this.renderLocalVideo() }
|
||||||
isLoading={this.props.isLocalLoading}
|
|
||||||
mediaType="local"
|
|
||||||
posterUrl={this.props.localPosterUrl}
|
|
||||||
srcVideoObject={this.props.localSrcVideoObject} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -256,11 +256,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
mixins: [
|
mixins: [
|
||||||
Backbone.Events,
|
Backbone.Events,
|
||||||
sharedMixins.MediaSetupMixin,
|
sharedMixins.MediaSetupMixin,
|
||||||
sharedMixins.RoomsAudioMixin,
|
sharedMixins.RoomsAudioMixin
|
||||||
loop.store.StoreMixin("activeRoomStore")
|
|
||||||
],
|
],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
// We pass conversationStore here rather than use the mixin, to allow
|
||||||
|
// easy configurability for the ui-showcase.
|
||||||
activeRoomStore: React.PropTypes.oneOfType([
|
activeRoomStore: React.PropTypes.oneOfType([
|
||||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
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() {
|
componentDidMount: function() {
|
||||||
// Adding a class to the document body element from here to ease styling it.
|
// Adding a class to the document body element from here to ease styling it.
|
||||||
document.body.classList.add("is-standalone-room");
|
document.body.classList.add("is-standalone-room");
|
||||||
|
@ -429,7 +440,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
*/
|
*/
|
||||||
_isScreenShareLoading: function() {
|
_isScreenShareLoading: function() {
|
||||||
return this.state.receivingScreenShare &&
|
return this.state.receivingScreenShare &&
|
||||||
!this.state.screenShareVideoObject;
|
!this.state.screenShareVideoObject &&
|
||||||
|
!this.props.screenSharePosterUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -456,6 +468,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
localPosterUrl: this.props.localPosterUrl,
|
localPosterUrl: this.props.localPosterUrl,
|
||||||
localSrcVideoObject: this.state.localSrcVideoObject,
|
localSrcVideoObject: this.state.localSrcVideoObject,
|
||||||
localVideoMuted: this.state.videoMuted,
|
localVideoMuted: this.state.videoMuted,
|
||||||
|
matchMedia: this.state.matchMedia || window.matchMedia.bind(window),
|
||||||
remotePosterUrl: this.props.remotePosterUrl,
|
remotePosterUrl: this.props.remotePosterUrl,
|
||||||
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
|
||||||
renderRemoteVideo: this.shouldRenderRemoteVideo(),
|
renderRemoteVideo: this.shouldRenderRemoteVideo(),
|
||||||
|
|
|
@ -256,11 +256,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
mixins: [
|
mixins: [
|
||||||
Backbone.Events,
|
Backbone.Events,
|
||||||
sharedMixins.MediaSetupMixin,
|
sharedMixins.MediaSetupMixin,
|
||||||
sharedMixins.RoomsAudioMixin,
|
sharedMixins.RoomsAudioMixin
|
||||||
loop.store.StoreMixin("activeRoomStore")
|
|
||||||
],
|
],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
// We pass conversationStore here rather than use the mixin, to allow
|
||||||
|
// easy configurability for the ui-showcase.
|
||||||
activeRoomStore: React.PropTypes.oneOfType([
|
activeRoomStore: React.PropTypes.oneOfType([
|
||||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
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() {
|
componentDidMount: function() {
|
||||||
// Adding a class to the document body element from here to ease styling it.
|
// Adding a class to the document body element from here to ease styling it.
|
||||||
document.body.classList.add("is-standalone-room");
|
document.body.classList.add("is-standalone-room");
|
||||||
|
@ -429,7 +440,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
*/
|
*/
|
||||||
_isScreenShareLoading: function() {
|
_isScreenShareLoading: function() {
|
||||||
return this.state.receivingScreenShare &&
|
return this.state.receivingScreenShare &&
|
||||||
!this.state.screenShareVideoObject;
|
!this.state.screenShareVideoObject &&
|
||||||
|
!this.props.screenSharePosterUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -456,6 +468,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||||
localPosterUrl={this.props.localPosterUrl}
|
localPosterUrl={this.props.localPosterUrl}
|
||||||
localSrcVideoObject={this.state.localSrcVideoObject}
|
localSrcVideoObject={this.state.localSrcVideoObject}
|
||||||
localVideoMuted={this.state.videoMuted}
|
localVideoMuted={this.state.videoMuted}
|
||||||
|
matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
|
||||||
remotePosterUrl={this.props.remotePosterUrl}
|
remotePosterUrl={this.props.remotePosterUrl}
|
||||||
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
|
||||||
renderRemoteVideo={this.shouldRenderRemoteVideo()}
|
renderRemoteVideo={this.shouldRenderRemoteVideo()}
|
||||||
|
|
|
@ -474,7 +474,9 @@ describe("loop.conversationViews", function () {
|
||||||
describe("OngoingConversationView", function() {
|
describe("OngoingConversationView", function() {
|
||||||
function mountTestComponent(extraProps) {
|
function mountTestComponent(extraProps) {
|
||||||
var props = _.extend({
|
var props = _.extend({
|
||||||
dispatcher: dispatcher
|
conversationStore: conversationStore,
|
||||||
|
dispatcher: dispatcher,
|
||||||
|
matchMedia: window.matchMedia
|
||||||
}, extraProps);
|
}, extraProps);
|
||||||
return TestUtils.renderIntoDocument(
|
return TestUtils.renderIntoDocument(
|
||||||
React.createElement(loop.conversationViews.OngoingConversationView, props));
|
React.createElement(loop.conversationViews.OngoingConversationView, props));
|
||||||
|
@ -489,15 +491,6 @@ describe("loop.conversationViews", function () {
|
||||||
sinon.match.hasOwn("name", "setupStreamElements"));
|
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() {
|
it("should display the remote video when the stream is enabled", function() {
|
||||||
conversationStore.setStoreState({
|
conversationStore.setStoreState({
|
||||||
remoteSrcVideoObject: { fake: 1 }
|
remoteSrcVideoObject: { fake: 1 }
|
||||||
|
@ -511,16 +504,6 @@ describe("loop.conversationViews", function () {
|
||||||
expect(view.getDOMNode().querySelector(".remote video")).not.eql(null);
|
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() {
|
it("should display the local video when the stream is enabled", function() {
|
||||||
conversationStore.setStoreState({
|
conversationStore.setStoreState({
|
||||||
localSrcVideoObject: { fake: 1 }
|
localSrcVideoObject: { fake: 1 }
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
|
|
||||||
describe("Unexpected Warnings Check", function() {
|
describe("Unexpected Warnings Check", function() {
|
||||||
it("should long only the warnings we expect", 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() {
|
describe("Edit Context", function() {
|
||||||
it("should show the form when the edit button is clicked", function() {
|
it("should show the form when the edit button is clicked", function() {
|
||||||
view = mountTestComponent();
|
view = mountTestComponent();
|
||||||
|
|
|
@ -99,7 +99,7 @@ class Test1BrowserCall(MarionetteTestCase):
|
||||||
self.switch_to_chatbox()
|
self.switch_to_chatbox()
|
||||||
|
|
||||||
# expect a video container on desktop side
|
# 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.assertEqual(media_container.tag_name, "div", "expect a video container")
|
||||||
|
|
||||||
self.check_video(".local-video")
|
self.check_video(".local-video")
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"gMozLoopAPI": true,
|
"gMozLoopAPI": true,
|
||||||
"mockDb": true,
|
"mockDb": true,
|
||||||
"mockPushHandler": true,
|
"mockPushHandler": true,
|
||||||
|
"OpenBrowserWindow": true,
|
||||||
"promiseDeletedOAuthParams": false,
|
"promiseDeletedOAuthParams": false,
|
||||||
"promiseOAuthGetRegistration": false,
|
"promiseOAuthGetRegistration": false,
|
||||||
"promiseOAuthParamsSetup": false,
|
"promiseOAuthParamsSetup": false,
|
||||||
|
|
|
@ -167,3 +167,19 @@ add_task(function* test_screen_share() {
|
||||||
MozLoopService.setScreenShareState("1", false);
|
MozLoopService.setScreenShareState("1", false);
|
||||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
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() {
|
it("should store the failure reason", function() {
|
||||||
store.connectionFailure(connectionFailureAction);
|
store.connectionFailure(connectionFailureAction);
|
||||||
|
|
||||||
|
|
|
@ -147,26 +147,6 @@ describe("loop.store.ConversationStore", function () {
|
||||||
store.setStoreState({windowId: "42"});
|
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() {
|
it("should disconnect the session", function() {
|
||||||
store.connectionFailure(
|
store.connectionFailure(
|
||||||
new sharedActions.ConnectionFailure({reason: "fake"}));
|
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() {
|
describe("#setMute", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
sdk.initPublisher.returns(publisher);
|
sdk.initPublisher.returns(publisher);
|
||||||
|
|
|
@ -56,27 +56,6 @@ describe("loop.shared.views.TextChatView", function () {
|
||||||
store.setStoreState({ textChatEnabled: true });
|
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() {
|
it("should render message entries when message were sent/ received", function() {
|
||||||
view = mountTestComponent({
|
view = mountTestComponent({
|
||||||
messageList: [{
|
messageList: [{
|
||||||
|
@ -297,6 +276,41 @@ describe("loop.shared.views.TextChatView", function () {
|
||||||
fakeServer.restore();
|
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() {
|
it("should show timestamps from msgs sent more than 1 min apart", function() {
|
||||||
view = mountTestComponent();
|
view = mountTestComponent();
|
||||||
|
|
||||||
|
@ -326,12 +340,6 @@ describe("loop.shared.views.TextChatView", function () {
|
||||||
.to.eql(2);
|
.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() {
|
it("should render message entries when message were sent/ received", function() {
|
||||||
view = mountTestComponent();
|
view = mountTestComponent();
|
||||||
|
|
||||||
|
|
|
@ -1057,6 +1057,7 @@ describe("loop.shared.views", function() {
|
||||||
isRemoteLoading: false,
|
isRemoteLoading: false,
|
||||||
isScreenShareLoading: false,
|
isScreenShareLoading: false,
|
||||||
localVideoMuted: false,
|
localVideoMuted: false,
|
||||||
|
matchMedia: window.matchMedia,
|
||||||
renderRemoteVideo: false,
|
renderRemoteVideo: false,
|
||||||
showContextRoomName: false,
|
showContextRoomName: false,
|
||||||
useDesktopPaths: false
|
useDesktopPaths: false
|
||||||
|
@ -1144,5 +1145,35 @@ describe("loop.shared.views", function() {
|
||||||
expect(view.getDOMNode().querySelector(".media-wrapper")
|
expect(view.getDOMNode().querySelector(".media-wrapper")
|
||||||
.classList.contains("showing-local-streams")).eql(true);
|
.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 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) {
|
sendTextChatMessage: function(message) {
|
||||||
dispatcher.dispatch(new loop.shared.actions.ReceivedTextChatMessage({
|
dispatcher.dispatch(new loop.shared.actions.ReceivedTextChatMessage({
|
||||||
message: message.message
|
message: message.message
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}, Backbone.Events);
|
};
|
||||||
|
|
||||||
|
var mockSDK = new MockSDK();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every view that uses an activeRoomStore needs its own; if they shared
|
* Every view that uses an activeRoomStore needs its own; if they shared
|
||||||
|
@ -116,7 +128,6 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
||||||
|
|
||||||
// Since this is called by setTimeout, we don't want to lose any
|
// 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...
|
// exceptions if there's a problem and we need to debug, so...
|
||||||
try {
|
try {
|
||||||
|
@ -136,6 +147,17 @@
|
||||||
camera: {height: 480, orientation: 0, width: 640}
|
camera: {height: 480, orientation: 0, width: 640}
|
||||||
},
|
},
|
||||||
remoteVideoEnabled: options.remoteVideoEnabled,
|
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),
|
matchMedia: contentWindow.matchMedia.bind(contentWindow),
|
||||||
roomState: options.roomState,
|
roomState: options.roomState,
|
||||||
videoMuted: !!options.videoMuted
|
videoMuted: !!options.videoMuted
|
||||||
|
@ -185,6 +207,10 @@
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var updatingMobileActiveRoomStore = makeActiveRoomStore({
|
||||||
|
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||||
|
});
|
||||||
|
|
||||||
var localFaceMuteRoomStore = makeActiveRoomStore({
|
var localFaceMuteRoomStore = makeActiveRoomStore({
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
videoMuted: true
|
videoMuted: true
|
||||||
|
@ -201,12 +227,19 @@
|
||||||
receivingScreenShare: true
|
receivingScreenShare: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var updatingSharingRoomMobileStore = makeActiveRoomStore({
|
||||||
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
|
receivingScreenShare: true
|
||||||
|
});
|
||||||
|
|
||||||
var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
|
var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
|
||||||
mediaConnected: false,
|
mediaConnected: false,
|
||||||
|
receivingScreenShare: true,
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
remoteSrcVideoObject: false
|
remoteSrcVideoObject: false
|
||||||
});
|
});
|
||||||
var loadingScreenSharingRoomStore = makeActiveRoomStore({
|
var loadingScreenSharingRoomStore = makeActiveRoomStore({
|
||||||
|
receivingScreenShare: true,
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -234,7 +267,10 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
var invitationRoomStore = new loop.store.RoomStore(dispatcher, {
|
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, {
|
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({
|
var desktopLocalFaceMuteActiveRoomStore = makeActiveRoomStore({
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
videoMuted: true
|
videoMuted: true
|
||||||
|
@ -272,14 +322,58 @@
|
||||||
activeRoomStore: desktopRemoteFaceMuteActiveRoomStore
|
activeRoomStore: desktopRemoteFaceMuteActiveRoomStore
|
||||||
});
|
});
|
||||||
|
|
||||||
var conversationStore = new loop.store.ConversationStore(dispatcher, {
|
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: {},
|
client: {},
|
||||||
mozLoop: navigator.mozLoop,
|
mozLoop: navigator.mozLoop,
|
||||||
sdkDriver: mockSDK
|
sdkDriver: mockSDK
|
||||||
});
|
});
|
||||||
var textChatStore = new loop.store.TextChatStore(dispatcher, {
|
|
||||||
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.
|
// Update the text chat store with the room info.
|
||||||
textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
|
textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
|
||||||
|
@ -341,7 +435,7 @@
|
||||||
|
|
||||||
loop.store.StoreMixin.register({
|
loop.store.StoreMixin.register({
|
||||||
activeRoomStore: activeRoomStore,
|
activeRoomStore: activeRoomStore,
|
||||||
conversationStore: conversationStore,
|
conversationStore: conversationStores[0],
|
||||||
textChatStore: textChatStore
|
textChatStore: textChatStore
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -360,14 +454,6 @@
|
||||||
requestCallUrlInfo: noop
|
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({
|
var mockWebSocket = new loop.CallConnectionWebSocket({
|
||||||
url: "fake",
|
url: "fake",
|
||||||
callId: "fakeId",
|
callId: "fakeId",
|
||||||
|
@ -763,7 +849,7 @@
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
||||||
outgoing: false,
|
outgoing: false,
|
||||||
store: conversationStore})
|
store: conversationStores[0]})
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
React.createElement(Example, {dashed: true,
|
React.createElement(Example, {dashed: true,
|
||||||
|
@ -772,7 +858,7 @@
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
||||||
outgoing: true,
|
outgoing: true,
|
||||||
store: conversationStore})
|
store: conversationStores[1]})
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
React.createElement(Example, {dashed: true,
|
React.createElement(Example, {dashed: true,
|
||||||
|
@ -781,18 +867,22 @@
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(CallFailedView, {dispatcher: dispatcher, emailLinkError: true,
|
React.createElement(CallFailedView, {dispatcher: dispatcher, emailLinkError: true,
|
||||||
outgoing: true,
|
outgoing: true,
|
||||||
store: conversationStore})
|
store: conversationStores[0]})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
React.createElement(Section, {name: "OngoingConversationView"},
|
React.createElement(Section, {name: "OngoingConversationView"},
|
||||||
React.createElement(FramedExample, {height: 254,
|
React.createElement(FramedExample, {
|
||||||
|
dashed: true,
|
||||||
|
height: 394,
|
||||||
|
onContentsRendered: conversationStores[0].forcedUpdate,
|
||||||
summary: "Desktop ongoing conversation window",
|
summary: "Desktop ongoing conversation window",
|
||||||
width: 298},
|
width: 298},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(OngoingConversationView, {
|
React.createElement(OngoingConversationView, {
|
||||||
audio: {enabled: true},
|
audio: {enabled: true},
|
||||||
|
conversationStore: conversationStores[0],
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
mediaConnected: true,
|
mediaConnected: true,
|
||||||
|
@ -802,12 +892,34 @@
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
React.createElement(FramedExample, {height: 600,
|
React.createElement(FramedExample, {
|
||||||
summary: "Desktop ongoing conversation window large",
|
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: 600,
|
||||||
|
onContentsRendered: conversationStores[2].forcedUpdate,
|
||||||
|
summary: "Desktop ongoing conversation window (large)",
|
||||||
width: 800},
|
width: 800},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(OngoingConversationView, {
|
React.createElement(OngoingConversationView, {
|
||||||
audio: {enabled: true},
|
audio: {enabled: true},
|
||||||
|
conversationStore: conversationStores[2],
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
mediaConnected: true,
|
mediaConnected: true,
|
||||||
|
@ -817,13 +929,18 @@
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
React.createElement(FramedExample, {height: 254,
|
React.createElement(FramedExample, {
|
||||||
|
dashed: true,
|
||||||
|
height: 394,
|
||||||
|
onContentsRendered: conversationStores[3].forcedUpdate,
|
||||||
summary: "Desktop ongoing conversation window - local face mute",
|
summary: "Desktop ongoing conversation window - local face mute",
|
||||||
width: 298},
|
width: 298},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(OngoingConversationView, {
|
React.createElement(OngoingConversationView, {
|
||||||
audio: {enabled: true},
|
audio: {enabled: true},
|
||||||
|
conversationStore: conversationStores[3],
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
mediaConnected: true,
|
mediaConnected: true,
|
||||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||||
remoteVideoEnabled: true,
|
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",
|
summary: "Desktop ongoing conversation window - remote face mute",
|
||||||
width: 298},
|
width: 298},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(OngoingConversationView, {
|
React.createElement(OngoingConversationView, {
|
||||||
audio: {enabled: true},
|
audio: {enabled: true},
|
||||||
|
conversationStore: conversationStores[4],
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
mediaConnected: true,
|
mediaConnected: true,
|
||||||
|
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||||
remoteVideoEnabled: false,
|
remoteVideoEnabled: false,
|
||||||
video: {enabled: true}})
|
video: {enabled: true}})
|
||||||
)
|
)
|
||||||
|
@ -894,7 +1015,8 @@
|
||||||
|
|
||||||
React.createElement(Section, {name: "DesktopRoomConversationView"},
|
React.createElement(Section, {name: "DesktopRoomConversationView"},
|
||||||
React.createElement(FramedExample, {
|
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)",
|
summary: "Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)",
|
||||||
width: 298},
|
width: 298},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
|
@ -911,6 +1033,7 @@
|
||||||
React.createElement(FramedExample, {
|
React.createElement(FramedExample, {
|
||||||
dashed: true,
|
dashed: true,
|
||||||
height: 394,
|
height: 394,
|
||||||
|
onContentsRendered: desktopRoomStoreLoading.activeRoomStore.forcedUpdate,
|
||||||
summary: "Desktop room conversation (loading)",
|
summary: "Desktop room conversation (loading)",
|
||||||
width: 298},
|
width: 298},
|
||||||
/* Hide scrollbars here. Rotating loading div overflows and causes
|
/* Hide scrollbars here. Rotating loading div overflows and causes
|
||||||
|
@ -927,8 +1050,12 @@
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
React.createElement(FramedExample, {height: 254,
|
React.createElement(FramedExample, {
|
||||||
summary: "Desktop room conversation"},
|
dashed: true,
|
||||||
|
height: 394,
|
||||||
|
onContentsRendered: roomStore.activeRoomStore.forcedUpdate,
|
||||||
|
summary: "Desktop room conversation",
|
||||||
|
width: 298},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
React.createElement(DesktopRoomConversationView, {
|
React.createElement(DesktopRoomConversationView, {
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
|
@ -941,8 +1068,46 @@
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
React.createElement(FramedExample, {dashed: true,
|
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,
|
height: 394,
|
||||||
|
onContentsRendered: desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate,
|
||||||
summary: "Desktop room conversation local face-mute",
|
summary: "Desktop room conversation local face-mute",
|
||||||
width: 298},
|
width: 298},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
|
@ -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",
|
summary: "Desktop room conversation remote face-mute",
|
||||||
width: 298},
|
width: 298},
|
||||||
React.createElement("div", {className: "fx-embedded"},
|
React.createElement("div", {className: "fx-embedded"},
|
||||||
|
@ -964,6 +1131,7 @@
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
mozLoop: navigator.mozLoop,
|
mozLoop: navigator.mozLoop,
|
||||||
onCallTerminated: function(){},
|
onCallTerminated: function(){},
|
||||||
|
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||||
roomStore: desktopRemoteFaceMuteRoomStore})
|
roomStore: desktopRemoteFaceMuteRoomStore})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1081,8 +1249,7 @@
|
||||||
isFirefox: true,
|
isFirefox: true,
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS})
|
||||||
screenSharePosterUrl: "sample-img/video-screen-baz.png"})
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -1102,8 +1269,7 @@
|
||||||
isFirefox: true,
|
isFirefox: true,
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
remotePosterUrl: "sample-img/video-screen-remote.png",
|
remotePosterUrl: "sample-img/video-screen-remote.png",
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS})
|
||||||
screenSharePosterUrl: "sample-img/video-screen-baz.png"})
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -1171,12 +1337,12 @@
|
||||||
cssClass: "standalone",
|
cssClass: "standalone",
|
||||||
dashed: true,
|
dashed: true,
|
||||||
height: 480,
|
height: 480,
|
||||||
onContentsRendered: updatingActiveRoomStore.forcedUpdate,
|
onContentsRendered: updatingMobileActiveRoomStore.forcedUpdate,
|
||||||
summary: "Standalone room conversation (has-participants, 600x480)",
|
summary: "Standalone room conversation (has-participants, 600x480)",
|
||||||
width: 600},
|
width: 600},
|
||||||
React.createElement("div", {className: "standalone"},
|
React.createElement("div", {className: "standalone"},
|
||||||
React.createElement(StandaloneRoomView, {
|
React.createElement(StandaloneRoomView, {
|
||||||
activeRoomStore: updatingActiveRoomStore,
|
activeRoomStore: updatingMobileActiveRoomStore,
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
isFirefox: true,
|
isFirefox: true,
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
|
@ -1189,12 +1355,12 @@
|
||||||
cssClass: "standalone",
|
cssClass: "standalone",
|
||||||
dashed: true,
|
dashed: true,
|
||||||
height: 480,
|
height: 480,
|
||||||
onContentsRendered: updatingSharingRoomStore.forcedUpdate,
|
onContentsRendered: updatingSharingRoomMobileStore.forcedUpdate,
|
||||||
summary: "Standalone room convo (has-participants, receivingScreenShare, 600x480)",
|
summary: "Standalone room convo (has-participants, receivingScreenShare, 600x480)",
|
||||||
width: 600},
|
width: 600},
|
||||||
React.createElement("div", {className: "standalone", cssClass: "standalone"},
|
React.createElement("div", {className: "standalone", cssClass: "standalone"},
|
||||||
React.createElement(StandaloneRoomView, {
|
React.createElement(StandaloneRoomView, {
|
||||||
activeRoomStore: updatingSharingRoomStore,
|
activeRoomStore: updatingSharingRoomMobileStore,
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
isFirefox: true,
|
isFirefox: true,
|
||||||
localPosterUrl: "sample-img/video-screen-local.png",
|
localPosterUrl: "sample-img/video-screen-local.png",
|
||||||
|
@ -1282,7 +1448,7 @@
|
||||||
|
|
||||||
// This simulates the mocha layout for errors which means we can run
|
// This simulates the mocha layout for errors which means we can run
|
||||||
// this alongside our other unit tests but use the same harness.
|
// this alongside our other unit tests but use the same harness.
|
||||||
var expectedWarningsCount = 23;
|
var expectedWarningsCount = 18;
|
||||||
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
||||||
if (uncaughtError || warningsMismatch) {
|
if (uncaughtError || warningsMismatch) {
|
||||||
$("#results").append("<div class='failures'><em>" +
|
$("#results").append("<div class='failures'><em>" +
|
||||||
|
|
|
@ -75,13 +75,25 @@
|
||||||
|
|
||||||
var dispatcher = new loop.Dispatcher();
|
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) {
|
sendTextChatMessage: function(message) {
|
||||||
dispatcher.dispatch(new loop.shared.actions.ReceivedTextChatMessage({
|
dispatcher.dispatch(new loop.shared.actions.ReceivedTextChatMessage({
|
||||||
message: message.message
|
message: message.message
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}, Backbone.Events);
|
};
|
||||||
|
|
||||||
|
var mockSDK = new MockSDK();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every view that uses an activeRoomStore needs its own; if they shared
|
* Every view that uses an activeRoomStore needs its own; if they shared
|
||||||
|
@ -116,7 +128,6 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
store.forcedUpdate = function forcedUpdate(contentWindow) {
|
||||||
|
|
||||||
// Since this is called by setTimeout, we don't want to lose any
|
// 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...
|
// exceptions if there's a problem and we need to debug, so...
|
||||||
try {
|
try {
|
||||||
|
@ -136,6 +147,17 @@
|
||||||
camera: {height: 480, orientation: 0, width: 640}
|
camera: {height: 480, orientation: 0, width: 640}
|
||||||
},
|
},
|
||||||
remoteVideoEnabled: options.remoteVideoEnabled,
|
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),
|
matchMedia: contentWindow.matchMedia.bind(contentWindow),
|
||||||
roomState: options.roomState,
|
roomState: options.roomState,
|
||||||
videoMuted: !!options.videoMuted
|
videoMuted: !!options.videoMuted
|
||||||
|
@ -185,6 +207,10 @@
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var updatingMobileActiveRoomStore = makeActiveRoomStore({
|
||||||
|
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||||
|
});
|
||||||
|
|
||||||
var localFaceMuteRoomStore = makeActiveRoomStore({
|
var localFaceMuteRoomStore = makeActiveRoomStore({
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
videoMuted: true
|
videoMuted: true
|
||||||
|
@ -201,12 +227,19 @@
|
||||||
receivingScreenShare: true
|
receivingScreenShare: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var updatingSharingRoomMobileStore = makeActiveRoomStore({
|
||||||
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
|
receivingScreenShare: true
|
||||||
|
});
|
||||||
|
|
||||||
var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
|
var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
|
||||||
mediaConnected: false,
|
mediaConnected: false,
|
||||||
|
receivingScreenShare: true,
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
remoteSrcVideoObject: false
|
remoteSrcVideoObject: false
|
||||||
});
|
});
|
||||||
var loadingScreenSharingRoomStore = makeActiveRoomStore({
|
var loadingScreenSharingRoomStore = makeActiveRoomStore({
|
||||||
|
receivingScreenShare: true,
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
roomState: ROOM_STATES.HAS_PARTICIPANTS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -234,7 +267,10 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
var invitationRoomStore = new loop.store.RoomStore(dispatcher, {
|
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, {
|
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({
|
var desktopLocalFaceMuteActiveRoomStore = makeActiveRoomStore({
|
||||||
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
roomState: ROOM_STATES.HAS_PARTICIPANTS,
|
||||||
videoMuted: true
|
videoMuted: true
|
||||||
|
@ -272,14 +322,58 @@
|
||||||
activeRoomStore: desktopRemoteFaceMuteActiveRoomStore
|
activeRoomStore: desktopRemoteFaceMuteActiveRoomStore
|
||||||
});
|
});
|
||||||
|
|
||||||
var conversationStore = new loop.store.ConversationStore(dispatcher, {
|
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: {},
|
client: {},
|
||||||
mozLoop: navigator.mozLoop,
|
mozLoop: navigator.mozLoop,
|
||||||
sdkDriver: mockSDK
|
sdkDriver: mockSDK
|
||||||
});
|
});
|
||||||
var textChatStore = new loop.store.TextChatStore(dispatcher, {
|
|
||||||
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.
|
// Update the text chat store with the room info.
|
||||||
textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
|
textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
|
||||||
|
@ -341,7 +435,7 @@
|
||||||
|
|
||||||
loop.store.StoreMixin.register({
|
loop.store.StoreMixin.register({
|
||||||
activeRoomStore: activeRoomStore,
|
activeRoomStore: activeRoomStore,
|
||||||
conversationStore: conversationStore,
|
conversationStore: conversationStores[0],
|
||||||
textChatStore: textChatStore
|
textChatStore: textChatStore
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -360,14 +454,6 @@
|
||||||
requestCallUrlInfo: noop
|
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({
|
var mockWebSocket = new loop.CallConnectionWebSocket({
|
||||||
url: "fake",
|
url: "fake",
|
||||||
callId: "fakeId",
|
callId: "fakeId",
|
||||||
|
@ -763,7 +849,7 @@
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<CallFailedView dispatcher={dispatcher}
|
<CallFailedView dispatcher={dispatcher}
|
||||||
outgoing={false}
|
outgoing={false}
|
||||||
store={conversationStore} />
|
store={conversationStores[0]} />
|
||||||
</div>
|
</div>
|
||||||
</Example>
|
</Example>
|
||||||
<Example dashed={true}
|
<Example dashed={true}
|
||||||
|
@ -772,7 +858,7 @@
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<CallFailedView dispatcher={dispatcher}
|
<CallFailedView dispatcher={dispatcher}
|
||||||
outgoing={true}
|
outgoing={true}
|
||||||
store={conversationStore} />
|
store={conversationStores[1]} />
|
||||||
</div>
|
</div>
|
||||||
</Example>
|
</Example>
|
||||||
<Example dashed={true}
|
<Example dashed={true}
|
||||||
|
@ -781,18 +867,22 @@
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<CallFailedView dispatcher={dispatcher} emailLinkError={true}
|
<CallFailedView dispatcher={dispatcher} emailLinkError={true}
|
||||||
outgoing={true}
|
outgoing={true}
|
||||||
store={conversationStore} />
|
store={conversationStores[0]} />
|
||||||
</div>
|
</div>
|
||||||
</Example>
|
</Example>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Section name="OngoingConversationView">
|
<Section name="OngoingConversationView">
|
||||||
<FramedExample height={254}
|
<FramedExample
|
||||||
|
dashed={true}
|
||||||
|
height={394}
|
||||||
|
onContentsRendered={conversationStores[0].forcedUpdate}
|
||||||
summary="Desktop ongoing conversation window"
|
summary="Desktop ongoing conversation window"
|
||||||
width={298}>
|
width={298}>
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<OngoingConversationView
|
<OngoingConversationView
|
||||||
audio={{enabled: true}}
|
audio={{enabled: true}}
|
||||||
|
conversationStore={conversationStores[0]}
|
||||||
dispatcher={dispatcher}
|
dispatcher={dispatcher}
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
mediaConnected={true}
|
mediaConnected={true}
|
||||||
|
@ -802,12 +892,34 @@
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
<FramedExample height={600}
|
<FramedExample
|
||||||
summary="Desktop ongoing conversation window large"
|
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={600}
|
||||||
|
onContentsRendered={conversationStores[2].forcedUpdate}
|
||||||
|
summary="Desktop ongoing conversation window (large)"
|
||||||
width={800}>
|
width={800}>
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<OngoingConversationView
|
<OngoingConversationView
|
||||||
audio={{enabled: true}}
|
audio={{enabled: true}}
|
||||||
|
conversationStore={conversationStores[2]}
|
||||||
dispatcher={dispatcher}
|
dispatcher={dispatcher}
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
mediaConnected={true}
|
mediaConnected={true}
|
||||||
|
@ -817,13 +929,18 @@
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
<FramedExample height={254}
|
<FramedExample
|
||||||
|
dashed={true}
|
||||||
|
height={394}
|
||||||
|
onContentsRendered={conversationStores[3].forcedUpdate}
|
||||||
summary="Desktop ongoing conversation window - local face mute"
|
summary="Desktop ongoing conversation window - local face mute"
|
||||||
width={298} >
|
width={298} >
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<OngoingConversationView
|
<OngoingConversationView
|
||||||
audio={{enabled: true}}
|
audio={{enabled: true}}
|
||||||
|
conversationStore={conversationStores[3]}
|
||||||
dispatcher={dispatcher}
|
dispatcher={dispatcher}
|
||||||
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
mediaConnected={true}
|
mediaConnected={true}
|
||||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||||
remoteVideoEnabled={true}
|
remoteVideoEnabled={true}
|
||||||
|
@ -831,15 +948,19 @@
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
<FramedExample height={254}
|
<FramedExample
|
||||||
|
dashed={true} height={394}
|
||||||
|
onContentsRendered={conversationStores[4].forcedUpdate}
|
||||||
summary="Desktop ongoing conversation window - remote face mute"
|
summary="Desktop ongoing conversation window - remote face mute"
|
||||||
width={298} >
|
width={298} >
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<OngoingConversationView
|
<OngoingConversationView
|
||||||
audio={{enabled: true}}
|
audio={{enabled: true}}
|
||||||
|
conversationStore={conversationStores[4]}
|
||||||
dispatcher={dispatcher}
|
dispatcher={dispatcher}
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
mediaConnected={true}
|
mediaConnected={true}
|
||||||
|
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||||
remoteVideoEnabled={false}
|
remoteVideoEnabled={false}
|
||||||
video={{enabled: true}} />
|
video={{enabled: true}} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -894,7 +1015,8 @@
|
||||||
|
|
||||||
<Section name="DesktopRoomConversationView">
|
<Section name="DesktopRoomConversationView">
|
||||||
<FramedExample
|
<FramedExample
|
||||||
height={254}
|
height={398}
|
||||||
|
onContentsRendered={invitationRoomStore.activeRoomStore.forcedUpdate}
|
||||||
summary="Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)"
|
summary="Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)"
|
||||||
width={298}>
|
width={298}>
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
|
@ -911,6 +1033,7 @@
|
||||||
<FramedExample
|
<FramedExample
|
||||||
dashed={true}
|
dashed={true}
|
||||||
height={394}
|
height={394}
|
||||||
|
onContentsRendered={desktopRoomStoreLoading.activeRoomStore.forcedUpdate}
|
||||||
summary="Desktop room conversation (loading)"
|
summary="Desktop room conversation (loading)"
|
||||||
width={298}>
|
width={298}>
|
||||||
{/* Hide scrollbars here. Rotating loading div overflows and causes
|
{/* Hide scrollbars here. Rotating loading div overflows and causes
|
||||||
|
@ -927,8 +1050,12 @@
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
<FramedExample height={254}
|
<FramedExample
|
||||||
summary="Desktop room conversation">
|
dashed={true}
|
||||||
|
height={394}
|
||||||
|
onContentsRendered={roomStore.activeRoomStore.forcedUpdate}
|
||||||
|
summary="Desktop room conversation"
|
||||||
|
width={298}>
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
<DesktopRoomConversationView
|
<DesktopRoomConversationView
|
||||||
dispatcher={dispatcher}
|
dispatcher={dispatcher}
|
||||||
|
@ -941,8 +1068,46 @@
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
<FramedExample dashed={true}
|
<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}
|
height={394}
|
||||||
|
onContentsRendered={desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate}
|
||||||
summary="Desktop room conversation local face-mute"
|
summary="Desktop room conversation local face-mute"
|
||||||
width={298}>
|
width={298}>
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
|
@ -955,7 +1120,9 @@
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
<FramedExample dashed={true} height={394}
|
<FramedExample dashed={true}
|
||||||
|
height={394}
|
||||||
|
onContentsRendered={desktopRemoteFaceMuteRoomStore.activeRoomStore.forcedUpdate}
|
||||||
summary="Desktop room conversation remote face-mute"
|
summary="Desktop room conversation remote face-mute"
|
||||||
width={298} >
|
width={298} >
|
||||||
<div className="fx-embedded">
|
<div className="fx-embedded">
|
||||||
|
@ -964,6 +1131,7 @@
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
mozLoop={navigator.mozLoop}
|
mozLoop={navigator.mozLoop}
|
||||||
onCallTerminated={function(){}}
|
onCallTerminated={function(){}}
|
||||||
|
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||||
roomStore={desktopRemoteFaceMuteRoomStore} />
|
roomStore={desktopRemoteFaceMuteRoomStore} />
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
@ -1081,8 +1249,7 @@
|
||||||
isFirefox={true}
|
isFirefox={true}
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||||
roomState={ROOM_STATES.HAS_PARTICIPANTS}
|
roomState={ROOM_STATES.HAS_PARTICIPANTS} />
|
||||||
screenSharePosterUrl="sample-img/video-screen-baz.png" />
|
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
|
@ -1102,8 +1269,7 @@
|
||||||
isFirefox={true}
|
isFirefox={true}
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
remotePosterUrl="sample-img/video-screen-remote.png"
|
remotePosterUrl="sample-img/video-screen-remote.png"
|
||||||
roomState={ROOM_STATES.HAS_PARTICIPANTS}
|
roomState={ROOM_STATES.HAS_PARTICIPANTS} />
|
||||||
screenSharePosterUrl="sample-img/video-screen-baz.png" />
|
|
||||||
</div>
|
</div>
|
||||||
</FramedExample>
|
</FramedExample>
|
||||||
|
|
||||||
|
@ -1171,12 +1337,12 @@
|
||||||
cssClass="standalone"
|
cssClass="standalone"
|
||||||
dashed={true}
|
dashed={true}
|
||||||
height={480}
|
height={480}
|
||||||
onContentsRendered={updatingActiveRoomStore.forcedUpdate}
|
onContentsRendered={updatingMobileActiveRoomStore.forcedUpdate}
|
||||||
summary="Standalone room conversation (has-participants, 600x480)"
|
summary="Standalone room conversation (has-participants, 600x480)"
|
||||||
width={600}>
|
width={600}>
|
||||||
<div className="standalone">
|
<div className="standalone">
|
||||||
<StandaloneRoomView
|
<StandaloneRoomView
|
||||||
activeRoomStore={updatingActiveRoomStore}
|
activeRoomStore={updatingMobileActiveRoomStore}
|
||||||
dispatcher={dispatcher}
|
dispatcher={dispatcher}
|
||||||
isFirefox={true}
|
isFirefox={true}
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
|
@ -1189,12 +1355,12 @@
|
||||||
cssClass="standalone"
|
cssClass="standalone"
|
||||||
dashed={true}
|
dashed={true}
|
||||||
height={480}
|
height={480}
|
||||||
onContentsRendered={updatingSharingRoomStore.forcedUpdate}
|
onContentsRendered={updatingSharingRoomMobileStore.forcedUpdate}
|
||||||
summary="Standalone room convo (has-participants, receivingScreenShare, 600x480)"
|
summary="Standalone room convo (has-participants, receivingScreenShare, 600x480)"
|
||||||
width={600} >
|
width={600} >
|
||||||
<div className="standalone" cssClass="standalone">
|
<div className="standalone" cssClass="standalone">
|
||||||
<StandaloneRoomView
|
<StandaloneRoomView
|
||||||
activeRoomStore={updatingSharingRoomStore}
|
activeRoomStore={updatingSharingRoomMobileStore}
|
||||||
dispatcher={dispatcher}
|
dispatcher={dispatcher}
|
||||||
isFirefox={true}
|
isFirefox={true}
|
||||||
localPosterUrl="sample-img/video-screen-local.png"
|
localPosterUrl="sample-img/video-screen-local.png"
|
||||||
|
@ -1282,7 +1448,7 @@
|
||||||
|
|
||||||
// This simulates the mocha layout for errors which means we can run
|
// This simulates the mocha layout for errors which means we can run
|
||||||
// this alongside our other unit tests but use the same harness.
|
// this alongside our other unit tests but use the same harness.
|
||||||
var expectedWarningsCount = 23;
|
var expectedWarningsCount = 18;
|
||||||
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
||||||
if (uncaughtError || warningsMismatch) {
|
if (uncaughtError || warningsMismatch) {
|
||||||
$("#results").append("<div class='failures'><em>" +
|
$("#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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* globals overlays, StyleInspectorMenu */
|
/* globals overlays, StyleInspectorMenu, loader, clipboardHelper,
|
||||||
|
_Iterator, StopIteration */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -49,8 +50,7 @@ const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function UpdateProcess(aWin, aGenerator, aOptions)
|
function UpdateProcess(aWin, aGenerator, aOptions) {
|
||||||
{
|
|
||||||
this.win = aWin;
|
this.win = aWin;
|
||||||
this.iter = _Iterator(aGenerator);
|
this.iter = _Iterator(aGenerator);
|
||||||
this.onItem = aOptions.onItem || function() {};
|
this.onItem = aOptions.onItem || function() {};
|
||||||
|
@ -66,8 +66,7 @@ UpdateProcess.prototype = {
|
||||||
/**
|
/**
|
||||||
* Schedule a new batch on the main loop.
|
* Schedule a new batch on the main loop.
|
||||||
*/
|
*/
|
||||||
schedule: function UP_schedule()
|
schedule: function() {
|
||||||
{
|
|
||||||
if (this.canceled) {
|
if (this.canceled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -78,8 +77,7 @@ UpdateProcess.prototype = {
|
||||||
* Cancel the running process. onItem will not be called again,
|
* Cancel the running process. onItem will not be called again,
|
||||||
* and onCancel will be called.
|
* and onCancel will be called.
|
||||||
*/
|
*/
|
||||||
cancel: function UP_cancel()
|
cancel: function() {
|
||||||
{
|
|
||||||
if (this._timeout) {
|
if (this._timeout) {
|
||||||
this.win.clearTimeout(this._timeout);
|
this.win.clearTimeout(this._timeout);
|
||||||
this._timeout = 0;
|
this._timeout = 0;
|
||||||
|
@ -88,7 +86,7 @@ UpdateProcess.prototype = {
|
||||||
this.onCancel();
|
this.onCancel();
|
||||||
},
|
},
|
||||||
|
|
||||||
_timeoutHandler: function UP_timeoutHandler() {
|
_timeoutHandler: function() {
|
||||||
this._timeout = null;
|
this._timeout = null;
|
||||||
try {
|
try {
|
||||||
this._runBatch();
|
this._runBatch();
|
||||||
|
@ -104,8 +102,7 @@ UpdateProcess.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_runBatch: function Y_runBatch()
|
_runBatch: function() {
|
||||||
{
|
|
||||||
let time = Date.now();
|
let time = Date.now();
|
||||||
while (!this.canceled) {
|
while (!this.canceled) {
|
||||||
// Continue until iter.next() throws...
|
// Continue until iter.next() throws...
|
||||||
|
@ -120,9 +117,9 @@ UpdateProcess.prototype = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CssComputedView is a panel that manages the display of a table sorted by style.
|
* CssComputedView is a panel that manages the display of a table
|
||||||
* There should be one instance of CssComputedView per style display (of which there
|
* sorted by style. There should be one instance of CssComputedView
|
||||||
* will generally only be one).
|
* per style display (of which there will generally only be one).
|
||||||
*
|
*
|
||||||
* @param {Inspector} inspector toolbox panel
|
* @param {Inspector} inspector toolbox panel
|
||||||
* @param {Document} document The document that will contain the computed view.
|
* @param {Document} document The document that will contain the computed view.
|
||||||
|
@ -142,8 +139,8 @@ function CssComputedView(inspector, document, pageStyle) {
|
||||||
|
|
||||||
this._outputParser = new OutputParser();
|
this._outputParser = new OutputParser();
|
||||||
|
|
||||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||||
getService(Ci.nsIXULChromeRegistry);
|
.getService(Ci.nsIXULChromeRegistry);
|
||||||
this.getRTLAttr = chromeReg.isLocaleRTL("global") ? "rtl" : "ltr";
|
this.getRTLAttr = chromeReg.isLocaleRTL("global") ? "rtl" : "ltr";
|
||||||
|
|
||||||
// Create bound methods.
|
// Create bound methods.
|
||||||
|
@ -211,8 +208,7 @@ function CssComputedView(inspector, document, pageStyle) {
|
||||||
* @param {string} aName The key to lookup.
|
* @param {string} aName The key to lookup.
|
||||||
* @returns A localized version of the given key.
|
* @returns A localized version of the given key.
|
||||||
*/
|
*/
|
||||||
CssComputedView.l10n = function CssComputedView_l10n(aName)
|
CssComputedView.l10n = function(aName) {
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
return CssComputedView._strings.GetStringFromName(aName);
|
return CssComputedView._strings.GetStringFromName(aName);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
@ -251,8 +247,7 @@ CssComputedView.prototype = {
|
||||||
this.pageStyle = pageStyle;
|
this.pageStyle = pageStyle;
|
||||||
},
|
},
|
||||||
|
|
||||||
get includeBrowserStyles()
|
get includeBrowserStyles() {
|
||||||
{
|
|
||||||
return this.includeBrowserStylesCheckbox.checked;
|
return this.includeBrowserStylesCheckbox.checked;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -264,8 +259,9 @@ CssComputedView.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the view with a new selected element.
|
* Update the view with a new selected element. The CssComputedView panel
|
||||||
* The CssComputedView panel will show the style information for the given element.
|
* will show the style information for the given element.
|
||||||
|
*
|
||||||
* @param {NodeFront} aElement The highlighted node to get styles for.
|
* @param {NodeFront} aElement The highlighted node to get styles for.
|
||||||
* @returns a promise that will be resolved when highlighting is complete.
|
* @returns a promise that will be resolved when highlighting is complete.
|
||||||
*/
|
*/
|
||||||
|
@ -383,8 +379,7 @@ CssComputedView.prototype = {
|
||||||
return {type, value};
|
return {type, value};
|
||||||
},
|
},
|
||||||
|
|
||||||
_createPropertyViews: function()
|
_createPropertyViews: function() {
|
||||||
{
|
|
||||||
if (this._createViewsPromise) {
|
if (this._createViewsPromise) {
|
||||||
return this._createViewsPromise;
|
return this._createViewsPromise;
|
||||||
}
|
}
|
||||||
|
@ -396,7 +391,8 @@ CssComputedView.prototype = {
|
||||||
this.numVisibleProperties = 0;
|
this.numVisibleProperties = 0;
|
||||||
let fragment = this.styleDocument.createDocumentFragment();
|
let fragment = this.styleDocument.createDocumentFragment();
|
||||||
|
|
||||||
this._createViewsProcess = new UpdateProcess(this.styleWindow, CssComputedView.propertyNames, {
|
this._createViewsProcess = new UpdateProcess(
|
||||||
|
this.styleWindow, CssComputedView.propertyNames, {
|
||||||
onItem: (aPropertyName) => {
|
onItem: (aPropertyName) => {
|
||||||
// Per-item callback.
|
// Per-item callback.
|
||||||
let propView = new PropertyView(this, aPropertyName);
|
let propView = new PropertyView(this, aPropertyName);
|
||||||
|
@ -426,8 +422,7 @@ CssComputedView.prototype = {
|
||||||
/**
|
/**
|
||||||
* Refresh the panel content.
|
* Refresh the panel content.
|
||||||
*/
|
*/
|
||||||
refreshPanel: function CssComputedView_refreshPanel()
|
refreshPanel: function() {
|
||||||
{
|
|
||||||
if (!this.viewedElement) {
|
if (!this.viewedElement) {
|
||||||
return promise.resolve();
|
return promise.resolve();
|
||||||
}
|
}
|
||||||
|
@ -443,12 +438,12 @@ CssComputedView.prototype = {
|
||||||
onlyMatched: !this.includeBrowserStyles,
|
onlyMatched: !this.includeBrowserStyles,
|
||||||
markMatched: true
|
markMatched: true
|
||||||
})
|
})
|
||||||
]).then(([createViews, computed]) => {
|
]).then(([, computed]) => {
|
||||||
if (viewedElement !== this.viewedElement) {
|
if (viewedElement !== this.viewedElement) {
|
||||||
return;
|
return promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._matchedProperties = new Set;
|
this._matchedProperties = new Set();
|
||||||
for (let name in computed) {
|
for (let name in computed) {
|
||||||
if (computed[name].matched) {
|
if (computed[name].matched) {
|
||||||
this._matchedProperties.add(name);
|
this._matchedProperties.add(name);
|
||||||
|
@ -469,7 +464,8 @@ CssComputedView.prototype = {
|
||||||
this._darkStripe = true;
|
this._darkStripe = true;
|
||||||
|
|
||||||
let deferred = promise.defer();
|
let deferred = promise.defer();
|
||||||
this._refreshProcess = new UpdateProcess(this.styleWindow, this.propertyViews, {
|
this._refreshProcess = new UpdateProcess(
|
||||||
|
this.styleWindow, this.propertyViews, {
|
||||||
onItem: (aPropView) => {
|
onItem: (aPropView) => {
|
||||||
aPropView.refresh();
|
aPropView.refresh();
|
||||||
},
|
},
|
||||||
|
@ -511,8 +507,7 @@ CssComputedView.prototype = {
|
||||||
*
|
*
|
||||||
* @param {Event} aEvent the DOM Event object.
|
* @param {Event} aEvent the DOM Event object.
|
||||||
*/
|
*/
|
||||||
_onFilterStyles: function(aEvent)
|
_onFilterStyles: function(aEvent) {
|
||||||
{
|
|
||||||
let win = this.styleWindow;
|
let win = this.styleWindow;
|
||||||
|
|
||||||
if (this._filterChangedTimeout) {
|
if (this._filterChangedTimeout) {
|
||||||
|
@ -580,8 +575,7 @@ CssComputedView.prototype = {
|
||||||
*
|
*
|
||||||
* @param {Event} aEvent the DOM Event object.
|
* @param {Event} aEvent the DOM Event object.
|
||||||
*/
|
*/
|
||||||
_onIncludeBrowserStyles: function(aEvent)
|
_onIncludeBrowserStyles: function(aEvent) {
|
||||||
{
|
|
||||||
this.refreshSourceFilter();
|
this.refreshSourceFilter();
|
||||||
this.refreshPanel();
|
this.refreshPanel();
|
||||||
},
|
},
|
||||||
|
@ -592,16 +586,14 @@ CssComputedView.prototype = {
|
||||||
* document or one of thedocument's stylesheets. If .checked is false we
|
* document or one of thedocument's stylesheets. If .checked is false we
|
||||||
* display all properties including those that come from UA stylesheets.
|
* display all properties including those that come from UA stylesheets.
|
||||||
*/
|
*/
|
||||||
refreshSourceFilter: function CssComputedView_setSourceFilter()
|
refreshSourceFilter: function() {
|
||||||
{
|
|
||||||
this._matchedProperties = null;
|
this._matchedProperties = null;
|
||||||
this._sourceFilter = this.includeBrowserStyles ?
|
this._sourceFilter = this.includeBrowserStyles ?
|
||||||
CssLogic.FILTER.UA :
|
CssLogic.FILTER.UA :
|
||||||
CssLogic.FILTER.USER;
|
CssLogic.FILTER.USER;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSourcePrefChanged: function CssComputedView__onSourcePrefChanged()
|
_onSourcePrefChanged: function() {
|
||||||
{
|
|
||||||
for (let propView of this.propertyViews) {
|
for (let propView of this.propertyViews) {
|
||||||
propView.updateSourceLinks();
|
propView.updateSourceLinks();
|
||||||
}
|
}
|
||||||
|
@ -611,8 +603,7 @@ CssComputedView.prototype = {
|
||||||
/**
|
/**
|
||||||
* The CSS as displayed by the UI.
|
* The CSS as displayed by the UI.
|
||||||
*/
|
*/
|
||||||
createStyleViews: function CssComputedView_createStyleViews()
|
createStyleViews: function() {
|
||||||
{
|
|
||||||
if (CssComputedView.propertyNames) {
|
if (CssComputedView.propertyNames) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -641,8 +632,8 @@ CssComputedView.prototype = {
|
||||||
|
|
||||||
this._createPropertyViews().then(null, e => {
|
this._createPropertyViews().then(null, e => {
|
||||||
if (!this._isDestroyed) {
|
if (!this._isDestroyed) {
|
||||||
console.warn("The creation of property views was cancelled because the " +
|
console.warn("The creation of property views was cancelled because " +
|
||||||
"computed-view was destroyed before it was done creating views");
|
"the computed-view was destroyed before it was done creating views");
|
||||||
} else {
|
} else {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
@ -654,18 +645,16 @@ CssComputedView.prototype = {
|
||||||
*
|
*
|
||||||
* @return {Set} If a property name is in the set, it has matching selectors.
|
* @return {Set} If a property name is in the set, it has matching selectors.
|
||||||
*/
|
*/
|
||||||
get matchedProperties()
|
get matchedProperties() {
|
||||||
{
|
return this._matchedProperties || new Set();
|
||||||
return this._matchedProperties || new Set;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focus the window on mousedown.
|
* 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;
|
let win = this.styleDocument.defaultView;
|
||||||
win.focus();
|
win.focus();
|
||||||
},
|
},
|
||||||
|
@ -707,8 +696,8 @@ CssComputedView.prototype = {
|
||||||
let win = this.styleDocument.defaultView;
|
let win = this.styleDocument.defaultView;
|
||||||
let text = win.getSelection().toString().trim();
|
let text = win.getSelection().toString().trim();
|
||||||
|
|
||||||
// Tidy up block headings by moving CSS property names and their values onto
|
// Tidy up block headings by moving CSS property names and their
|
||||||
// the same line and inserting a colon between them.
|
// values onto the same line and inserting a colon between them.
|
||||||
let textArray = text.split(/[\r\n]+/);
|
let textArray = text.split(/[\r\n]+/);
|
||||||
let result = "";
|
let result = "";
|
||||||
|
|
||||||
|
@ -737,8 +726,7 @@ CssComputedView.prototype = {
|
||||||
/**
|
/**
|
||||||
* Destructor for CssComputedView.
|
* Destructor for CssComputedView.
|
||||||
*/
|
*/
|
||||||
destroy: function CssComputedView_destroy()
|
destroy: function() {
|
||||||
{
|
|
||||||
this.viewedElement = null;
|
this.viewedElement = null;
|
||||||
this._outputParser = null;
|
this._outputParser = null;
|
||||||
|
|
||||||
|
@ -819,8 +807,7 @@ PropertyInfo.prototype = {
|
||||||
* @param {string} aName the CSS property name for which this PropertyView
|
* @param {string} aName the CSS property name for which this PropertyView
|
||||||
* instance will render the rules.
|
* instance will render the rules.
|
||||||
*/
|
*/
|
||||||
function PropertyView(aTree, aName)
|
function PropertyView(aTree, aName) {
|
||||||
{
|
|
||||||
this.tree = aTree;
|
this.tree = aTree;
|
||||||
this.name = aName;
|
this.name = aName;
|
||||||
this.getRTLAttr = aTree.getRTLAttr;
|
this.getRTLAttr = aTree.getRTLAttr;
|
||||||
|
@ -864,32 +851,28 @@ PropertyView.prototype = {
|
||||||
* @return {string} the computed style for the current property of the
|
* @return {string} the computed style for the current property of the
|
||||||
* currently highlighted element.
|
* currently highlighted element.
|
||||||
*/
|
*/
|
||||||
get value()
|
get value() {
|
||||||
{
|
|
||||||
return this.propertyInfo.value;
|
return this.propertyInfo.value;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An easy way to access the CssPropertyInfo behind this PropertyView.
|
* An easy way to access the CssPropertyInfo behind this PropertyView.
|
||||||
*/
|
*/
|
||||||
get propertyInfo()
|
get propertyInfo() {
|
||||||
{
|
|
||||||
return this._propertyInfo;
|
return this._propertyInfo;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the property have any matched selectors?
|
* Does the property have any matched selectors?
|
||||||
*/
|
*/
|
||||||
get hasMatchedSelectors()
|
get hasMatchedSelectors() {
|
||||||
{
|
|
||||||
return this.tree.matchedProperties.has(this.name);
|
return this.tree.matchedProperties.has(this.name);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should this property be visible?
|
* Should this property be visible?
|
||||||
*/
|
*/
|
||||||
get visible()
|
get visible() {
|
||||||
{
|
|
||||||
if (!this.tree.viewedElement) {
|
if (!this.tree.viewedElement) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -913,8 +896,7 @@ PropertyView.prototype = {
|
||||||
* Returns the className that should be assigned to the propertyView.
|
* Returns the className that should be assigned to the propertyView.
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
get propertyHeaderClassName()
|
get propertyHeaderClassName() {
|
||||||
{
|
|
||||||
if (this.visible) {
|
if (this.visible) {
|
||||||
let isDark = this.tree._darkStripe = !this.tree._darkStripe;
|
let isDark = this.tree._darkStripe = !this.tree._darkStripe;
|
||||||
return isDark ? "property-view row-striped" : "property-view";
|
return isDark ? "property-view row-striped" : "property-view";
|
||||||
|
@ -927,8 +909,7 @@ PropertyView.prototype = {
|
||||||
* container.
|
* container.
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
get propertyContentClassName()
|
get propertyContentClassName() {
|
||||||
{
|
|
||||||
if (this.visible) {
|
if (this.visible) {
|
||||||
let isDark = this.tree._darkStripe;
|
let isDark = this.tree._darkStripe;
|
||||||
return isDark ? "property-content row-striped" : "property-content";
|
return isDark ? "property-content row-striped" : "property-content";
|
||||||
|
@ -940,8 +921,7 @@ PropertyView.prototype = {
|
||||||
* Build the markup for on computed style
|
* Build the markup for on computed style
|
||||||
* @return Element
|
* @return Element
|
||||||
*/
|
*/
|
||||||
buildMain: function PropertyView_buildMain()
|
buildMain: function() {
|
||||||
{
|
|
||||||
let doc = this.tree.styleDocument;
|
let doc = this.tree.styleDocument;
|
||||||
|
|
||||||
// Build the container element
|
// Build the container element
|
||||||
|
@ -998,8 +978,7 @@ PropertyView.prototype = {
|
||||||
return this.element;
|
return this.element;
|
||||||
},
|
},
|
||||||
|
|
||||||
buildSelectorContainer: function PropertyView_buildSelectorContainer()
|
buildSelectorContainer: function() {
|
||||||
{
|
|
||||||
let doc = this.tree.styleDocument;
|
let doc = this.tree.styleDocument;
|
||||||
let element = doc.createElementNS(HTML_NS, "div");
|
let element = doc.createElementNS(HTML_NS, "div");
|
||||||
element.setAttribute("class", this.propertyContentClassName);
|
element.setAttribute("class", this.propertyContentClassName);
|
||||||
|
@ -1013,8 +992,7 @@ PropertyView.prototype = {
|
||||||
/**
|
/**
|
||||||
* Refresh the panel's CSS property value.
|
* Refresh the panel's CSS property value.
|
||||||
*/
|
*/
|
||||||
refresh: function PropertyView_refresh()
|
refresh: function() {
|
||||||
{
|
|
||||||
this.element.className = this.propertyHeaderClassName;
|
this.element.className = this.propertyHeaderClassName;
|
||||||
this.element.nextElementSibling.className = this.propertyContentClassName;
|
this.element.nextElementSibling.className = this.propertyContentClassName;
|
||||||
|
|
||||||
|
@ -1051,8 +1029,7 @@ PropertyView.prototype = {
|
||||||
/**
|
/**
|
||||||
* Refresh the panel matched rules.
|
* Refresh the panel matched rules.
|
||||||
*/
|
*/
|
||||||
refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors()
|
refreshMatchedSelectors: function() {
|
||||||
{
|
|
||||||
let hasMatchedSelectors = this.hasMatchedSelectors;
|
let hasMatchedSelectors = this.hasMatchedSelectors;
|
||||||
this.matchedSelectorsContainer.parentNode.hidden = !hasMatchedSelectors;
|
this.matchedSelectorsContainer.parentNode.hidden = !hasMatchedSelectors;
|
||||||
|
|
||||||
|
@ -1063,9 +1040,11 @@ PropertyView.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.matchedExpanded && hasMatchedSelectors) {
|
if (this.matchedExpanded && hasMatchedSelectors) {
|
||||||
return this.tree.pageStyle.getMatchedSelectors(this.tree.viewedElement, this.name).then(matched => {
|
return this.tree.pageStyle
|
||||||
|
.getMatchedSelectors(this.tree.viewedElement, this.name)
|
||||||
|
.then(matched => {
|
||||||
if (!this.matchedExpanded) {
|
if (!this.matchedExpanded) {
|
||||||
return;
|
return promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._matchedSelectorResponse = matched;
|
this._matchedSelectorResponse = matched;
|
||||||
|
@ -1075,16 +1054,15 @@ PropertyView.prototype = {
|
||||||
this.tree.inspector.emit("computed-view-property-expanded");
|
this.tree.inspector.emit("computed-view-property-expanded");
|
||||||
});
|
});
|
||||||
}).then(null, console.error);
|
}).then(null, console.error);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
this.matchedSelectorsContainer.innerHTML = "";
|
this.matchedSelectorsContainer.innerHTML = "";
|
||||||
this.matchedExpander.removeAttribute("open");
|
this.matchedExpander.removeAttribute("open");
|
||||||
this.tree.inspector.emit("computed-view-property-collapsed");
|
this.tree.inspector.emit("computed-view-property-collapsed");
|
||||||
return promise.resolve(undefined);
|
return promise.resolve(undefined);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
get matchedSelectors()
|
get matchedSelectors() {
|
||||||
{
|
|
||||||
return this._matchedSelectorResponse;
|
return this._matchedSelectorResponse;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1130,13 +1108,13 @@ PropertyView.prototype = {
|
||||||
* Provide access to the matched SelectorViews that we are currently
|
* Provide access to the matched SelectorViews that we are currently
|
||||||
* displaying.
|
* displaying.
|
||||||
*/
|
*/
|
||||||
get matchedSelectorViews()
|
get matchedSelectorViews() {
|
||||||
{
|
|
||||||
if (!this._matchedSelectorViews) {
|
if (!this._matchedSelectorViews) {
|
||||||
this._matchedSelectorViews = [];
|
this._matchedSelectorViews = [];
|
||||||
this._matchedSelectorResponse.forEach(
|
this._matchedSelectorResponse.forEach(
|
||||||
function matchedSelectorViews_convert(aSelectorInfo) {
|
function(aSelectorInfo) {
|
||||||
this._matchedSelectorViews.push(new SelectorView(this.tree, aSelectorInfo));
|
let selectorView = new SelectorView(this.tree, aSelectorInfo);
|
||||||
|
this._matchedSelectorViews.push(selectorView);
|
||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
return this._matchedSelectorViews;
|
return this._matchedSelectorViews;
|
||||||
|
@ -1146,8 +1124,7 @@ PropertyView.prototype = {
|
||||||
* Update all the selector source links to reflect whether we're linking to
|
* Update all the selector source links to reflect whether we're linking to
|
||||||
* original sources (e.g. Sass files).
|
* original sources (e.g. Sass files).
|
||||||
*/
|
*/
|
||||||
updateSourceLinks: function PropertyView_updateSourceLinks()
|
updateSourceLinks: function() {
|
||||||
{
|
|
||||||
if (!this._matchedSelectorViews) {
|
if (!this._matchedSelectorViews) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1162,8 +1139,7 @@ PropertyView.prototype = {
|
||||||
* @param {Event} aEvent Used to determine the class name of the targets click
|
* @param {Event} aEvent Used to determine the class name of the targets click
|
||||||
* event.
|
* event.
|
||||||
*/
|
*/
|
||||||
onMatchedToggle: function PropertyView_onMatchedToggle(aEvent)
|
onMatchedToggle: function(aEvent) {
|
||||||
{
|
|
||||||
if (aEvent.shiftKey) {
|
if (aEvent.shiftKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1175,8 +1151,7 @@ PropertyView.prototype = {
|
||||||
/**
|
/**
|
||||||
* The action when a user clicks on the MDN help link for a property.
|
* 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;
|
let inspector = this.tree.inspector;
|
||||||
|
|
||||||
if (inspector.target.tab) {
|
if (inspector.target.tab) {
|
||||||
|
@ -1189,7 +1164,7 @@ PropertyView.prototype = {
|
||||||
/**
|
/**
|
||||||
* Destroy this property view, removing event listeners
|
* Destroy this property view, removing event listeners
|
||||||
*/
|
*/
|
||||||
destroy: function PropertyView_destroy() {
|
destroy: function() {
|
||||||
this.element.removeEventListener("dblclick", this.onMatchedToggle, false);
|
this.element.removeEventListener("dblclick", this.onMatchedToggle, false);
|
||||||
this.element.removeEventListener("keydown", this.onKeyDown, false);
|
this.element.removeEventListener("keydown", this.onKeyDown, false);
|
||||||
this.element = null;
|
this.element = null;
|
||||||
|
@ -1210,8 +1185,7 @@ PropertyView.prototype = {
|
||||||
* @param CssComputedView aTree, the owning CssComputedView
|
* @param CssComputedView aTree, the owning CssComputedView
|
||||||
* @param aSelectorInfo
|
* @param aSelectorInfo
|
||||||
*/
|
*/
|
||||||
function SelectorView(aTree, aSelectorInfo)
|
function SelectorView(aTree, aSelectorInfo) {
|
||||||
{
|
|
||||||
this.tree = aTree;
|
this.tree = aTree;
|
||||||
this.selectorInfo = aSelectorInfo;
|
this.selectorInfo = aSelectorInfo;
|
||||||
this._cacheStatusNames();
|
this._cacheStatusNames();
|
||||||
|
@ -1245,8 +1219,7 @@ SelectorView.prototype = {
|
||||||
*
|
*
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
_cacheStatusNames: function SelectorView_cacheStatusNames()
|
_cacheStatusNames: function() {
|
||||||
{
|
|
||||||
if (SelectorView.STATUS_NAMES.length) {
|
if (SelectorView.STATUS_NAMES.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1256,7 +1229,7 @@ SelectorView.prototype = {
|
||||||
if (i > CssLogic.STATUS.UNMATCHED) {
|
if (i > CssLogic.STATUS.UNMATCHED) {
|
||||||
let value = CssComputedView.l10n("rule.status." + status);
|
let value = CssComputedView.l10n("rule.status." + status);
|
||||||
// Replace normal spaces with non-breaking spaces
|
// 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
|
* A localized version of cssRule.status
|
||||||
*/
|
*/
|
||||||
get statusText()
|
get statusText() {
|
||||||
{
|
|
||||||
return SelectorView.STATUS_NAMES[this.selectorInfo.status];
|
return SelectorView.STATUS_NAMES[this.selectorInfo.status];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get class name for selector depending on status
|
* Get class name for selector depending on status
|
||||||
*/
|
*/
|
||||||
get statusClass()
|
get statusClass() {
|
||||||
{
|
|
||||||
return SelectorView.CLASS_NAMES[this.selectorInfo.status - 1];
|
return SelectorView.CLASS_NAMES[this.selectorInfo.status - 1];
|
||||||
},
|
},
|
||||||
|
|
||||||
get href()
|
get href() {
|
||||||
{
|
|
||||||
if (this._href) {
|
if (this._href) {
|
||||||
return this._href;
|
return this._href;
|
||||||
}
|
}
|
||||||
|
@ -1287,19 +1257,15 @@ SelectorView.prototype = {
|
||||||
return this._href;
|
return this._href;
|
||||||
},
|
},
|
||||||
|
|
||||||
get sourceText()
|
get sourceText() {
|
||||||
{
|
|
||||||
return this.selectorInfo.sourceText;
|
return this.selectorInfo.sourceText;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get value() {
|
||||||
get value()
|
|
||||||
{
|
|
||||||
return this.selectorInfo.value;
|
return this.selectorInfo.value;
|
||||||
},
|
},
|
||||||
|
|
||||||
get outputFragment()
|
get outputFragment() {
|
||||||
{
|
|
||||||
// Sadly, because this fragment is added to the template by DOM Templater
|
// 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
|
// 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
|
// 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
|
* Update the text of the source link to reflect whether we're showing
|
||||||
* original sources or not.
|
* original sources or not.
|
||||||
*/
|
*/
|
||||||
updateSourceLink: function()
|
updateSourceLink: function() {
|
||||||
{
|
|
||||||
return this.updateSource().then((oldSource) => {
|
return this.updateSource().then((oldSource) => {
|
||||||
if (oldSource != this.source && this.tree.element) {
|
if (oldSource != this.source && this.tree.element) {
|
||||||
let selector = '[sourcelocation="' + oldSource + '"]';
|
let selector = '[sourcelocation="' + oldSource + '"]';
|
||||||
|
@ -1337,8 +1302,7 @@ SelectorView.prototype = {
|
||||||
/**
|
/**
|
||||||
* Update the 'source' store based on our original sources preference.
|
* Update the 'source' store based on our original sources preference.
|
||||||
*/
|
*/
|
||||||
updateSource: function()
|
updateSource: function() {
|
||||||
{
|
|
||||||
let rule = this.selectorInfo.rule;
|
let rule = this.selectorInfo.rule;
|
||||||
this.sheet = rule.parentStyleSheet;
|
this.sheet = rule.parentStyleSheet;
|
||||||
|
|
||||||
|
@ -1373,8 +1337,7 @@ SelectorView.prototype = {
|
||||||
/**
|
/**
|
||||||
* Open the style editor if the RETURN key was pressed.
|
* Open the style editor if the RETURN key was pressed.
|
||||||
*/
|
*/
|
||||||
maybeOpenStyleEditor: function(aEvent)
|
maybeOpenStyleEditor: function(aEvent) {
|
||||||
{
|
|
||||||
let keyEvent = Ci.nsIDOMKeyEvent;
|
let keyEvent = Ci.nsIDOMKeyEvent;
|
||||||
if (aEvent.keyCode == keyEvent.DOM_VK_RETURN) {
|
if (aEvent.keyCode == keyEvent.DOM_VK_RETURN) {
|
||||||
this.openStyleEditor();
|
this.openStyleEditor();
|
||||||
|
@ -1391,8 +1354,7 @@ SelectorView.prototype = {
|
||||||
*
|
*
|
||||||
* @param aEvent The click event
|
* @param aEvent The click event
|
||||||
*/
|
*/
|
||||||
openStyleEditor: function(aEvent)
|
openStyleEditor: function(aEvent) {
|
||||||
{
|
|
||||||
let inspector = this.tree.inspector;
|
let inspector = this.tree.inspector;
|
||||||
let rule = this.selectorInfo.rule;
|
let rule = this.selectorInfo.rule;
|
||||||
|
|
||||||
|
@ -1401,15 +1363,8 @@ SelectorView.prototype = {
|
||||||
//
|
//
|
||||||
// If the stylesheet is a content stylesheet we send it to the style
|
// If the stylesheet is a content stylesheet we send it to the style
|
||||||
// editor else we display it in the view source window.
|
// editor else we display it in the view source window.
|
||||||
let sheet = rule.parentStyleSheet;
|
let parentStyleSheet = rule.parentStyleSheet;
|
||||||
if (!sheet || sheet.isSystem) {
|
if (!parentStyleSheet || parentStyleSheet.isSystem) {
|
||||||
let contentDoc = null;
|
|
||||||
if (this.tree.viewedElement.isLocal_toBeDeprecated()) {
|
|
||||||
let rawNode = this.tree.viewedElement.rawNode();
|
|
||||||
if (rawNode) {
|
|
||||||
contentDoc = rawNode.ownerDocument;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let toolbox = gDevTools.getToolbox(inspector.target);
|
let toolbox = gDevTools.getToolbox(inspector.target);
|
||||||
toolbox.viewSource(rule.href, rule.line);
|
toolbox.viewSource(rule.href, rule.line);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* globals overlays, Services, EventEmitter, StyleInspectorMenu,
|
/* globals overlays, Services, EventEmitter, StyleInspectorMenu,
|
||||||
clipboardHelper, _strings, domUtils, AutocompletePopup */
|
clipboardHelper, _strings, domUtils, AutocompletePopup, loader,
|
||||||
|
osString */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -209,7 +210,7 @@ ElementStyle.prototype = {
|
||||||
filter: this.showUserAgentStyles ? "ua" : undefined,
|
filter: this.showUserAgentStyles ? "ua" : undefined,
|
||||||
}).then(entries => {
|
}).then(entries => {
|
||||||
if (this.destroyed) {
|
if (this.destroyed) {
|
||||||
return;
|
return promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the dummy element has been created before continuing...
|
// 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.
|
// We're done with the previous list of rules.
|
||||||
delete this._refreshRules;
|
delete this._refreshRules;
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
}).then(null, e => {
|
}).then(null, e => {
|
||||||
// populate is often called after a setTimeout,
|
// populate is often called after a setTimeout,
|
||||||
// the connection may already be closed.
|
// the connection may already be closed.
|
||||||
if (this.destroyed) {
|
if (this.destroyed) {
|
||||||
return;
|
return promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
return promiseWarn(e);
|
return promiseWarn(e);
|
||||||
});
|
});
|
||||||
|
@ -636,7 +635,7 @@ Rule.prototype = {
|
||||||
disabled.delete(this.style);
|
disabled.delete(this.style);
|
||||||
}
|
}
|
||||||
|
|
||||||
let promise = aModifications.apply().then(() => {
|
let modificationsPromise = aModifications.apply().then(() => {
|
||||||
let cssProps = {};
|
let cssProps = {};
|
||||||
for (let cssProp of parseDeclarations(this.style.cssText)) {
|
for (let cssProp of parseDeclarations(this.style.cssText)) {
|
||||||
cssProps[cssProp.name] = cssProp;
|
cssProps[cssProp.name] = cssProp;
|
||||||
|
@ -668,8 +667,8 @@ Rule.prototype = {
|
||||||
this.elementStyle._changed();
|
this.elementStyle._changed();
|
||||||
}).then(null, promiseWarn);
|
}).then(null, promiseWarn);
|
||||||
|
|
||||||
this._applyingModifications = promise;
|
this._applyingModifications = modificationsPromise;
|
||||||
return promise;
|
return modificationsPromise;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1111,7 +1110,8 @@ TextProperty.prototype = {
|
||||||
*/
|
*/
|
||||||
stringifyProperty: function() {
|
stringifyProperty: function() {
|
||||||
// Get the displayed property value
|
// 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
|
// Comment out property declarations that are not enabled
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
|
@ -1741,7 +1741,7 @@ CssRuleView.prototype = {
|
||||||
refreshPanel: function() {
|
refreshPanel: function() {
|
||||||
// Ignore refreshes during editing or when no element is selected.
|
// Ignore refreshes during editing or when no element is selected.
|
||||||
if (this.isEditing || !this._elementStyle) {
|
if (this.isEditing || !this._elementStyle) {
|
||||||
return;
|
return promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repopulate the element style once the current modifications are done.
|
// Repopulate the element style once the current modifications are done.
|
||||||
|
@ -1893,9 +1893,10 @@ CssRuleView.prototype = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expandable container in the rule view
|
* Creates an expandable container in the rule view
|
||||||
* @param {String} aLabel The label for the container header
|
* @param {String} aLabel
|
||||||
* @param {Boolean} isPseudo Whether or not the container will hold
|
* The label for the container header
|
||||||
* pseudo element rules
|
* @param {Boolean} isPseudo
|
||||||
|
* Whether or not the container will hold pseudo element rules
|
||||||
* @return {DOMNode} The container element
|
* @return {DOMNode} The container element
|
||||||
*/
|
*/
|
||||||
createExpandableContainer: function(aLabel, isPseudo = false) {
|
createExpandableContainer: function(aLabel, isPseudo = false) {
|
||||||
|
@ -1915,7 +1916,36 @@ CssRuleView.prototype = {
|
||||||
container.classList.add("ruleview-expandable-container");
|
container.classList.add("ruleview-expandable-container");
|
||||||
this.element.appendChild(container);
|
this.element.appendChild(container);
|
||||||
|
|
||||||
let toggleContainerVisibility = (isPseudo, showPseudo) => {
|
header.addEventListener("dblclick", () => {
|
||||||
|
this._toggleContainerVisibility(twisty, header, isPseudo,
|
||||||
|
!this.showPseudoElements);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
twisty.addEventListener("click", () => {
|
||||||
|
this._toggleContainerVisibility(twisty, header, isPseudo,
|
||||||
|
!this.showPseudoElements);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
if (isPseudo) {
|
||||||
|
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");
|
let isOpen = twisty.getAttribute("open");
|
||||||
|
|
||||||
if (isPseudo) {
|
if (isPseudo) {
|
||||||
|
@ -1937,20 +1967,6 @@ CssRuleView.prototype = {
|
||||||
} else {
|
} else {
|
||||||
twisty.setAttribute("open", "true");
|
twisty.setAttribute("open", "true");
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
header.addEventListener("dblclick", () => {
|
|
||||||
toggleContainerVisibility(isPseudo, !this.showPseudoElements);
|
|
||||||
}, false);
|
|
||||||
twisty.addEventListener("click", () => {
|
|
||||||
toggleContainerVisibility(isPseudo, !this.showPseudoElements);
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
if (isPseudo) {
|
|
||||||
toggleContainerVisibility(isPseudo, this.showPseudoElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
return container;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_getRuleViewHeaderClassName: function(isPseudo) {
|
_getRuleViewHeaderClassName: function(isPseudo) {
|
||||||
|
|
|
@ -231,6 +231,7 @@ StyleInspectorMenu.prototype = {
|
||||||
this.menuitemCopy.hidden = !this._hasTextSelected();
|
this.menuitemCopy.hidden = !this._hasTextSelected();
|
||||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||||
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrl();
|
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrl();
|
||||||
|
this.menuitemCopyUrl.hidden = !this._isImageUrl();
|
||||||
|
|
||||||
this.menuitemCopyRule.hidden = true;
|
this.menuitemCopyRule.hidden = true;
|
||||||
this.menuitemCopyLocation.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
|
* Retrieve the url for the selected image and copy it to the clipboard
|
||||||
*/
|
*/
|
||||||
_onCopyUrl: function() {
|
_onCopyUrl: function() {
|
||||||
|
if (!this._clickedNodeInfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
clipboardHelper.copyString(this._clickedNodeInfo.value.url);
|
clipboardHelper.copyString(this._clickedNodeInfo.value.url);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,20 @@ add_task(function*() {
|
||||||
copyRule: false
|
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",
|
desc: "Test Copy Property Declaration",
|
||||||
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
||||||
|
@ -66,6 +80,20 @@ add_task(function*() {
|
||||||
copyRule: false
|
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",
|
desc: "Test Copy Rule",
|
||||||
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
node: ruleEditor.rule.textProps[2].editor.nameSpan,
|
||||||
|
@ -74,6 +102,7 @@ add_task(function*() {
|
||||||
"\tcolor: #F00;[\\r\\n]+" +
|
"\tcolor: #F00;[\\r\\n]+" +
|
||||||
"\tbackground-color: #00F;[\\r\\n]+" +
|
"\tbackground-color: #00F;[\\r\\n]+" +
|
||||||
"\tfont-size: 12px;[\\r\\n]+" +
|
"\tfont-size: 12px;[\\r\\n]+" +
|
||||||
|
"\tborder-color: #00F !important;[\\r\\n]+" +
|
||||||
"}",
|
"}",
|
||||||
hidden: {
|
hidden: {
|
||||||
copyLocation: true,
|
copyLocation: true,
|
||||||
|
@ -124,6 +153,7 @@ add_task(function*() {
|
||||||
"\t\/\\* color: #F00; \\*\/[\\r\\n]+" +
|
"\t\/\\* color: #F00; \\*\/[\\r\\n]+" +
|
||||||
"\tbackground-color: #00F;[\\r\\n]+" +
|
"\tbackground-color: #00F;[\\r\\n]+" +
|
||||||
"\tfont-size: 12px;[\\r\\n]+" +
|
"\tfont-size: 12px;[\\r\\n]+" +
|
||||||
|
"\tborder-color: #00F !important;[\\r\\n]+" +
|
||||||
"}",
|
"}",
|
||||||
hidden: {
|
hidden: {
|
||||||
copyLocation: true,
|
copyLocation: true,
|
||||||
|
|
|
@ -80,6 +80,7 @@ function* testCopyUrlToClipboard({view, inspector}, type, selector, expected) {
|
||||||
yield popup;
|
yield popup;
|
||||||
|
|
||||||
info("Context menu is displayed");
|
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");
|
ok(!view._contextmenu.menuitemCopyImageDataUrl.hidden, "\"Copy Image Data-URL\" menu entry is displayed");
|
||||||
|
|
||||||
if (type == "data-uri") {
|
if (type == "data-uri") {
|
||||||
|
|
|
@ -6,4 +6,5 @@ html, body, #testid {
|
||||||
color: #F00;
|
color: #F00;
|
||||||
background-color: #00F;
|
background-color: #00F;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
border-color: #00F !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -558,6 +558,7 @@
|
||||||
@RESPATH@/components/AlarmsManager.manifest
|
@RESPATH@/components/AlarmsManager.manifest
|
||||||
@RESPATH@/components/Push.js
|
@RESPATH@/components/Push.js
|
||||||
@RESPATH@/components/Push.manifest
|
@RESPATH@/components/Push.manifest
|
||||||
|
@RESPATH@/components/PushClient.js
|
||||||
@RESPATH@/components/PushNotificationService.js
|
@RESPATH@/components/PushNotificationService.js
|
||||||
|
|
||||||
@RESPATH@/components/SlowScriptDebug.manifest
|
@RESPATH@/components/SlowScriptDebug.manifest
|
||||||
|
@ -637,6 +638,7 @@
|
||||||
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
@RESPATH@/components/nsUrlClassifierHashCompleter.js
|
||||||
@RESPATH@/components/nsUrlClassifierListManager.js
|
@RESPATH@/components/nsUrlClassifierListManager.js
|
||||||
@RESPATH@/components/nsUrlClassifierLib.js
|
@RESPATH@/components/nsUrlClassifierLib.js
|
||||||
|
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||||
@RESPATH@/components/url-classifier.xpt
|
@RESPATH@/components/url-classifier.xpt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,9 @@ quit-button.tooltiptext.mac = Quit %1$S (%2$S)
|
||||||
# approval before you change it.
|
# approval before you change it.
|
||||||
loop-call-button3.label = Hello
|
loop-call-button3.label = Hello
|
||||||
loop-call-button3.tooltiptext = Start a conversation
|
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.label = Share This Page
|
||||||
social-share-button.tooltiptext = 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
|
inactive_screenshare_button_title=Share your screen
|
||||||
share_tabs_button_title2=Share your Tabs
|
share_tabs_button_title2=Share your Tabs
|
||||||
share_windows_button_title=Share other Windows
|
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
|
## LOCALIZATION NOTE (call_with_contact_title): The title displayed
|
||||||
## when calling a contact. Don't translate the part between {{..}} because
|
## when calling a contact. Don't translate the part between {{..}} because
|
||||||
|
|
|
@ -115,7 +115,7 @@
|
||||||
.titlebar-button {
|
.titlebar-button {
|
||||||
border: none;
|
border: none;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
padding: 12px 17px;
|
padding: 10px 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-window[sizemode=maximized] .titlebar-button {
|
#main-window[sizemode=maximized] .titlebar-button {
|
||||||
|
@ -147,6 +147,20 @@
|
||||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
|
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
|
/* 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: */
|
* 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) {
|
@media (min-resolution: 1.20dppx) and (max-resolution: 1.45dppx) {
|
||||||
|
@ -222,20 +236,32 @@
|
||||||
background-color: Highlight;
|
background-color: Highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#titlebar-min {
|
||||||
|
list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-highcontrast);
|
||||||
|
}
|
||||||
#titlebar-min:hover {
|
#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 {
|
#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 {
|
#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 {
|
#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;
|
-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) {
|
#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
|
@ -771,8 +771,8 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||||
width: 32px;
|
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] > .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-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-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]: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 */ {
|
#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;
|
-moz-padding-end: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* overlap the urlbar's border */
|
||||||
|
#PopupAutoCompleteRichResult {
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (-moz-os-version: windows-xp),
|
@media (-moz-os-version: windows-xp),
|
||||||
(-moz-os-version: windows-vista),
|
(-moz-os-version: windows-vista),
|
||||||
(-moz-os-version: windows-win7) {
|
(-moz-os-version: windows-win7) {
|
||||||
|
@ -1246,6 +1251,11 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||||
.searchbar-textbox:not(:-moz-lwtheme)[focused] {
|
.searchbar-textbox:not(:-moz-lwtheme)[focused] {
|
||||||
box-shadow: 0 0 0 1px Highlight inset;
|
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) {
|
@media not all and (-moz-os-version: windows-xp) {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
fill: none;
|
fill: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
g:not(#close) {
|
g:not([id|="close"]) {
|
||||||
shape-rendering: crispEdges;
|
shape-rendering: crispEdges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,17 +21,36 @@
|
||||||
display: initial;
|
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;
|
stroke: HighlightText;
|
||||||
}
|
}
|
||||||
|
|
||||||
[id$="-white"] > g {
|
[id$="-white"] > g {
|
||||||
stroke: #fff;
|
stroke: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<g id="close">
|
<g id="close">
|
||||||
<line x1="1" y1="1" x2="11" y2="11"/>
|
<path d="M1,1 l 10,10 M1,11 l 10,-10"/>
|
||||||
<line x1="11" y1="1" x2="1" y2="11"/>
|
|
||||||
</g>
|
</g>
|
||||||
<g id="maximize">
|
<g id="maximize">
|
||||||
<rect x="1.5" y="1.5" width="9" height="9"/>
|
<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"/>
|
<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"/>
|
<polyline points="3.5,3.5 3.5,1.5 10.5,1.5 10.5,8.5 8.5,8.5"/>
|
||||||
</g>
|
</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="close-white" xlink:href="#close"/>
|
||||||
<use id="maximize-white" xlink:href="#maximize"/>
|
<use id="maximize-white" xlink:href="#maximize"/>
|
||||||
<use id="minimize-white" xlink:href="#minimize"/>
|
<use id="minimize-white" xlink:href="#minimize"/>
|
||||||
<use id="restore-white" xlink:href="#restore"/>
|
<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>
|
</svg>
|
||||||
|
|
До Ширина: | Высота: | Размер: 1.5 KiB После Ширина: | Высота: | Размер: 3.0 KiB |
|
@ -1,6 +1,7 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "clang/AST/ASTConsumer.h"
|
#include "clang/AST/ASTConsumer.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
#include "clang/AST/RecursiveASTVisitor.h"
|
#include "clang/AST/RecursiveASTVisitor.h"
|
||||||
|
@ -56,7 +57,6 @@ private:
|
||||||
ScopeChecker(Scope scope_) :
|
ScopeChecker(Scope scope_) :
|
||||||
scope(scope_) {}
|
scope(scope_) {}
|
||||||
virtual void run(const MatchFinder::MatchResult &Result);
|
virtual void run(const MatchFinder::MatchResult &Result);
|
||||||
void noteInferred(QualType T, DiagnosticsEngine &Diag);
|
|
||||||
private:
|
private:
|
||||||
Scope scope;
|
Scope scope;
|
||||||
};
|
};
|
||||||
|
@ -64,7 +64,6 @@ private:
|
||||||
class NonHeapClassChecker : public MatchFinder::MatchCallback {
|
class NonHeapClassChecker : public MatchFinder::MatchCallback {
|
||||||
public:
|
public:
|
||||||
virtual void run(const MatchFinder::MatchResult &Result);
|
virtual void run(const MatchFinder::MatchResult &Result);
|
||||||
void noteInferred(QualType T, DiagnosticsEngine &Diag);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArithmeticArgChecker : public MatchFinder::MatchCallback {
|
class ArithmeticArgChecker : public MatchFinder::MatchCallback {
|
||||||
|
@ -97,6 +96,16 @@ private:
|
||||||
virtual void run(const MatchFinder::MatchResult &Result);
|
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 stackClassChecker;
|
||||||
ScopeChecker globalClassChecker;
|
ScopeChecker globalClassChecker;
|
||||||
NonHeapClassChecker nonheapClassChecker;
|
NonHeapClassChecker nonheapClassChecker;
|
||||||
|
@ -106,6 +115,8 @@ private:
|
||||||
NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
|
NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
|
||||||
RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
|
RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
|
||||||
ExplicitOperatorBoolChecker explicitOperatorBoolChecker;
|
ExplicitOperatorBoolChecker explicitOperatorBoolChecker;
|
||||||
|
NeedsNoVTableTypeChecker needsNoVTableTypeChecker;
|
||||||
|
NonMemMovableChecker nonMemMovableChecker;
|
||||||
MatchFinder astMatcher;
|
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> {
|
class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
|
||||||
DiagnosticsEngine &Diag;
|
DiagnosticsEngine &Diag;
|
||||||
const CompilerInstance &CI;
|
const CompilerInstance &CI;
|
||||||
|
@ -232,29 +288,29 @@ public:
|
||||||
TraverseDecl(ctx.getTranslationUnitDecl());
|
TraverseDecl(ctx.getTranslationUnitDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hasCustomAnnotation(const Decl *d, const char *spelling) {
|
static bool hasCustomAnnotation(const Decl *D, const char *Spelling) {
|
||||||
AnnotateAttr *attr = d->getAttr<AnnotateAttr>();
|
iterator_range<specific_attr_iterator<AnnotateAttr> > Attrs =
|
||||||
if (!attr)
|
D->specific_attrs<AnnotateAttr>();
|
||||||
return false;
|
|
||||||
|
|
||||||
return attr->getAnnotation() == spelling;
|
for (AnnotateAttr *Attr : Attrs) {
|
||||||
|
if (Attr->getAnnotation() == Spelling) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleUnusedExprResult(const Stmt *stmt) {
|
void HandleUnusedExprResult(const Stmt *stmt) {
|
||||||
const Expr* E = dyn_cast_or_null<Expr>(stmt);
|
const Expr* E = dyn_cast_or_null<Expr>(stmt);
|
||||||
if (E) {
|
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();
|
QualType T = E->getType();
|
||||||
CXXRecordDecl *decl = T->getAsCXXRecordDecl();
|
if (MustUse.hasEffectiveAnnotation(T)) {
|
||||||
if (decl) {
|
|
||||||
decl = decl->getDefinition();
|
|
||||||
if (decl && hasCustomAnnotation(decl, "moz_must_use")) {
|
|
||||||
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||||
DiagnosticIDs::Error, "Unused MOZ_MUST_USE value of type %0");
|
DiagnosticIDs::Error, "Unused value of must-use type %0");
|
||||||
|
|
||||||
Diag.Report(E->getLocStart(), errorID) << T;
|
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.
|
/// A cached data of whether classes are refcounted or not.
|
||||||
typedef DenseMap<const CXXRecordDecl *,
|
typedef DenseMap<const CXXRecordDecl *,
|
||||||
std::pair<const Decl *, bool> > RefCountedMap;
|
std::pair<const Decl *, bool> > RefCountedMap;
|
||||||
|
@ -527,7 +487,88 @@ bool isClassRefCounted(QualType T) {
|
||||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||||
T = arrTy->getElementType();
|
T = arrTy->getElementType();
|
||||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
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>
|
template<class T>
|
||||||
|
@ -540,6 +581,13 @@ bool IsInSystemHeader(const ASTContext &AC, const T &D) {
|
||||||
return SourceManager.isInSystemHeader(ExpansionLoc);
|
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 {
|
namespace clang {
|
||||||
|
@ -548,19 +596,19 @@ namespace ast_matchers {
|
||||||
/// This matcher will match any class with the stack class assertion or an
|
/// This matcher will match any class with the stack class assertion or an
|
||||||
/// array of such classes.
|
/// array of such classes.
|
||||||
AST_MATCHER(QualType, stackClassAggregate) {
|
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
|
/// This matcher will match any class with the global class assertion or an
|
||||||
/// array of such classes.
|
/// array of such classes.
|
||||||
AST_MATCHER(QualType, globalClassAggregate) {
|
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
|
/// This matcher will match any class with the stack class assertion or an
|
||||||
/// array of such classes.
|
/// array of such classes.
|
||||||
AST_MATCHER(QualType, nonheapClassAggregate) {
|
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
|
/// This matcher will match any function declaration that is declared as a heap
|
||||||
|
@ -694,11 +742,126 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
|
||||||
|
|
||||||
#endif
|
#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 {
|
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) {
|
bool isPlacementNew(const CXXNewExpr *expr) {
|
||||||
// Regular new expressions aren't placement new
|
// Regular new expressions aren't placement new
|
||||||
if (expr->getNumPlacementArgs() == 0)
|
if (expr->getNumPlacementArgs() == 0)
|
||||||
|
@ -816,6 +979,18 @@ DiagnosticsMatcher::DiagnosticsMatcher()
|
||||||
astMatcher.addMatcher(methodDecl(anyOf(hasName("operator bool"),
|
astMatcher.addMatcher(methodDecl(anyOf(hasName("operator bool"),
|
||||||
hasName("operator _Bool"))).bind("node"),
|
hasName("operator _Bool"))).bind("node"),
|
||||||
&explicitOperatorBoolChecker);
|
&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(
|
void DiagnosticsMatcher::ScopeChecker::run(
|
||||||
|
@ -825,7 +1000,9 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||||
DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
|
DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
|
||||||
unsigned globalID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
unsigned globalID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||||
DiagnosticIDs::Error, "variable of type %0 only valid as global");
|
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 (const VarDecl *d = Result.Nodes.getNodeAs<VarDecl>("node")) {
|
||||||
if (scope == eLocal) {
|
if (scope == eLocal) {
|
||||||
// Ignore the match if it's a local variable.
|
// Ignore the match if it's a local variable.
|
||||||
|
@ -840,56 +1017,29 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Diag.Report(d->getLocation(), errorID) << d->getType();
|
Loc = d->getLocation();
|
||||||
noteInferred(d->getType(), Diag);
|
T = d->getType();
|
||||||
} else if (const CXXNewExpr *expr =
|
} else if (const CXXNewExpr *expr =
|
||||||
Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
|
Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
|
||||||
// If it's placement new, then this match doesn't count.
|
// If it's placement new, then this match doesn't count.
|
||||||
if (scope == eLocal && isPlacementNew(expr))
|
if (scope == eLocal && isPlacementNew(expr))
|
||||||
return;
|
return;
|
||||||
Diag.Report(expr->getStartLoc(), errorID) << expr->getAllocatedType();
|
|
||||||
noteInferred(expr->getAllocatedType(), Diag);
|
Loc = expr->getStartLoc();
|
||||||
|
T = expr->getAllocatedType();
|
||||||
} else if (const CallExpr *expr =
|
} else if (const CallExpr *expr =
|
||||||
Result.Nodes.getNodeAs<CallExpr>("node")) {
|
Result.Nodes.getNodeAs<CallExpr>("node")) {
|
||||||
QualType badType = GetCallReturnType(expr)->getPointeeType();
|
Loc = expr->getLocStart();
|
||||||
Diag.Report(expr->getLocStart(), errorID) << badType;
|
T = GetCallReturnType(expr)->getPointeeType();
|
||||||
noteInferred(badType, Diag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagnosticsMatcher::ScopeChecker::noteInferred(QualType T,
|
if (scope == eLocal) {
|
||||||
DiagnosticsEngine &Diag) {
|
Diag.Report(Loc, stackID) << T;
|
||||||
unsigned inheritsID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
StackClass.dumpAnnotationReason(Diag, T, Loc);
|
||||||
DiagnosticIDs::Note,
|
} else if (scope == eGlobal) {
|
||||||
"%0 is a %2 class because it inherits from a %2 class %1");
|
Diag.Report(Loc, globalID) << T;
|
||||||
unsigned memberID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
GlobalClass.dumpAnnotationReason(Diag, T, Loc);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively follow this back.
|
|
||||||
noteInferred(cast<ValueDecl>(cause)->getType(), Diag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagnosticsMatcher::NonHeapClassChecker::run(
|
void DiagnosticsMatcher::NonHeapClassChecker::run(
|
||||||
|
@ -897,46 +1047,22 @@ void DiagnosticsMatcher::NonHeapClassChecker::run(
|
||||||
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
||||||
unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||||
DiagnosticIDs::Error, "variable of type %0 is not valid on the heap");
|
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 (const CXXNewExpr *expr = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
|
||||||
// If it's placement new, then this match doesn't count.
|
// If it's placement new, then this match doesn't count.
|
||||||
if (isPlacementNew(expr))
|
if (isPlacementNew(expr))
|
||||||
return;
|
return;
|
||||||
Diag.Report(expr->getStartLoc(), stackID) << expr->getAllocatedType();
|
Loc = expr->getLocStart();
|
||||||
noteInferred(expr->getAllocatedType(), Diag);
|
T = expr->getAllocatedType();
|
||||||
} else if (const CallExpr *expr = Result.Nodes.getNodeAs<CallExpr>("node")) {
|
} else if (const CallExpr *expr = Result.Nodes.getNodeAs<CallExpr>("node")) {
|
||||||
QualType badType = GetCallReturnType(expr)->getPointeeType();
|
Loc = expr->getLocStart();
|
||||||
Diag.Report(expr->getLocStart(), stackID) << badType;
|
T = GetCallReturnType(expr)->getPointeeType();
|
||||||
noteInferred(badType, Diag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagnosticsMatcher::NonHeapClassChecker::noteInferred(QualType T,
|
Diag.Report(Loc, stackID) << T;
|
||||||
DiagnosticsEngine &Diag) {
|
NonHeapClass.dumpAnnotationReason(Diag, T, Loc);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagnosticsMatcher::ArithmeticArgChecker::run(
|
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 {
|
class MozCheckAction : public PluginASTAction {
|
||||||
public:
|
public:
|
||||||
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {
|
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {
|
||||||
|
|
|
@ -16,9 +16,9 @@ void gobble(void *) { }
|
||||||
|
|
||||||
void misuseGlobalClass(int len) {
|
void misuseGlobalClass(int len) {
|
||||||
Global notValid; // expected-error {{variable of type 'Global' only valid as global}}
|
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 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);
|
||||||
gobble(¬Valid);
|
gobble(¬Valid);
|
||||||
|
@ -35,7 +35,7 @@ void misuseGlobalClass(int len) {
|
||||||
|
|
||||||
Global valid;
|
Global valid;
|
||||||
struct RandomClass {
|
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;
|
static Global staticMember;
|
||||||
};
|
};
|
||||||
struct MOZ_GLOBAL_CLASS RandomGlobalClass {
|
struct MOZ_GLOBAL_CLASS RandomGlobalClass {
|
||||||
|
@ -43,7 +43,7 @@ struct MOZ_GLOBAL_CLASS RandomGlobalClass {
|
||||||
static Global staticMember;
|
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 {};
|
struct MOZ_GLOBAL_CLASS GoodInherit : Global {};
|
||||||
|
|
||||||
void misuseGlobalClassEvenMore(int len) {
|
void misuseGlobalClassEvenMore(int len) {
|
||||||
|
|
|
@ -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 use(bool);
|
||||||
|
|
||||||
void foo() {
|
void foo() {
|
||||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMustUsePointer();
|
producesMustUsePointer();
|
||||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMayUse();
|
producesMayUse();
|
||||||
producesMayUsePointer();
|
producesMayUsePointer();
|
||||||
producesMayUseRef();
|
producesMayUseRef();
|
||||||
{
|
{
|
||||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMustUsePointer();
|
producesMustUsePointer();
|
||||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMayUse();
|
producesMayUse();
|
||||||
producesMayUsePointer();
|
producesMayUsePointer();
|
||||||
producesMayUseRef();
|
producesMayUseRef();
|
||||||
}
|
}
|
||||||
if (true) {
|
if (true) {
|
||||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMustUsePointer();
|
producesMustUsePointer();
|
||||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMayUse();
|
producesMayUse();
|
||||||
producesMayUsePointer();
|
producesMayUsePointer();
|
||||||
producesMayUseRef();
|
producesMayUseRef();
|
||||||
} else {
|
} else {
|
||||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMustUsePointer();
|
producesMustUsePointer();
|
||||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMayUse();
|
producesMayUse();
|
||||||
producesMayUsePointer();
|
producesMayUsePointer();
|
||||||
producesMayUseRef();
|
producesMayUseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(true) 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 MOZ_MUST_USE value of type 'MustUse'}}
|
else producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
if(true) producesMustUsePointer();
|
if(true) producesMustUsePointer();
|
||||||
else producesMustUsePointer();
|
else producesMustUsePointer();
|
||||||
if(true) 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 MOZ_MUST_USE value of type 'MustUse'}}
|
else producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
if(true) producesMayUse();
|
if(true) producesMayUse();
|
||||||
else producesMayUse();
|
else producesMayUse();
|
||||||
if(true) producesMayUsePointer();
|
if(true) producesMayUsePointer();
|
||||||
|
@ -63,18 +63,18 @@ void foo() {
|
||||||
if(true) producesMayUseRef();
|
if(true) producesMayUseRef();
|
||||||
else 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) 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) producesMayUse();
|
||||||
while (true) producesMayUsePointer();
|
while (true) producesMayUsePointer();
|
||||||
while (true) producesMayUseRef();
|
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);
|
while (true);
|
||||||
do producesMustUsePointer();
|
do producesMustUsePointer();
|
||||||
while (true);
|
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);
|
while (true);
|
||||||
do producesMayUse();
|
do producesMayUse();
|
||||||
while (true);
|
while (true);
|
||||||
|
@ -83,48 +83,48 @@ void foo() {
|
||||||
do producesMayUseRef();
|
do producesMayUseRef();
|
||||||
while (true);
|
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 (;;) 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 (;;) producesMayUse();
|
||||||
for (;;) producesMayUsePointer();
|
for (;;) producesMayUsePointer();
|
||||||
for (;;) producesMayUseRef();
|
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 (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 (producesMayUse();;);
|
||||||
for (producesMayUsePointer();;);
|
for (producesMayUsePointer();;);
|
||||||
for (producesMayUseRef();;);
|
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 (;;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 (;;producesMayUse());
|
||||||
for (;;producesMayUsePointer());
|
for (;;producesMayUsePointer());
|
||||||
for (;;producesMayUseRef());
|
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((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((producesMayUse(), false));
|
||||||
use((producesMayUsePointer(), false));
|
use((producesMayUsePointer(), false));
|
||||||
use((producesMayUseRef(), false));
|
use((producesMayUseRef(), false));
|
||||||
|
|
||||||
switch (1) {
|
switch (1) {
|
||||||
case 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();
|
producesMustUsePointer();
|
||||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMayUse();
|
producesMayUse();
|
||||||
producesMayUsePointer();
|
producesMayUsePointer();
|
||||||
producesMayUseRef();
|
producesMayUseRef();
|
||||||
case 2:
|
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:
|
case 3:
|
||||||
producesMustUsePointer();
|
producesMustUsePointer();
|
||||||
case 4:
|
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:
|
case 5:
|
||||||
producesMayUse();
|
producesMayUse();
|
||||||
case 6:
|
case 6:
|
||||||
|
@ -132,9 +132,9 @@ void foo() {
|
||||||
case 7:
|
case 7:
|
||||||
producesMayUseRef();
|
producesMayUseRef();
|
||||||
default:
|
default:
|
||||||
producesMustUse(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMustUsePointer();
|
producesMustUsePointer();
|
||||||
producesMustUseRef(); // expected-error {{Unused MOZ_MUST_USE value of type 'MustUse'}}
|
producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
|
||||||
producesMayUse();
|
producesMayUse();
|
||||||
producesMayUsePointer();
|
producesMayUsePointer();
|
||||||
producesMayUseRef();
|
producesMayUseRef();
|
||||||
|
|
|
@ -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;
|
NonHeap validStatic;
|
||||||
struct RandomClass {
|
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;
|
static NonHeap staticMember;
|
||||||
};
|
};
|
||||||
struct MOZ_NONHEAP_CLASS RandomNonHeapClass {
|
struct MOZ_NONHEAP_CLASS RandomNonHeapClass {
|
||||||
|
@ -44,7 +44,7 @@ struct MOZ_NONHEAP_CLASS RandomNonHeapClass {
|
||||||
static NonHeap staticMember;
|
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 {};
|
struct MOZ_NONHEAP_CLASS GoodInherit : NonHeap {};
|
||||||
|
|
||||||
void useStuffWrongly() {
|
void useStuffWrongly() {
|
||||||
|
@ -52,11 +52,11 @@ void useStuffWrongly() {
|
||||||
gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}}
|
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_STACK_CLASS StackClass {};
|
||||||
struct MOZ_NONHEAP_CLASS InferredStackClass : GoodInherit {
|
struct MOZ_NONHEAP_CLASS InferredStackClass : GoodInherit {
|
||||||
NonHeap nonstaticMember;
|
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}}
|
InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}}
|
||||||
|
|
|
@ -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 valid;
|
||||||
Stack alsoValid[2];
|
Stack alsoValid[2];
|
||||||
static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}}
|
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);
|
||||||
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}}
|
Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}}
|
||||||
struct RandomClass {
|
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}}
|
static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}}
|
||||||
};
|
};
|
||||||
struct MOZ_STACK_CLASS RandomStackClass {
|
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}}
|
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 {};
|
struct MOZ_STACK_CLASS GoodInherit : Stack {};
|
||||||
|
|
||||||
BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}}
|
BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}}
|
||||||
|
|
|
@ -9,13 +9,16 @@ SOURCES += [
|
||||||
'TestCustomHeap.cpp',
|
'TestCustomHeap.cpp',
|
||||||
'TestExplicitOperatorBool.cpp',
|
'TestExplicitOperatorBool.cpp',
|
||||||
'TestGlobalClass.cpp',
|
'TestGlobalClass.cpp',
|
||||||
|
'TestMultipleAnnotations.cpp',
|
||||||
'TestMustOverride.cpp',
|
'TestMustOverride.cpp',
|
||||||
'TestMustUse.cpp',
|
'TestMustUse.cpp',
|
||||||
'TestNANTestingExpr.cpp',
|
'TestNANTestingExpr.cpp',
|
||||||
'TestNANTestingExprC.c',
|
'TestNANTestingExprC.c',
|
||||||
|
'TestNeedsNoVTableType.cpp',
|
||||||
'TestNoAddRefReleaseOnReturn.cpp',
|
'TestNoAddRefReleaseOnReturn.cpp',
|
||||||
'TestNoArithmeticExprInArgument.cpp',
|
'TestNoArithmeticExprInArgument.cpp',
|
||||||
'TestNonHeapClass.cpp',
|
'TestNonHeapClass.cpp',
|
||||||
|
'TestNonMemMovable.cpp',
|
||||||
'TestNoRefcountedInsideLambdas.cpp',
|
'TestNoRefcountedInsideLambdas.cpp',
|
||||||
'TestStackClass.cpp',
|
'TestStackClass.cpp',
|
||||||
'TestTrivialCtorDtor.cpp',
|
'TestTrivialCtorDtor.cpp',
|
||||||
|
|
|
@ -109,6 +109,7 @@ class MachCommands(MachCommandBase):
|
||||||
'--show-possibly-lost=no',
|
'--show-possibly-lost=no',
|
||||||
'--track-origins=yes',
|
'--track-origins=yes',
|
||||||
'--trace-children=yes',
|
'--trace-children=yes',
|
||||||
|
'-v', # Enable verbosity to get the list of used suppressions
|
||||||
]
|
]
|
||||||
|
|
||||||
for s in suppressions:
|
for s in suppressions:
|
||||||
|
|
|
@ -1710,20 +1710,22 @@ nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t loadType = LOAD_NORMAL;
|
uint32_t loadType = LOAD_NORMAL;
|
||||||
|
nsCOMPtr<nsIPrincipal> requestingPrincipal;
|
||||||
if (aLoadInfo) {
|
if (aLoadInfo) {
|
||||||
nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
|
nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
|
||||||
(void)aLoadInfo->GetLoadType(<);
|
(void)aLoadInfo->GetLoadType(<);
|
||||||
// Get the appropriate LoadType from nsIDocShellLoadInfo type
|
// Get the appropriate LoadType from nsIDocShellLoadInfo type
|
||||||
loadType = ConvertDocShellLoadInfoToLoadType(lt);
|
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);
|
NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
|
||||||
|
|
||||||
mLoadType = loadType;
|
mLoadType = loadType;
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> owner;
|
|
||||||
aLoadInfo->GetOwner(getter_AddRefs(owner));
|
|
||||||
nsCOMPtr<nsIPrincipal> requestingPrincipal = do_QueryInterface(owner);
|
|
||||||
if (!requestingPrincipal) {
|
if (!requestingPrincipal) {
|
||||||
requestingPrincipal = nsContentUtils::GetSystemPrincipal();
|
requestingPrincipal = nsContentUtils::GetSystemPrincipal();
|
||||||
}
|
}
|
||||||
|
@ -2953,129 +2955,16 @@ nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
|
||||||
nsresult
|
nsresult
|
||||||
nsDocShell::PopProfileTimelineMarkers(
|
nsDocShell::PopProfileTimelineMarkers(
|
||||||
JSContext* aCx,
|
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
|
nsTArray<dom::ProfileTimelineMarker> store;
|
||||||
// START marker is found, look for the corresponding END marker and build a
|
SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
|
||||||
// {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<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
|
if (IsObserved()) {
|
||||||
SequenceRooter<mozilla::dom::ProfileTimelineMarker> rooter(
|
mObserved->PopMarkers(aCx, store);
|
||||||
aCx, &profileTimelineMarkers);
|
|
||||||
|
|
||||||
if (!IsObserved()) {
|
|
||||||
if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
|
|
||||||
JS_ClearPendingException(aCx);
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<UniquePtr<TimelineMarker>>& markersStore = mObserved.get()->mTimelineMarkers;
|
if (!ToJSValue(aCx, store, aOut)) {
|
||||||
|
|
||||||
// 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)) {
|
|
||||||
JS_ClearPendingException(aCx);
|
JS_ClearPendingException(aCx);
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,4 +34,101 @@ ObservedDocShell::ClearMarkers()
|
||||||
mTimelineMarkers.Clear();
|
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
|
} // namespace mozilla
|
||||||
|
|
|
@ -15,6 +15,9 @@ class nsDocShell;
|
||||||
class TimelineMarker;
|
class TimelineMarker;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
struct ProfileTimelineMarker;
|
||||||
|
}
|
||||||
|
|
||||||
// # ObservedDocShell
|
// # ObservedDocShell
|
||||||
//
|
//
|
||||||
|
@ -24,18 +27,16 @@ class ObservedDocShell : public LinkedListElement<ObservedDocShell>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
nsRefPtr<nsDocShell> mDocShell;
|
nsRefPtr<nsDocShell> mDocShell;
|
||||||
|
|
||||||
public:
|
|
||||||
// FIXME: make this private once all marker-specific logic has been
|
|
||||||
// moved out of nsDocShell.
|
|
||||||
nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
|
nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
|
||||||
|
|
||||||
|
public:
|
||||||
explicit ObservedDocShell(nsDocShell* aDocShell);
|
explicit ObservedDocShell(nsDocShell* aDocShell);
|
||||||
nsDocShell* operator*() const { return mDocShell.get(); }
|
nsDocShell* operator*() const { return mDocShell.get(); }
|
||||||
|
|
||||||
void AddMarker(const char* aName, TracingMetadata aMetaData);
|
void AddMarker(const char* aName, TracingMetadata aMetaData);
|
||||||
void AddMarker(UniquePtr<TimelineMarker>&& aMarker);
|
void AddMarker(UniquePtr<TimelineMarker>&& aMarker);
|
||||||
void ClearMarkers();
|
void ClearMarkers();
|
||||||
|
void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -2728,8 +2728,52 @@ Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
|
||||||
const Optional<Sequence<MediaKeySystemOptions>>& aOptions,
|
const Optional<Sequence<MediaKeySystemOptions>>& aOptions,
|
||||||
ErrorResult& aRv)
|
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);
|
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()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,13 @@
|
||||||
#include "mozilla/dom/MimeTypeArrayBinding.h"
|
#include "mozilla/dom/MimeTypeArrayBinding.h"
|
||||||
#include "mozilla/dom/MimeTypeBinding.h"
|
#include "mozilla/dom/MimeTypeBinding.h"
|
||||||
#include "nsIDOMNavigator.h"
|
#include "nsIDOMNavigator.h"
|
||||||
|
#include "nsPIDOMWindow.h"
|
||||||
#include "nsPluginArray.h"
|
#include "nsPluginArray.h"
|
||||||
#include "nsIMIMEService.h"
|
#include "nsIMIMEService.h"
|
||||||
#include "nsIMIMEInfo.h"
|
#include "nsIMIMEInfo.h"
|
||||||
#include "Navigator.h"
|
#include "Navigator.h"
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "nsPluginTags.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
@ -216,19 +218,22 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeType, mWindow, mPluginElement)
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeType, mWindow, mPluginElement)
|
||||||
|
|
||||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
|
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow,
|
||||||
uint32_t aPluginTagMimeIndex, const nsAString& aType)
|
nsPluginElement* aPluginElement,
|
||||||
|
const nsAString& aType,
|
||||||
|
const nsAString& aDescription,
|
||||||
|
const nsAString& aExtension)
|
||||||
: mWindow(aWindow),
|
: mWindow(aWindow),
|
||||||
mPluginElement(aPluginElement),
|
mPluginElement(aPluginElement),
|
||||||
mPluginTagMimeIndex(aPluginTagMimeIndex),
|
mType(aType),
|
||||||
mType(aType)
|
mDescription(aDescription),
|
||||||
|
mExtension(aExtension)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aType)
|
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aType)
|
||||||
: mWindow(aWindow),
|
: mWindow(aWindow),
|
||||||
mPluginElement(nullptr),
|
mPluginElement(nullptr),
|
||||||
mPluginTagMimeIndex(0),
|
|
||||||
mType(aType)
|
mType(aType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -251,14 +256,9 @@ nsMimeType::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsMimeType::GetDescription(nsString& retval) const
|
nsMimeType::GetDescription(nsString& aRetval) const
|
||||||
{
|
{
|
||||||
retval.Truncate();
|
aRetval = mDescription;
|
||||||
|
|
||||||
if (mPluginElement) {
|
|
||||||
CopyUTF8toUTF16(mPluginElement->PluginTag()->
|
|
||||||
mMimeDescriptions[mPluginTagMimeIndex], retval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsPluginElement*
|
nsPluginElement*
|
||||||
|
@ -269,14 +269,9 @@ nsMimeType::GetEnabledPlugin() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsMimeType::GetSuffixes(nsString& retval) const
|
nsMimeType::GetSuffixes(nsString& aRetval) const
|
||||||
{
|
{
|
||||||
retval.Truncate();
|
aRetval = mExtension;
|
||||||
|
|
||||||
if (mPluginElement) {
|
|
||||||
CopyUTF8toUTF16(mPluginElement->PluginTag()->
|
|
||||||
mExtensions[mPluginTagMimeIndex], retval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -58,8 +58,11 @@ public:
|
||||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsMimeType)
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsMimeType)
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsMimeType)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsMimeType)
|
||||||
|
|
||||||
nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
|
nsMimeType(nsPIDOMWindow* aWindow,
|
||||||
uint32_t aPluginTagMimeIndex, const nsAString& aMimeType);
|
nsPluginElement* aPluginElement,
|
||||||
|
const nsAString& aType,
|
||||||
|
const nsAString& aDescription,
|
||||||
|
const nsAString& aExtension);
|
||||||
nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aMimeType);
|
nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aMimeType);
|
||||||
nsPIDOMWindow* GetParentObject() const;
|
nsPIDOMWindow* GetParentObject() const;
|
||||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
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
|
// mimetype array. We rely on the cycle collector to break this
|
||||||
// cycle.
|
// cycle.
|
||||||
nsRefPtr<nsPluginElement> mPluginElement;
|
nsRefPtr<nsPluginElement> mPluginElement;
|
||||||
uint32_t mPluginTagMimeIndex;
|
|
||||||
nsString mType;
|
nsString mType;
|
||||||
|
nsString mDescription;
|
||||||
|
nsString mExtension;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* nsMimeTypeArray_h___ */
|
#endif /* nsMimeTypeArray_h___ */
|
||||||
|
|
|
@ -130,7 +130,7 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
||||||
// that plugins did not change and was not reloaded
|
// that plugins did not change and was not reloaded
|
||||||
if (pluginHost->ReloadPlugins() ==
|
if (pluginHost->ReloadPlugins() ==
|
||||||
NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
|
NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
|
||||||
nsTArray<nsRefPtr<nsPluginTag> > newPluginTags;
|
nsTArray<nsCOMPtr<nsIInternalPluginTag> > newPluginTags;
|
||||||
pluginHost->GetPlugins(newPluginTags);
|
pluginHost->GetPlugins(newPluginTags);
|
||||||
|
|
||||||
// Check if the number of plugins we know about are different from
|
// 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)
|
const nsRefPtr<nsPluginElement>& rhs)
|
||||||
{
|
{
|
||||||
// Sort plugins alphabetically by name.
|
// Sort plugins alphabetically by name.
|
||||||
return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
|
return lhs->PluginTag()->Name() < rhs->PluginTag()->Name();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -296,14 +296,13 @@ nsPluginArray::EnsurePlugins()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
|
nsTArray<nsCOMPtr<nsIInternalPluginTag> > pluginTags;
|
||||||
pluginHost->GetPlugins(pluginTags);
|
pluginHost->GetPlugins(pluginTags);
|
||||||
|
|
||||||
// need to wrap each of these with a nsPluginElement, which is
|
// need to wrap each of these with a nsPluginElement, which is
|
||||||
// scriptable.
|
// scriptable.
|
||||||
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
||||||
nsPluginTag* pluginTag = pluginTags[i];
|
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTag));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alphabetize the enumeration order of non-hidden plugins to reduce
|
// 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)
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
|
||||||
|
|
||||||
nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
|
nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
|
||||||
nsPluginTag* aPluginTag)
|
nsIInternalPluginTag* aPluginTag)
|
||||||
: mWindow(aWindow),
|
: mWindow(aWindow),
|
||||||
mPluginTag(aPluginTag)
|
mPluginTag(aPluginTag)
|
||||||
{
|
{
|
||||||
|
@ -349,25 +348,25 @@ nsPluginElement::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
void
|
void
|
||||||
nsPluginElement::GetDescription(nsString& retval) const
|
nsPluginElement::GetDescription(nsString& retval) const
|
||||||
{
|
{
|
||||||
CopyUTF8toUTF16(mPluginTag->mDescription, retval);
|
CopyUTF8toUTF16(mPluginTag->Description(), retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsPluginElement::GetFilename(nsString& retval) const
|
nsPluginElement::GetFilename(nsString& retval) const
|
||||||
{
|
{
|
||||||
CopyUTF8toUTF16(mPluginTag->mFileName, retval);
|
CopyUTF8toUTF16(mPluginTag->FileName(), retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsPluginElement::GetVersion(nsString& retval) const
|
nsPluginElement::GetVersion(nsString& retval) const
|
||||||
{
|
{
|
||||||
CopyUTF8toUTF16(mPluginTag->mVersion, retval);
|
CopyUTF8toUTF16(mPluginTag->Version(), retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsPluginElement::GetName(nsString& retval) const
|
nsPluginElement::GetName(nsString& retval) const
|
||||||
{
|
{
|
||||||
CopyUTF8toUTF16(mPluginTag->mName, retval);
|
CopyUTF8toUTF16(mPluginTag->Name(), retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsMimeType*
|
nsMimeType*
|
||||||
|
@ -452,8 +451,18 @@ nsPluginElement::EnsurePluginMimeTypes()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) {
|
if (mPluginTag->MimeTypes().Length() != mPluginTag->MimeDescriptions().Length() ||
|
||||||
NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]);
|
mPluginTag->MimeTypes().Length() != mPluginTag->Extensions().Length()) {
|
||||||
mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type));
|
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 "nsWeakReference.h"
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "nsPluginTags.h"
|
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
|
|
||||||
class nsPluginElement;
|
class nsPluginElement;
|
||||||
class nsMimeType;
|
class nsMimeType;
|
||||||
|
class nsIInternalPluginTag;
|
||||||
|
|
||||||
class nsPluginArray final : public nsIObserver,
|
class nsPluginArray final : public nsIObserver,
|
||||||
public nsSupportsWeakReference,
|
public nsSupportsWeakReference,
|
||||||
|
@ -70,12 +70,12 @@ public:
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPluginElement)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPluginElement)
|
||||||
|
|
||||||
nsPluginElement(nsPIDOMWindow* aWindow, nsPluginTag* aPluginTag);
|
nsPluginElement(nsPIDOMWindow* aWindow, nsIInternalPluginTag* aPluginTag);
|
||||||
|
|
||||||
nsPIDOMWindow* GetParentObject() const;
|
nsPIDOMWindow* GetParentObject() const;
|
||||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
nsPluginTag* PluginTag() const
|
nsIInternalPluginTag* PluginTag() const
|
||||||
{
|
{
|
||||||
return mPluginTag;
|
return mPluginTag;
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ protected:
|
||||||
void EnsurePluginMimeTypes();
|
void EnsurePluginMimeTypes();
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||||
nsRefPtr<nsPluginTag> mPluginTag;
|
nsCOMPtr<nsIInternalPluginTag> mPluginTag;
|
||||||
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
|
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -960,6 +960,25 @@ DOMInterfaces = {
|
||||||
'workers': True
|
'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': {
|
'Range': {
|
||||||
'nativeType': 'nsRange',
|
'nativeType': 'nsRange',
|
||||||
'binaryNames': {
|
'binaryNames': {
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "mozilla/ipc/BackgroundChild.h"
|
#include "mozilla/ipc/BackgroundChild.h"
|
||||||
#include "mozilla/ipc/BackgroundUtils.h"
|
#include "mozilla/ipc/BackgroundUtils.h"
|
||||||
#include "mozilla/ipc/PBackgroundChild.h"
|
#include "mozilla/ipc/PBackgroundChild.h"
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "WorkerPrivate.h"
|
#include "WorkerPrivate.h"
|
||||||
#include "WorkerRunnable.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
|
} // 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,
|
BroadcastChannel::BroadcastChannel(nsPIDOMWindow* aWindow,
|
||||||
const PrincipalInfo& aPrincipalInfo,
|
const PrincipalInfo& aPrincipalInfo,
|
||||||
const nsACString& aOrigin,
|
const nsACString& aOrigin,
|
||||||
|
|
|
@ -47,8 +47,6 @@ public:
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BroadcastChannel,
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BroadcastChannel,
|
||||||
DOMEventTargetHelper)
|
DOMEventTargetHelper)
|
||||||
|
|
||||||
static bool IsEnabled(JSContext* aCx, JSObject* aGlobal);
|
|
||||||
|
|
||||||
virtual JSObject*
|
virtual JSObject*
|
||||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
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]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
iframe_broadcastchannel.html
|
iframe_broadcastchannel.html
|
||||||
broadcastchannel_pref_worker.js
|
|
||||||
broadcastchannel_sharedWorker.js
|
broadcastchannel_sharedWorker.js
|
||||||
broadcastchannel_worker.js
|
broadcastchannel_worker.js
|
||||||
broadcastchannel_worker_alive.js
|
broadcastchannel_worker_alive.js
|
||||||
|
@ -17,7 +16,6 @@ support-files =
|
||||||
[test_broadcastchannel_basic.html]
|
[test_broadcastchannel_basic.html]
|
||||||
[test_broadcastchannel_close.html]
|
[test_broadcastchannel_close.html]
|
||||||
[test_broadcastchannel_self.html]
|
[test_broadcastchannel_self.html]
|
||||||
[test_broadcastchannel_pref.html]
|
|
||||||
[test_broadcastchannel_sharedWorker.html]
|
[test_broadcastchannel_sharedWorker.html]
|
||||||
[test_broadcastchannel_worker.html]
|
[test_broadcastchannel_worker.html]
|
||||||
[test_broadcastchannel_worker_alive.html]
|
[test_broadcastchannel_worker_alive.html]
|
||||||
|
|
|
@ -130,7 +130,7 @@ function runTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
runTest();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -55,7 +55,7 @@ function runTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
runTest();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -54,7 +54,7 @@ function runTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
runTest();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -84,8 +84,7 @@ var steps = [
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
|
SpecialPowers.pushPrefEnv({"set": [["network.disable.ipc.security", true],
|
||||||
["network.disable.ipc.security", true],
|
|
||||||
["browser.pagethumbnails.capturing_disabled", true],
|
["browser.pagethumbnails.capturing_disabled", true],
|
||||||
["dom.mozBrowserFramesEnabled", true],
|
["dom.mozBrowserFramesEnabled", true],
|
||||||
["dom.ipc.browser_frames.oop_by_default", false],
|
["dom.ipc.browser_frames.oop_by_default", false],
|
||||||
|
|
|
@ -84,8 +84,7 @@ var steps = [
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
|
SpecialPowers.pushPrefEnv({"set": [["network.disable.ipc.security", true],
|
||||||
["network.disable.ipc.security", true],
|
|
||||||
["browser.pagethumbnails.capturing_disabled", true],
|
["browser.pagethumbnails.capturing_disabled", true],
|
||||||
["dom.mozBrowserFramesEnabled", true],
|
["dom.mozBrowserFramesEnabled", true],
|
||||||
["dom.ipc.browser_frames.oop_by_default", false],
|
["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();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
runTest();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -30,7 +30,7 @@ function runTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTest);
|
runTest();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -44,8 +44,7 @@ function runTests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true],
|
SpecialPowers.pushPrefEnv({"set": [["dom.workers.sharedWorkers.enabled", true]]}, runTests);
|
||||||
["dom.workers.sharedWorkers.enabled", true]]}, runTests);
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
@ -54,7 +54,7 @@ function runTests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
SpecialPowers.pushPrefEnv({"set": [["dom.broadcastChannel.enabled", true]]}, runTests);
|
runTests();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче