зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
ad1f0f26c7
|
@ -7139,22 +7139,27 @@ nsContentUtils::GetInnerWindowID(nsIRequest* aRequest)
|
|||
}
|
||||
|
||||
void
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost)
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost)
|
||||
{
|
||||
aHost.Truncate();
|
||||
nsAutoCString hostname;
|
||||
nsresult rv = aURI->GetHost(hostname);
|
||||
nsresult rv = aURI->GetHost(aHost);
|
||||
if (NS_FAILED(rv)) { // Some URIs do not have a host
|
||||
return;
|
||||
}
|
||||
|
||||
if (hostname.FindChar(':') != -1) { // Escape IPv6 address
|
||||
MOZ_ASSERT(!hostname.Length() ||
|
||||
(hostname[0] !='[' && hostname[hostname.Length() - 1] != ']'));
|
||||
hostname.Insert('[', 0);
|
||||
hostname.Append(']');
|
||||
if (aHost.FindChar(':') != -1) { // Escape IPv6 address
|
||||
MOZ_ASSERT(!aHost.Length() ||
|
||||
(aHost[0] !='[' && aHost[aHost.Length() - 1] != ']'));
|
||||
aHost.Insert('[', 0);
|
||||
aHost.Append(']');
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost)
|
||||
{
|
||||
nsAutoCString hostname;
|
||||
GetHostOrIPv6WithBrackets(aURI, hostname);
|
||||
CopyUTF8toUTF16(hostname, aHost);
|
||||
}
|
||||
|
||||
|
|
|
@ -2282,6 +2282,7 @@ public:
|
|||
* otherwise it just outputs the hostname in aHost.
|
||||
*/
|
||||
static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
|
||||
static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
|
||||
|
||||
/*
|
||||
* Call the given callback on all remote children of the given top-level
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
|
@ -117,7 +116,7 @@
|
|||
{ url: 'http://example.com/carrot#question%3f',
|
||||
base: undefined,
|
||||
error: false,
|
||||
hash: '#question%3f'
|
||||
hash: '#question?'
|
||||
},
|
||||
{ url: 'https://example.com:4443?',
|
||||
base: undefined,
|
||||
|
|
|
@ -1897,6 +1897,8 @@ addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
|
|||
addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
|
||||
headerFile='nsIAsyncInputStream.h')
|
||||
addExternalIface('nsIFile', nativeType='nsIFile', notflattened=True)
|
||||
addExternalIface('nsILoadGroup', nativeType='nsILoadGroup',
|
||||
headerFile='nsILoadGroup.h', notflattened=True)
|
||||
addExternalIface('nsIMessageBroadcaster', nativeType='nsIMessageBroadcaster',
|
||||
headerFile='nsIMessageManager.h', notflattened=True)
|
||||
addExternalIface('nsISelectionListener', nativeType='nsISelectionListener')
|
||||
|
|
|
@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=422132
|
|||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -25,67 +26,96 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=422132
|
|||
/** Test for Bug 422132 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("untriaged");
|
||||
SimpleTest.waitForFocus(function() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set":[["general.smoothScroll", false],
|
||||
["mousewheel.min_line_scroll_amount", 1],
|
||||
["mousewheel.system_scroll_override_on_root_content.enabled", false],
|
||||
["mousewheel.transaction.timeout", 100000]]}, runTests)}, window);
|
||||
|
||||
function hitEventLoop(aFunc, aTimes)
|
||||
{
|
||||
if (--aTimes) {
|
||||
setTimeout(hitEventLoop, 0, aFunc, aTimes);
|
||||
} else {
|
||||
setTimeout(aFunc, 20);
|
||||
}
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
var target = document.getElementById("target");
|
||||
|
||||
var scrollLeft = target.scrollLeft;
|
||||
var scrollTop = target.scrollTop;
|
||||
synthesizeWheel(target, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
|
||||
deltaX: 0.5, deltaY: 0.5, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 });
|
||||
hitEventLoop(function () {
|
||||
is(target.scrollLeft, scrollLeft, "scrolled to right by 0.5px delta value");
|
||||
is(target.scrollTop, scrollTop, "scrolled to bottom by 0.5px delta value");
|
||||
|
||||
var tests = [
|
||||
{
|
||||
prepare: function() {
|
||||
scrollLeft = target.scrollLeft;
|
||||
scrollTop = target.scrollTop;
|
||||
synthesizeWheel(target, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
|
||||
deltaX: 0.5, deltaY: 0.5, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 });
|
||||
hitEventLoop(function () {
|
||||
ok(target.scrollLeft > scrollLeft,
|
||||
},
|
||||
event: {
|
||||
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
|
||||
deltaX: 0.5,
|
||||
deltaY: 0.5,
|
||||
lineOrPageDeltaX: 0,
|
||||
lineOrPageDeltaY: 0
|
||||
},
|
||||
}, {
|
||||
event: {
|
||||
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
|
||||
deltaX: 0.5,
|
||||
deltaY: 0.5,
|
||||
lineOrPageDeltaX: 0,
|
||||
lineOrPageDeltaY: 0
|
||||
},
|
||||
check: function() {
|
||||
is(target.scrollLeft - scrollLeft, 1,
|
||||
"not scrolled to right by 0.5px delta value with pending 0.5px delta");
|
||||
ok(target.scrollTop > scrollTop,
|
||||
is(target.scrollTop - scrollTop, 1,
|
||||
"not scrolled to bottom by 0.5px delta value with pending 0.5px delta");
|
||||
},
|
||||
}, {
|
||||
prepare: function() {
|
||||
scrollLeft = target.scrollLeft;
|
||||
scrollTop = target.scrollTop;
|
||||
synthesizeWheel(target, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 0.5, deltaY: 0.5, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 });
|
||||
hitEventLoop(function () {
|
||||
is(target.scrollLeft, scrollLeft, "scrolled to right by 0.5 line delta value");
|
||||
is(target.scrollTop, scrollTop, "scrolled to bottom by 0.5 line delta value");
|
||||
scrollLeft = target.scrollLeft;
|
||||
scrollTop = target.scrollTop;
|
||||
synthesizeWheel(target, 10, 10,
|
||||
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 0.5, deltaY: 0.5, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 });
|
||||
hitEventLoop(function () {
|
||||
ok(target.scrollLeft > scrollLeft,
|
||||
},
|
||||
event: {
|
||||
deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 0.5,
|
||||
deltaY: 0.5,
|
||||
lineOrPageDeltaX: 0,
|
||||
lineOrPageDeltaY: 0
|
||||
},
|
||||
}, {
|
||||
event: {
|
||||
deltaMode: WheelEvent.DOM_DELTA_LINE,
|
||||
deltaX: 0.5,
|
||||
deltaY: 0.5,
|
||||
lineOrPageDeltaX: 1,
|
||||
lineOrPageDeltaY: 1
|
||||
},
|
||||
check: function() {
|
||||
is(target.scrollLeft - scrollLeft, 1,
|
||||
"not scrolled to right by 0.5 line delta value with pending 0.5 line delta");
|
||||
ok(target.scrollTop > scrollTop,
|
||||
is(target.scrollTop - scrollTop, 1,
|
||||
"not scrolled to bottom by 0.5 line delta value with pending 0.5 line delta");
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
var nextTest = function() {
|
||||
var test = tests.shift();
|
||||
if (test.prepare) {
|
||||
test.prepare();
|
||||
}
|
||||
|
||||
sendWheelAndPaint(target, 10, 10, test.event, function() {
|
||||
if (test.check) {
|
||||
test.check();
|
||||
}
|
||||
if (tests.length == 0) {
|
||||
SimpleTest.finish();
|
||||
}, 20);
|
||||
}, 20);
|
||||
}, 20);
|
||||
}, 20);
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(nextTest, 0);
|
||||
});
|
||||
}
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -7,14 +7,42 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<a id="target1" href="http://www.example.com/#q=♥â¥#hello"></a>
|
||||
<a id="target2" href="http://www.example.com/#q=%E2%99%A5%C3%A2%C2%A5"></a>
|
||||
<a id="target3" href="http://www.example.com/#/search/%23important"></a>
|
||||
<a id="target4" href='http://www.example.com/#{"a":[13, 42], "b":{"key":"value"}}'></a>
|
||||
|
||||
<pre id="test">
|
||||
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [['dom.url.encode_decode_hash', false]]}, runTest);
|
||||
|
||||
function runTest() {
|
||||
setupTest();
|
||||
doTestEncoded();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function setupTest() {
|
||||
var target1 = document.createElement("a");
|
||||
target1.id = "target1";
|
||||
target1.href = "http://www.example.com/#q=♥â¥#hello";
|
||||
document.body.appendChild(target1);
|
||||
|
||||
var target2 = document.createElement("a");
|
||||
target2.id = "target2";
|
||||
target2.href = "http://www.example.com/#q=%E2%99%A5%C3%A2%C2%A5";
|
||||
document.body.appendChild(target2);
|
||||
|
||||
var target3 = document.createElement("a");
|
||||
target3.id = "target3";
|
||||
target3.href = "http://www.example.com/#/search/%23important";
|
||||
document.body.appendChild(target3);
|
||||
|
||||
var target4 = document.createElement("a");
|
||||
target4.id = "target4";
|
||||
target4.href = 'http://www.example.com/#{"a":[13, 42], "b":{"key":"value"}}';
|
||||
document.body.appendChild(target4);
|
||||
}
|
||||
|
||||
function doTestEncoded() {
|
||||
// Tests Link::GetHash
|
||||
|
||||
// Check that characters aren't being encoded
|
||||
|
@ -32,9 +60,7 @@
|
|||
// Some JSON
|
||||
target = document.getElementById("target4");
|
||||
is(target.hash, '#{"a":[13, 42], "b":{"key":"value"}}', 'Unexpected link hash');
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Tests URL::GetHash
|
||||
|
||||
var url = new URL("http://www.example.com/#q=♥â¥#hello")
|
||||
|
@ -68,9 +94,7 @@
|
|||
is(target.hash, '#{"a":[13, 42], "b":{"key":"value"}}', 'Unexpected url hash');
|
||||
parsed = JSON.parse(target.hash.substring(1));
|
||||
is(parsed.b.key, 'value', 'JSON not parsed correctly');
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Tests nsLocation::GetHash
|
||||
|
||||
window.history.pushState(1, document.title, '#q=♥â¥#hello');
|
||||
|
@ -84,6 +108,9 @@
|
|||
|
||||
window.history.pushState(1, document.title, '#{"a":[13, 42], "b":{"key":"value"}}');
|
||||
is(location.hash,'#{"a":[13, 42], "b":{"key":"value"}}', 'Unexpected location hash');
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</pre>
|
||||
|
|
|
@ -41,15 +41,18 @@ function ResourceLoader(res, rej) {
|
|||
}
|
||||
|
||||
/** Loads the identified https:// URL. */
|
||||
ResourceLoader.load = function(uri) {
|
||||
ResourceLoader.load = function(uri, doc) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let listener = new ResourceLoader(resolve, reject);
|
||||
let ioService = Cc['@mozilla.org/network/io-service;1']
|
||||
.getService(Ci.nsIIOService);
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
// the '2' identifies this as a script load
|
||||
let ioChannel = ioService.newChannelFromURI2(uri, null, systemPrincipal,
|
||||
systemPrincipal, 0, 2);
|
||||
let ioChannel = ioService.newChannelFromURI2(uri, doc, doc.nodePrincipal,
|
||||
systemPrincipal, 0,
|
||||
Ci.nsIContentPolicy.TYPE_SCRIPT);
|
||||
|
||||
ioChannel.loadGroup = doc.documentLoadGroup.QueryInterface(Ci.nsILoadGroup);
|
||||
ioChannel.notificationCallbacks = new RedirectHttpsOnly();
|
||||
ioChannel.asyncOpen(listener, null);
|
||||
});
|
||||
|
@ -110,12 +113,14 @@ function createLocationFromURI(uri) {
|
|||
*
|
||||
* @param domain (string) the domain of the IdP
|
||||
* @param protocol (string?) the protocol of the IdP [default: 'default']
|
||||
* @param doc (obj) the current document
|
||||
* @throws if the domain or protocol aren't valid
|
||||
*/
|
||||
function IdpSandbox(domain, protocol) {
|
||||
function IdpSandbox(domain, protocol, doc) {
|
||||
this.source = IdpSandbox.createIdpUri(domain, protocol || "default");
|
||||
this.active = null;
|
||||
this.sandbox = null;
|
||||
this.document = doc;
|
||||
}
|
||||
|
||||
IdpSandbox.checkDomain = function(domain) {
|
||||
|
@ -176,7 +181,7 @@ IdpSandbox.prototype = {
|
|||
|
||||
start: function() {
|
||||
if (!this.active) {
|
||||
this.active = ResourceLoader.load(this.source)
|
||||
this.active = ResourceLoader.load(this.source, this.document)
|
||||
.then(result => this._createSandbox(result));
|
||||
}
|
||||
return this.active;
|
||||
|
|
|
@ -1223,9 +1223,10 @@ void MediaDecoder::UpdateReadyStateForData()
|
|||
mOwner->UpdateReadyStateForData(frameStatus);
|
||||
}
|
||||
|
||||
void MediaDecoder::OnSeekResolvedInternal(bool aAtEnd, MediaDecoderEventVisibility aEventVisibility)
|
||||
void MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mSeekRequest.Complete();
|
||||
|
||||
if (mShuttingDown)
|
||||
return;
|
||||
|
@ -1242,20 +1243,20 @@ void MediaDecoder::OnSeekResolvedInternal(bool aAtEnd, MediaDecoderEventVisibili
|
|||
seekWasAborted = true;
|
||||
} else {
|
||||
UnpinForSeek();
|
||||
fireEnded = aAtEnd;
|
||||
if (aAtEnd) {
|
||||
fireEnded = aVal.mAtEnd;
|
||||
if (aVal.mAtEnd) {
|
||||
ChangeState(PLAY_STATE_ENDED);
|
||||
} else if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
|
||||
ChangeState(aAtEnd ? PLAY_STATE_ENDED : mNextState);
|
||||
} else if (aVal.mEventVisibility != MediaDecoderEventVisibility::Suppressed) {
|
||||
ChangeState(aVal.mAtEnd ? PLAY_STATE_ENDED : mNextState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackPositionChanged(aEventVisibility);
|
||||
PlaybackPositionChanged(aVal.mEventVisibility);
|
||||
|
||||
if (mOwner) {
|
||||
UpdateReadyStateForData();
|
||||
if (!seekWasAborted && (aEventVisibility != MediaDecoderEventVisibility::Suppressed)) {
|
||||
if (!seekWasAborted && (aVal.mEventVisibility != MediaDecoderEventVisibility::Suppressed)) {
|
||||
mOwner->SeekCompleted();
|
||||
if (fireEnded) {
|
||||
mOwner->PlaybackEnded();
|
||||
|
|
|
@ -809,21 +809,7 @@ public:
|
|||
void PlaybackEnded();
|
||||
|
||||
void OnSeekRejected() { mSeekRequest.Complete(); }
|
||||
void OnSeekResolvedInternal(bool aAtEnd, MediaDecoderEventVisibility aEventVisibility);
|
||||
|
||||
void OnSeekResolved(SeekResolveValue aVal)
|
||||
{
|
||||
mSeekRequest.Complete();
|
||||
OnSeekResolvedInternal(aVal.mAtEnd, aVal.mEventVisibility);
|
||||
}
|
||||
|
||||
#ifdef MOZ_AUDIO_OFFLOAD
|
||||
// Temporary hack - see bug 1139206.
|
||||
void SimulateSeekResolvedForAudioOffload(MediaDecoderEventVisibility aEventVisibility)
|
||||
{
|
||||
OnSeekResolvedInternal(false, aEventVisibility);
|
||||
}
|
||||
#endif
|
||||
void OnSeekResolved(SeekResolveValue aVal);
|
||||
|
||||
// Seeking has started. Inform the element on the main
|
||||
// thread.
|
||||
|
|
|
@ -56,7 +56,7 @@ PeerConnectionIdp.prototype = {
|
|||
}
|
||||
this._idp.stop();
|
||||
}
|
||||
this._idp = new IdpSandbox(provider, protocol);
|
||||
this._idp = new IdpSandbox(provider, protocol, this._win.document);
|
||||
},
|
||||
|
||||
// start the IdP and do some error fixup
|
||||
|
|
|
@ -57,13 +57,10 @@ static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
|
|||
AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
|
||||
mStarted(false),
|
||||
mPlaying(false),
|
||||
mSeeking(false),
|
||||
mReachedEOS(false),
|
||||
mSeekDuringPause(false),
|
||||
mIsElementVisible(true),
|
||||
mSampleRate(0),
|
||||
mStartPosUs(0),
|
||||
mSeekTimeUs(0),
|
||||
mPositionTimeMediaUs(-1),
|
||||
mInputBuffer(nullptr),
|
||||
mObserver(aObserver)
|
||||
|
@ -199,13 +196,6 @@ status_t AudioOffloadPlayer::ChangeState(MediaDecoder::PlayState aState)
|
|||
StartTimeUpdate();
|
||||
} break;
|
||||
|
||||
case MediaDecoder::PLAY_STATE_SEEKING: {
|
||||
int64_t seekTimeUs
|
||||
= mObserver->GetSeekTime();
|
||||
SeekTo(seekTimeUs, true);
|
||||
mObserver->ResetSeekTime();
|
||||
} break;
|
||||
|
||||
case MediaDecoder::PLAY_STATE_PAUSED:
|
||||
case MediaDecoder::PLAY_STATE_SHUTDOWN:
|
||||
// Just pause here during play state shutdown as well to stop playing
|
||||
|
@ -278,8 +268,12 @@ status_t AudioOffloadPlayer::Play()
|
|||
return err;
|
||||
}
|
||||
// Seek to last play position only when there was no seek during last pause
|
||||
if (!mSeeking) {
|
||||
SeekTo(mPositionTimeMediaUs);
|
||||
android::Mutex::Autolock autoLock(mLock);
|
||||
if (!mSeekTarget.IsValid()) {
|
||||
mSeekTarget = SeekTarget(mPositionTimeMediaUs,
|
||||
SeekTarget::Accurate,
|
||||
MediaDecoderEventVisibility::Suppressed);
|
||||
DoSeek();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,28 +337,36 @@ void AudioOffloadPlayer::Reset()
|
|||
WakeLockRelease();
|
||||
}
|
||||
|
||||
status_t AudioOffloadPlayer::SeekTo(int64_t aTimeUs, bool aDispatchSeekEvents)
|
||||
nsRefPtr<MediaDecoder::SeekPromise> AudioOffloadPlayer::Seek(SeekTarget aTarget)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
CHECK(mAudioSink.get());
|
||||
|
||||
android::Mutex::Autolock autoLock(mLock);
|
||||
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("SeekTo ( %lld )", aTimeUs));
|
||||
mSeekPromise.RejectIfExists(true, __func__);
|
||||
mSeekTarget = aTarget;
|
||||
nsRefPtr<MediaDecoder::SeekPromise> p = mSeekPromise.Ensure(__func__);
|
||||
DoSeek();
|
||||
return p;
|
||||
}
|
||||
|
||||
status_t AudioOffloadPlayer::DoSeek()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mSeekTarget.IsValid());
|
||||
CHECK(mAudioSink.get());
|
||||
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("DoSeek ( %lld )", mSeekTarget.mTime));
|
||||
|
||||
mSeeking = true;
|
||||
mReachedEOS = false;
|
||||
mPositionTimeMediaUs = -1;
|
||||
mSeekTimeUs = aTimeUs;
|
||||
mStartPosUs = aTimeUs;
|
||||
mDispatchSeekEvents = aDispatchSeekEvents;
|
||||
mStartPosUs = mSeekTarget.mTime;
|
||||
|
||||
if (mDispatchSeekEvents) {
|
||||
if (!mSeekPromise.IsEmpty()) {
|
||||
nsCOMPtr<nsIRunnable> nsEvent =
|
||||
NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>(
|
||||
mObserver,
|
||||
&MediaDecoder::SeekingStarted,
|
||||
MediaDecoderEventVisibility::Observable);
|
||||
mSeekTarget.mEventVisibility);
|
||||
NS_DispatchToCurrentThread(nsEvent);
|
||||
}
|
||||
|
||||
|
@ -374,21 +376,15 @@ status_t AudioOffloadPlayer::SeekTo(int64_t aTimeUs, bool aDispatchSeekEvents)
|
|||
mAudioSink->Start();
|
||||
|
||||
} else {
|
||||
mSeekDuringPause = true;
|
||||
|
||||
if (mStarted) {
|
||||
mAudioSink->Flush();
|
||||
}
|
||||
|
||||
if (mDispatchSeekEvents) {
|
||||
mDispatchSeekEvents = false;
|
||||
if (!mSeekPromise.IsEmpty()) {
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Fake seek complete during pause"));
|
||||
nsCOMPtr<nsIRunnable> nsEvent =
|
||||
NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>(
|
||||
mObserver,
|
||||
&MediaDecoder::SimulateSeekResolvedForAudioOffload,
|
||||
MediaDecoderEventVisibility::Observable);
|
||||
NS_DispatchToCurrentThread(nsEvent);
|
||||
// We do not reset mSeekTarget here.
|
||||
MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
|
||||
mSeekPromise.Resolve(val, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -407,8 +403,8 @@ int64_t AudioOffloadPlayer::GetMediaTimeUs()
|
|||
android::Mutex::Autolock autoLock(mLock);
|
||||
|
||||
int64_t playPosition = 0;
|
||||
if (mSeeking) {
|
||||
return mSeekTimeUs;
|
||||
if (mSeekTarget.IsValid()) {
|
||||
return mSeekTarget.mTime;
|
||||
}
|
||||
if (!mStarted) {
|
||||
return mPositionTimeMediaUs;
|
||||
|
@ -439,6 +435,12 @@ int64_t AudioOffloadPlayer::GetOutputPlayPositionUs_l() const
|
|||
|
||||
void AudioOffloadPlayer::NotifyAudioEOS()
|
||||
{
|
||||
android::Mutex::Autolock autoLock(mLock);
|
||||
// We do not reset mSeekTarget here.
|
||||
if (!mSeekPromise.IsEmpty()) {
|
||||
MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
|
||||
mSeekPromise.Resolve(val, __func__);
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
|
||||
&MediaDecoder::PlaybackEnded);
|
||||
NS_DispatchToMainThread(nsEvent);
|
||||
|
@ -456,6 +458,15 @@ void AudioOffloadPlayer::NotifyPositionChanged()
|
|||
|
||||
void AudioOffloadPlayer::NotifyAudioTearDown()
|
||||
{
|
||||
// Fallback to state machine.
|
||||
// state machine's seeks will be done with
|
||||
// MediaDecoderEventVisibility::Suppressed.
|
||||
android::Mutex::Autolock autoLock(mLock);
|
||||
// We do not reset mSeekTarget here.
|
||||
if (!mSeekPromise.IsEmpty()) {
|
||||
MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
|
||||
mSeekPromise.Resolve(val, __func__);
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
|
||||
&MediaOmxCommonDecoder::AudioOffloadTearDown);
|
||||
NS_DispatchToMainThread(nsEvent);
|
||||
|
@ -506,27 +517,26 @@ size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
|
|||
|
||||
size_t sizeDone = 0;
|
||||
size_t sizeRemaining = aSize;
|
||||
int64_t seekTimeUs = -1;
|
||||
while (sizeRemaining > 0) {
|
||||
MediaSource::ReadOptions options;
|
||||
bool refreshSeekTime = false;
|
||||
|
||||
{
|
||||
android::Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mSeeking) {
|
||||
options.setSeekTo(mSeekTimeUs);
|
||||
if (mSeekTarget.IsValid()) {
|
||||
seekTimeUs = mSeekTarget.mTime;
|
||||
options.setSeekTo(seekTimeUs);
|
||||
refreshSeekTime = true;
|
||||
|
||||
if (mInputBuffer) {
|
||||
mInputBuffer->release();
|
||||
mInputBuffer = nullptr;
|
||||
}
|
||||
mSeeking = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mInputBuffer) {
|
||||
|
||||
status_t err;
|
||||
err = mSource->read(&mInputBuffer, &options);
|
||||
|
||||
|
@ -535,6 +545,9 @@ size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
|
|||
android::Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (err != OK) {
|
||||
if (mSeekTarget.IsValid()) {
|
||||
mSeekTarget.Reset();
|
||||
}
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Error while reading media source %d "
|
||||
"Ok to receive EOS error at end", err));
|
||||
if (!mReachedEOS) {
|
||||
|
@ -564,25 +577,19 @@ size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
|
|||
kKeyTime, &mPositionTimeMediaUs));
|
||||
}
|
||||
|
||||
if (refreshSeekTime) {
|
||||
if (mDispatchSeekEvents && !mSeekDuringPause) {
|
||||
mDispatchSeekEvents = false;
|
||||
if (mSeekTarget.IsValid() && seekTimeUs == mSeekTarget.mTime) {
|
||||
MOZ_ASSERT(mSeekTarget.IsValid());
|
||||
mSeekTarget.Reset();
|
||||
if (!mSeekPromise.IsEmpty()) {
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("FillBuffer posting SEEK_COMPLETE"));
|
||||
nsCOMPtr<nsIRunnable> nsEvent =
|
||||
NS_NewRunnableMethodWithArg<MediaDecoderEventVisibility>(
|
||||
mObserver,
|
||||
&MediaDecoder::SimulateSeekResolvedForAudioOffload,
|
||||
MediaDecoderEventVisibility::Observable);
|
||||
NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);
|
||||
|
||||
} else if (mSeekDuringPause) {
|
||||
// Callback is already called for seek during pause. Just reset the
|
||||
// flag
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Not posting seek complete as its"
|
||||
" already faked"));
|
||||
mSeekDuringPause = false;
|
||||
MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility);
|
||||
mSeekPromise.Resolve(val, __func__);
|
||||
}
|
||||
} else if (mSeekTarget.IsValid()) {
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("seek is updated during unlocking mLock"));
|
||||
}
|
||||
|
||||
if (refreshSeekTime) {
|
||||
NotifyPositionChanged();
|
||||
|
||||
// need to adjust the mStartPosUs for offload decoding since parser
|
||||
|
@ -590,14 +597,6 @@ size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
|
|||
mStartPosUs = mPositionTimeMediaUs;
|
||||
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Adjust seek time to: %.2f",
|
||||
mStartPosUs / 1E6));
|
||||
|
||||
// clear seek time with mLock locked and once we have valid
|
||||
// mPositionTimeMediaUs
|
||||
// before clearing mSeekTimeUs check if a new seek request has been
|
||||
// received while we were reading from the source with mLock released.
|
||||
if (!mSeeking) {
|
||||
mSeekTimeUs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,25 +78,27 @@ public:
|
|||
~AudioOffloadPlayer();
|
||||
|
||||
// Caller retains ownership of "aSource".
|
||||
void SetSource(const android::sp<MediaSource> &aSource);
|
||||
virtual void SetSource(const android::sp<MediaSource> &aSource) override;
|
||||
|
||||
// Start the source if it's not already started and open the AudioSink to
|
||||
// create an offloaded audio track
|
||||
status_t Start(bool aSourceAlreadyStarted = false);
|
||||
virtual status_t Start(bool aSourceAlreadyStarted = false) override;
|
||||
|
||||
double GetMediaTimeSecs();
|
||||
virtual status_t ChangeState(MediaDecoder::PlayState aState) override;
|
||||
|
||||
virtual void SetVolume(double aVolume) override;
|
||||
|
||||
virtual double GetMediaTimeSecs() override;
|
||||
|
||||
// To update progress bar when the element is visible
|
||||
void SetElementVisibility(bool aIsVisible);
|
||||
|
||||
status_t ChangeState(MediaDecoder::PlayState aState);
|
||||
|
||||
void SetVolume(double aVolume);
|
||||
virtual void SetElementVisibility(bool aIsVisible) override;;
|
||||
|
||||
// Update ready state based on current play state. Not checking data
|
||||
// availability since offloading is currently done only when whole compressed
|
||||
// data is available
|
||||
MediaDecoderOwner::NextFrameStatus GetNextFrameStatus();
|
||||
virtual MediaDecoderOwner::NextFrameStatus GetNextFrameStatus() override;
|
||||
|
||||
virtual nsRefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget) override;
|
||||
|
||||
void TimeUpdate();
|
||||
|
||||
|
@ -112,28 +114,12 @@ private:
|
|||
// Used only in main thread
|
||||
bool mPlaying;
|
||||
|
||||
// Set when playstate is seeking and reset when FillBUffer() acknowledged
|
||||
// seeking by seeking audio source. Used in main thread and offload
|
||||
// callback thread, protected by Mutex mLock
|
||||
bool mSeeking;
|
||||
|
||||
// Once playback reached end of stream (last ~100ms), position provided by DSP
|
||||
// may be reset/corrupted. This bool is used to avoid that.
|
||||
// Used in main thread and offload callback thread, protected by Mutex
|
||||
// mLock
|
||||
bool mReachedEOS;
|
||||
|
||||
// Set when there is a seek request during pause.
|
||||
// Used in main thread and offload callback thread, protected by Mutex
|
||||
// mLock
|
||||
bool mSeekDuringPause;
|
||||
|
||||
// Seek can be triggered internally or by MediaDecoder. This bool is to
|
||||
// to track seek triggered by MediaDecoder so that we can send back
|
||||
// SeekingStarted and SeekingStopped events.
|
||||
// Used in main thread and offload callback thread, protected by Mutex mLock
|
||||
bool mDispatchSeekEvents;
|
||||
|
||||
// Set when the HTML Audio Element is visible to the user.
|
||||
// Used only in main thread
|
||||
bool mIsElementVisible;
|
||||
|
@ -155,10 +141,15 @@ private:
|
|||
// mLock
|
||||
int64_t mStartPosUs;
|
||||
|
||||
// Given seek time when there is a request to seek
|
||||
// The target of current seek when there is a request to seek
|
||||
// Used in main thread and offload callback thread, protected by Mutex
|
||||
// mLock
|
||||
int64_t mSeekTimeUs;
|
||||
SeekTarget mSeekTarget;
|
||||
|
||||
// MediaPromise of current seek.
|
||||
// Used in main thread and offload callback thread, protected by Mutex
|
||||
// mLock
|
||||
MediaPromiseHolder<MediaDecoder::SeekPromise> mSeekPromise;
|
||||
|
||||
// Positions obtained from offlaoded tracks (DSP)
|
||||
// Used in main thread and offload callback thread, protected by Mutex
|
||||
|
@ -221,15 +212,15 @@ private:
|
|||
|
||||
bool IsSeeking();
|
||||
|
||||
// Set mSeekTime to the given position and restart the sink. Actual seek
|
||||
// happens in FillBuffer(). If aDispatchSeekEvents is true, send
|
||||
// Set mSeekTarget to the given position and restart the sink. Actual seek
|
||||
// happens in FillBuffer(). If mSeekPromise is not empty, send
|
||||
// SeekingStarted event always and SeekingStopped event when the play state is
|
||||
// paused to MediaDecoder.
|
||||
// When decoding and playing happens separately, if there is a seek during
|
||||
// pause, we can decode and keep data ready.
|
||||
// In case of offload player, no way to seek during pause. So just fake that
|
||||
// seek is done.
|
||||
status_t SeekTo(int64_t aTimeUs, bool aDispatchSeekEvents = false);
|
||||
status_t DoSeek();
|
||||
|
||||
// Start/Resume the audio sink so that callback will start being called to get
|
||||
// compressed data
|
||||
|
|
|
@ -66,6 +66,8 @@ public:
|
|||
{
|
||||
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
virtual nsRefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget) = 0;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -126,8 +126,9 @@ MediaOmxCommonDecoder::ResumeStateMachine()
|
|||
mAudioOffloadPlayer = nullptr;
|
||||
int64_t timeUsecs = 0;
|
||||
SecondsToUsecs(mCurrentTime, timeUsecs);
|
||||
mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
|
||||
|
||||
mRequestedSeekTarget = SeekTarget(timeUsecs,
|
||||
SeekTarget::Accurate,
|
||||
MediaDecoderEventVisibility::Suppressed);
|
||||
mNextState = mPlayState;
|
||||
ChangeState(PLAY_STATE_LOADING);
|
||||
// exit dormant state
|
||||
|
@ -193,10 +194,25 @@ MediaOmxCommonDecoder::ChangeState(PlayState aState)
|
|||
// in between
|
||||
MediaDecoder::ChangeState(aState);
|
||||
|
||||
if (mAudioOffloadPlayer) {
|
||||
if (!mAudioOffloadPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
status_t err = mAudioOffloadPlayer->ChangeState(aState);
|
||||
if (err != OK) {
|
||||
ResumeStateMachine();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mPlayState) {
|
||||
case PLAY_STATE_SEEKING:
|
||||
mSeekRequest.Begin(mAudioOffloadPlayer->Seek(mRequestedSeekTarget)
|
||||
->RefableThen(AbstractThread::MainThread(), __func__, static_cast<MediaDecoder*>(this),
|
||||
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
|
||||
mRequestedSeekTarget.Reset();
|
||||
break;
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
(function(global) {
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
// rather than create a million different IdP configurations and litter the
|
||||
// world with files all containing near-identical code, let's use the hash/URL
|
||||
// fragment as a way of generating instructions for the IdP
|
||||
var instructions = global.location.hash.replace("#", "").split(":");
|
||||
var instructions = global.location.hash.replace('#', '').split(':');
|
||||
function is(target) {
|
||||
return function(instruction) {
|
||||
return instruction === target;
|
||||
|
@ -16,35 +16,55 @@
|
|||
var path = global.location.pathname;
|
||||
this.protocol =
|
||||
path.substring(path.lastIndexOf('/') + 1) + global.location.hash;
|
||||
this.id = crypto.getRandomValues(new Uint8Array(10)).join('.');
|
||||
}
|
||||
|
||||
function borkResult(result) {
|
||||
if (instructions.some(is("throw"))) {
|
||||
throw new Error('Throwing!');
|
||||
IDPJS.prototype = {
|
||||
getLogin: function() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'https://example.com/.well-known/idp-proxy/idp.sjs?' + this.id);
|
||||
return new Promise(resolve => {
|
||||
xhr.onload = e => resolve(xhr.status === 200);
|
||||
xhr.send();
|
||||
});
|
||||
},
|
||||
checkLogin: function(result) {
|
||||
return this.getLogin()
|
||||
.then(loggedIn => {
|
||||
if (loggedIn) {
|
||||
return result;
|
||||
}
|
||||
if (instructions.some(is("fail"))) {
|
||||
return Promise.reject(new Error('Failing!'));
|
||||
}
|
||||
if (instructions.some(is("loginerror"))) {
|
||||
return Promise.reject({
|
||||
name: 'IdpLoginError',
|
||||
loginUrl: 'https://example.com/log/in/here'
|
||||
loginUrl: 'https://example.com/.well-known/idp-proxy/login.html#' +
|
||||
this.id
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
borkResult: function(result) {
|
||||
if (instructions.some(is('throw'))) {
|
||||
throw new Error('Throwing!');
|
||||
}
|
||||
if (instructions.some(is("hang"))) {
|
||||
if (instructions.some(is('fail'))) {
|
||||
return Promise.reject(new Error('Failing!'));
|
||||
}
|
||||
if (instructions.some(is('login'))) {
|
||||
return this.checkLogin(result);
|
||||
}
|
||||
if (instructions.some(is('hang'))) {
|
||||
return new Promise(r => {});
|
||||
}
|
||||
dump('idp: result=' + JSON.stringify(result) + '\n');
|
||||
return Promise.resolve(result);
|
||||
};
|
||||
},
|
||||
|
||||
IDPJS.prototype = {
|
||||
_selectUsername: function(usernameHint) {
|
||||
var username = "someone@" + this.domain;
|
||||
var username = 'someone@' + this.domain;
|
||||
if (usernameHint) {
|
||||
var at = usernameHint.indexOf("@");
|
||||
var at = usernameHint.indexOf('@');
|
||||
if (at < 0) {
|
||||
username = usernameHint + "@" + this.domain;
|
||||
username = usernameHint + '@' + this.domain;
|
||||
} else if (usernameHint.substring(at + 1) === this.domain) {
|
||||
username = usernameHint;
|
||||
}
|
||||
|
@ -58,10 +78,10 @@
|
|||
domain: this.domain,
|
||||
protocol: this.protocol
|
||||
};
|
||||
if (instructions.some(is("bad-assert"))) {
|
||||
if (instructions.some(is('bad-assert'))) {
|
||||
idpDetails = {};
|
||||
}
|
||||
return borkResult({
|
||||
return this.borkResult({
|
||||
idp: idpDetails,
|
||||
assertion: JSON.stringify({
|
||||
username: this._selectUsername(usernameHint),
|
||||
|
@ -73,17 +93,17 @@
|
|||
validateAssertion: function(assertion, origin) {
|
||||
dump('idp: validateAssertion(' + assertion + ')\n');
|
||||
var assertion = JSON.parse(assertion);
|
||||
if (instructions.some(is("bad-validate"))) {
|
||||
if (instructions.some(is('bad-validate'))) {
|
||||
assertion.contents = {};
|
||||
}
|
||||
return borkResult({
|
||||
return this.borkResult({
|
||||
identity: assertion.username,
|
||||
contents: assertion.contents
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!instructions.some(is("not_ready"))) {
|
||||
if (!instructions.some(is('not_ready'))) {
|
||||
dump('registering idp.js' + global.location.hash + '\n');
|
||||
global.rtcIdentityProvider.register(new IDPJS());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
function handleRequest(request, response) {
|
||||
var key = '/.well-known/idp-proxy/' + request.queryString;
|
||||
dump(getState(key) + '\n');
|
||||
if (request.method === 'GET') {
|
||||
if (getState(key)) {
|
||||
response.setStatusLine(request.httpVersion, 200, 'OK');
|
||||
} else {
|
||||
response.setStatusLine(request.httpVersion, 404, 'Not Found');
|
||||
}
|
||||
} else if (request.method === 'PUT') {
|
||||
setState(key, 'OK');
|
||||
response.setStatusLine(request.httpVersion, 200, 'OK');
|
||||
} else {
|
||||
response.setStatusLine(request.httpVersion, 406, 'Method Not Allowed');
|
||||
}
|
||||
response.setHeader('Content-Type', 'text/plain;charset=UTF-8');
|
||||
response.write('OK');
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Identity Provider Login</title>
|
||||
<script type="application/javascript">
|
||||
window.onload = () => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", "https://example.com/.well-known/idp-proxy/idp.sjs?" +
|
||||
window.location.hash.replace('#', ''));
|
||||
xhr.onload = () => {
|
||||
var isFramed = (window !== window.top);
|
||||
var parent = isFramed ? window.parent : window.opener;
|
||||
// Using '*' is cheating, but that's OK.
|
||||
parent.postMessage('LOGINDONE', '*');
|
||||
var done = document.createElement('div');
|
||||
|
||||
done.textContent = 'Done';
|
||||
document.body.appendChild(done);
|
||||
|
||||
if (!isFramed) {
|
||||
window.close();
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div>Logging in...</div>
|
||||
</body>
|
||||
</html>
|
|
@ -27,6 +27,11 @@ support-files =
|
|||
[test_setIdentityProviderWithErrors.html]
|
||||
[test_peerConnection_peerIdentity.html]
|
||||
[test_peerConnection_asymmetricIsolation.html]
|
||||
[test_loginNeeded.html]
|
||||
support-files =
|
||||
/.well-known/idp-proxy/login.html
|
||||
/.well-known/idp-proxy/idp.sjs
|
||||
|
||||
|
||||
# Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
|
||||
[../test_zmedia_cleanup.html]
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
function getIdentityAssertion(fpArray) {
|
||||
var Cu = SpecialPowers.Cu;
|
||||
var rtcid = Cu.import('resource://gre/modules/media/IdpSandbox.jsm');
|
||||
var sandbox = new rtcid.IdpSandbox('example.com', 'idp.js');
|
||||
var sandbox = new rtcid.IdpSandbox('example.com', 'idp.js', window.document);
|
||||
return sandbox.start()
|
||||
.then(idp => SpecialPowers.wrap(idp)
|
||||
.generateAssertion(JSON.stringify({ fingerprint: fpArray }),
|
||||
|
|
|
@ -55,11 +55,12 @@ function theTest() {
|
|||
},
|
||||
|
||||
function PC_LOCAL_IDP_LOGIN_ERROR(t) {
|
||||
return getAssertion(t, '#loginerror')
|
||||
.then(a => ok(false, '#loginerror should not work'),
|
||||
return getAssertion(t, '#login')
|
||||
.then(a => ok(false, '#login should not work'),
|
||||
e => {
|
||||
is(e.name, 'IdpLoginError', 'name is IdpLoginError');
|
||||
is(t.pcLocal._pc.idpLoginUrl, 'https://example.com/log/in/here',
|
||||
is(t.pcLocal._pc.idpLoginUrl.split('#')[0],
|
||||
'https://example.com/.well-known/idp-proxy/login.html',
|
||||
'got the right login URL from the IdP');
|
||||
});
|
||||
},
|
||||
|
|
|
@ -26,7 +26,7 @@ function test_domain_sandbox() {
|
|||
'', 12, null, diabolical, true ];
|
||||
domains.forEach(function(domain) {
|
||||
try {
|
||||
var idp = new IdpSandbox(domain);
|
||||
var idp = new IdpSandbox(domain, undefined, window.document);
|
||||
ok(false, 'IdpSandbox allowed a bad domain: ' + domain);
|
||||
} catch (e) {
|
||||
var str = (typeof domain === 'string') ? domain : typeof domain;
|
||||
|
@ -40,7 +40,7 @@ function test_protocol_sandbox() {
|
|||
'\\evil', '%5cevil', 12, true, {} ];
|
||||
protos.forEach(function(proto) {
|
||||
try {
|
||||
var idp = new IdpSandbox('example.com', proto);
|
||||
var idp = new IdpSandbox('example.com', proto, window.document);
|
||||
ok(false, 'IdpSandbox allowed a bad protocol: ' + proto);
|
||||
} catch (e) {
|
||||
var str = (typeof proto === 'string') ? proto : typeof proto;
|
||||
|
@ -56,7 +56,7 @@ function idpName(hash) {
|
|||
function makeSandbox(js) {
|
||||
var name = js || idpName();
|
||||
info('Creating a sandbox for the protocol: ' + name);
|
||||
var sandbox = new IdpSandbox('example.com', name);
|
||||
var sandbox = new IdpSandbox('example.com', name, window.document);
|
||||
return sandbox.start().then(idp => SpecialPowers.wrap(idp));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript">var scriptRelativePath = "../";</script>
|
||||
<script type="application/javascript" src="../pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
title: 'RTCPeerConnection identity with login',
|
||||
bug: '1153314'
|
||||
});
|
||||
|
||||
function waitForLoginDone() {
|
||||
return new Promise(resolve => {
|
||||
window.addEventListener('message', function listener(e) {
|
||||
is(e.origin, 'https://example.com', 'got the right message origin');
|
||||
is(e.data, 'LOGINDONE', 'got the right message');
|
||||
window.removeEventListener('message', listener);
|
||||
resolve();
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
function checkLogin(t, name, onLoginNeeded) {
|
||||
t.pcLocal.setIdentityProvider('example.com', 'idp.js#login:' + name);
|
||||
return t.pcLocal._pc.getIdentityAssertion()
|
||||
.then(a => ok(false, 'should request login'),
|
||||
e => {
|
||||
is(e.name, 'IdpLoginError', 'name is IdpLoginError');
|
||||
is(t.pcLocal._pc.idpLoginUrl.split('#')[0],
|
||||
'https://example.com/.well-known/idp-proxy/login.html',
|
||||
'got the right login URL from the IdP');
|
||||
return t.pcLocal._pc.idpLoginUrl;
|
||||
})
|
||||
.then(onLoginNeeded)
|
||||
.then(waitForLoginDone)
|
||||
.then(() => t.pcLocal._pc.getIdentityAssertion())
|
||||
.then(a => ok(a, 'got assertion'));
|
||||
}
|
||||
|
||||
function theTest() {
|
||||
var test = new PeerConnectionTest();
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.chain.removeAfter('PC_REMOTE_CHECK_INITIAL_SIGNALINGSTATE');
|
||||
test.chain.append([
|
||||
function PC_LOCAL_IDENTITY_ASSERTION_WITH_IFRAME_LOGIN(t) {
|
||||
return checkLogin(t, 'iframe', loginUrl => {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('src', loginUrl);
|
||||
iframe.frameBorder = 0;
|
||||
iframe.width = 400;
|
||||
iframe.height = 60;
|
||||
document.getElementById('display').appendChild(iframe);
|
||||
});
|
||||
},
|
||||
function PC_LOCAL_IDENTITY_ASSERTION_WITH_WINDOW_LOGIN(t) {
|
||||
return checkLogin(t, 'openwin', loginUrl => {
|
||||
window.open(loginUrl, 'login', 'width=400,height=60');
|
||||
});
|
||||
}
|
||||
]);
|
||||
test.run();
|
||||
}
|
||||
runNetworkTest(theTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -10,6 +10,7 @@ interface WindowProxy;
|
|||
interface nsISupports;
|
||||
interface URI;
|
||||
interface nsIDocShell;
|
||||
interface nsILoadGroup;
|
||||
|
||||
enum VisibilityState { "hidden", "visible" };
|
||||
|
||||
|
@ -354,6 +355,8 @@ partial interface Document {
|
|||
[ChromeOnly] readonly attribute nsIDocShell? docShell;
|
||||
|
||||
[ChromeOnly] readonly attribute DOMString contentLanguage;
|
||||
|
||||
[ChromeOnly] readonly attribute nsILoadGroup? documentLoadGroup;
|
||||
};
|
||||
|
||||
// Extension to give chrome JS the ability to determine when a document was
|
||||
|
|
|
@ -47,6 +47,7 @@ interface NavigatorID {
|
|||
readonly attribute DOMString product; // constant "Gecko"
|
||||
|
||||
// Everyone but WebKit/Blink supports this. See bug 679971.
|
||||
[Exposed=Window]
|
||||
boolean taintEnabled(); // constant false
|
||||
};
|
||||
|
||||
|
|
|
@ -3996,17 +3996,16 @@ WorkerPrivateParent<Derived>::SetBaseURI(nsIURI* aBaseURI)
|
|||
mLocationInfo.mHref.Truncate();
|
||||
}
|
||||
|
||||
if (NS_FAILED(aBaseURI->GetHost(mLocationInfo.mHostname))) {
|
||||
mLocationInfo.mHostname.Truncate();
|
||||
}
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(aBaseURI, mLocationInfo.mHostname);
|
||||
|
||||
if (NS_FAILED(aBaseURI->GetPath(mLocationInfo.mPathname))) {
|
||||
nsCOMPtr<nsIURL> url(do_QueryInterface(aBaseURI));
|
||||
if (!url || NS_FAILED(url->GetFilePath(mLocationInfo.mPathname))) {
|
||||
mLocationInfo.mPathname.Truncate();
|
||||
}
|
||||
|
||||
nsCString temp;
|
||||
|
||||
nsCOMPtr<nsIURL> url(do_QueryInterface(aBaseURI));
|
||||
if (url && NS_SUCCEEDED(url->GetQuery(temp)) && !temp.IsEmpty()) {
|
||||
mLocationInfo.mSearch.Assign('?');
|
||||
mLocationInfo.mSearch.Append(temp);
|
||||
|
|
|
@ -11,7 +11,6 @@ var supportedProps = [
|
|||
{ name: "getDataStores", b2g: true },
|
||||
"platform",
|
||||
"product",
|
||||
"taintEnabled",
|
||||
"userAgent",
|
||||
"onLine",
|
||||
"language",
|
||||
|
@ -66,9 +65,7 @@ function startTest(isB2G) {
|
|||
|
||||
obj = { name: prop };
|
||||
|
||||
if (prop === "taintEnabled") {
|
||||
obj.value = navigator[prop]();
|
||||
} else if (prop === "getDataStores") {
|
||||
if (prop === "getDataStores") {
|
||||
obj.value = typeof navigator[prop];
|
||||
} else {
|
||||
obj.value = navigator[prop];
|
||||
|
|
|
@ -35,11 +35,6 @@ Tests of DOM Worker Navigator
|
|||
return;
|
||||
}
|
||||
|
||||
if (args.name === "taintEnabled") {
|
||||
is(navigator[args.name](), args.value, args.name + "() returns false.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.name === "getDataStores") {
|
||||
var type = typeof navigator[args.name];
|
||||
is(type, args.value, "getDataStores() exists and it's a function.");
|
||||
|
|
|
@ -111,7 +111,7 @@ onmessage = function() {
|
|||
{ url: 'http://example.com/carrot#question%3f',
|
||||
base: undefined,
|
||||
error: false,
|
||||
hash: '#question%3f'
|
||||
hash: '#question?'
|
||||
},
|
||||
{ url: 'https://example.com:4443?',
|
||||
base: undefined,
|
||||
|
|
|
@ -55,8 +55,8 @@
|
|||
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "asmjs/AsmJSModule.h"
|
||||
#include "jit/AtomicOperations.h"
|
||||
|
||||
#include "js/Class.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/SharedTypedArrayObject.h"
|
||||
|
|
|
@ -1503,7 +1503,7 @@ js::testingFunc_inJit(JSContext* cx, unsigned argc, jsval* vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!IsBaselineEnabled(cx)) {
|
||||
if (!jit::IsBaselineEnabled(cx)) {
|
||||
JSString* error = JS_NewStringCopyZ(cx, "Baseline is disabled.");
|
||||
if(!error)
|
||||
return false;
|
||||
|
@ -1531,7 +1531,7 @@ js::testingFunc_inIon(JSContext* cx, unsigned argc, jsval* vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!IsIonEnabled(cx)) {
|
||||
if (!jit::IsIonEnabled(cx)) {
|
||||
JSString* error = JS_NewStringCopyZ(cx, "Ion is disabled.");
|
||||
if (!error)
|
||||
return false;
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
#ifndef ds_IdValuePair_h
|
||||
#define ds_IdValuePair_h
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
#include "js/Id.h"
|
||||
|
||||
namespace js {
|
||||
|
|
|
@ -977,13 +977,13 @@ BytecodeEmitter::leaveNestedScope(StmtInfoBCE* stmt)
|
|||
if (!emit1(stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH))
|
||||
return false;
|
||||
|
||||
blockScopeList.recordEnd(blockScopeIndex, offset());
|
||||
|
||||
if (stmt->isBlockScope && stmt->staticScope->as<StaticBlockObject>().needsClone()) {
|
||||
if (!emit1(JSOP_POPBLOCKSCOPE))
|
||||
return false;
|
||||
}
|
||||
|
||||
blockScopeList.recordEnd(blockScopeIndex, offset());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ ArenaLists::allocateFromArena(JS::Zone* zone, AllocKind thingKind,
|
|||
AutoMaybeStartBackgroundAllocation& maybeStartBGAlloc)
|
||||
{
|
||||
JSRuntime* rt = zone->runtimeFromAnyThread();
|
||||
Maybe<AutoLockGC> maybeLock;
|
||||
mozilla::Maybe<AutoLockGC> maybeLock;
|
||||
|
||||
// See if we can proceed without taking the GC lock.
|
||||
if (backgroundFinalizeState[thingKind] != BFS_DONE)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Test that Debugger.Frame.prototype.environment works at all pcs of a script
|
||||
// with an aliased block scope.
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
frame.onStep = (function () { frame.environment; });
|
||||
};
|
||||
g.eval("debugger; for (let i of [1,2,3]) print(i);");
|
|
@ -0,0 +1,8 @@
|
|||
// |jit-test| error: TypeError
|
||||
var g = newGlobal();
|
||||
g.debuggeeGlobal = this;
|
||||
g.eval("(" + function () {
|
||||
dbg = new Debugger(debuggeeGlobal);
|
||||
dbg.onExceptionUnwind = Map;
|
||||
} + ")();");
|
||||
throw new Error("oops");
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "jit/BacktrackingAllocator.h"
|
||||
#include "jit/LIR.h"
|
||||
#include "jit/MIR.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
|
|
|
@ -1532,8 +1532,8 @@ JitcodeIonTable::WriteIonTable(CompactBufferWriter& writer,
|
|||
JS_PUBLIC_API(JS::ProfilingFrameIterator::FrameKind)
|
||||
JS::GetProfilingFrameKindFromNativeAddr(JSRuntime* rt, void* addr)
|
||||
{
|
||||
JitcodeGlobalTable* table = rt->jitRuntime()->getJitcodeGlobalTable();
|
||||
JitcodeGlobalEntry entry;
|
||||
js::jit::JitcodeGlobalTable* table = rt->jitRuntime()->getJitcodeGlobalTable();
|
||||
js::jit::JitcodeGlobalEntry entry;
|
||||
table->lookupInfallible(addr, &entry, rt);
|
||||
MOZ_ASSERT(entry.isIon() || entry.isIonCache() || entry.isBaseline());
|
||||
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
# error "Wrong architecture. Only x86 and x64 should build this file!"
|
||||
#endif
|
||||
|
||||
#include "jit/RegisterSets.h"
|
||||
|
||||
const char*
|
||||
FloatRegister::name() const {
|
||||
js::jit::FloatRegister::name() const {
|
||||
static const char* const names[] = {
|
||||
|
||||
#ifdef JS_CODEGEN_X64
|
||||
|
@ -38,8 +40,8 @@ FloatRegister::name() const {
|
|||
return names[size_t(code())];
|
||||
}
|
||||
|
||||
FloatRegisterSet
|
||||
FloatRegister::ReduceSetForPush(const FloatRegisterSet& s)
|
||||
js::jit::FloatRegisterSet
|
||||
js::jit::FloatRegister::ReduceSetForPush(const FloatRegisterSet& s)
|
||||
{
|
||||
SetType bits = s.bits();
|
||||
|
||||
|
@ -58,7 +60,7 @@ FloatRegister::ReduceSetForPush(const FloatRegisterSet& s)
|
|||
}
|
||||
|
||||
uint32_t
|
||||
FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s)
|
||||
js::jit::FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s)
|
||||
{
|
||||
SetType all = s.bits();
|
||||
SetType float32x4Set =
|
||||
|
@ -92,7 +94,7 @@ FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s)
|
|||
+ count32b * sizeof(float);
|
||||
}
|
||||
uint32_t
|
||||
FloatRegister::getRegisterDumpOffsetInBytes()
|
||||
js::jit::FloatRegister::getRegisterDumpOffsetInBytes()
|
||||
{
|
||||
return uint32_t(encoding()) * sizeof(FloatRegisters::RegisterContent);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
# error "Unsupported architecture!"
|
||||
#endif
|
||||
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jit/x86-shared/Constants-x86-shared.h"
|
||||
|
||||
namespace js {
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
#ifndef jit_x86_shared_Constants_x86_shared_h
|
||||
#define jit_x86_shared_Constants_x86_shared_h
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ BEGIN_TEST(testForwardSetProperty)
|
|||
|
||||
// Non-strict setter
|
||||
|
||||
ObjectOpResult result;
|
||||
JS::ObjectOpResult result;
|
||||
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, v3, result));
|
||||
CHECK(result);
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
|
||||
BEGIN_TEST(testJSEvaluateScript)
|
||||
{
|
||||
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef jsapi_tests_tests_h
|
||||
#define jsapi_tests_tests_h
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
|
|
@ -125,7 +125,7 @@ class AutoClearPendingException
|
|||
{ }
|
||||
|
||||
~AutoClearPendingException() {
|
||||
cx->clearPendingException();
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1753,7 +1753,13 @@ FindStartPC(JSContext* cx, const FrameIter& iter, int spindex, int skipStackHits
|
|||
|
||||
if (spindex == JSDVG_SEARCH_STACK) {
|
||||
size_t index = iter.numFrameSlots();
|
||||
MOZ_ASSERT(index >= size_t(parser.stackDepthAtPC(current)));
|
||||
|
||||
// The decompiler may be called from inside functions that are not
|
||||
// called from script, but via the C++ API directly, such as
|
||||
// Invoke. In that case, the youngest script frame may have a
|
||||
// completely unrelated pc and stack depth, so we give up.
|
||||
if (index < size_t(parser.stackDepthAtPC(current)))
|
||||
return true;
|
||||
|
||||
// We search from fp->sp to base to find the most recently calculated
|
||||
// value matching v under assumption that it is the value that caused
|
||||
|
|
|
@ -1634,6 +1634,9 @@ class JSScript : public js::gc::TenuredCell
|
|||
return arr->vector[index];
|
||||
}
|
||||
|
||||
// The following 3 functions find the static scope just before the
|
||||
// execution of the instruction pointed to by pc.
|
||||
|
||||
js::NestedScopeObject* getStaticBlockScope(jsbytecode* pc);
|
||||
|
||||
// Returns the innermost static scope at pc if it falls within the extent
|
||||
|
|
|
@ -2202,6 +2202,30 @@ TryNotes(JSContext* cx, HandleScript script, Sprinter* sp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
BlockNotes(JSContext* cx, HandleScript script, Sprinter* sp)
|
||||
{
|
||||
if (!script->hasBlockScopes())
|
||||
return true;
|
||||
|
||||
Sprint(sp, "\nBlock table:\n index parent start end\n");
|
||||
|
||||
BlockScopeArray* scopes = script->blockScopes();
|
||||
for (uint32_t i = 0; i < scopes->length; i++) {
|
||||
const BlockScopeNote* note = &scopes->vector[i];
|
||||
if (note->index == BlockScopeNote::NoBlockScopeIndex)
|
||||
Sprint(sp, "%8s ", "(none)");
|
||||
else
|
||||
Sprint(sp, "%8u ", note->index);
|
||||
if (note->parent == BlockScopeNote::NoBlockScopeIndex)
|
||||
Sprint(sp, "%8s ", "(none)");
|
||||
else
|
||||
Sprint(sp, "%8u ", note->parent);
|
||||
Sprint(sp, "%8u %8u\n", note->start, note->start + note->length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, bool lines,
|
||||
bool recursive, Sprinter* sp)
|
||||
|
@ -2229,6 +2253,7 @@ DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, bool l
|
|||
return false;
|
||||
SrcNotes(cx, script, sp);
|
||||
TryNotes(cx, script, sp);
|
||||
BlockNotes(cx, script, sp);
|
||||
|
||||
if (recursive && script->hasObjects()) {
|
||||
ObjectArray* objects = script->objects();
|
||||
|
@ -2299,6 +2324,7 @@ DisassembleToSprinter(JSContext* cx, unsigned argc, jsval* vp, Sprinter* sprinte
|
|||
return false;
|
||||
SrcNotes(cx, script, sprinter);
|
||||
TryNotes(cx, script, sprinter);
|
||||
BlockNotes(cx, script, sprinter);
|
||||
}
|
||||
} else {
|
||||
for (unsigned i = 0; i < p.argc; i++) {
|
||||
|
@ -4314,7 +4340,7 @@ SetSharedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
class SprintOptimizationTypeInfoOp : public ForEachTrackedOptimizationTypeInfoOp
|
||||
class SprintOptimizationTypeInfoOp : public JS::ForEachTrackedOptimizationTypeInfoOp
|
||||
{
|
||||
Sprinter* sp;
|
||||
bool startedTypes_;
|
||||
|
@ -4345,7 +4371,7 @@ class SprintOptimizationTypeInfoOp : public ForEachTrackedOptimizationTypeInfoOp
|
|||
Sprint(sp, "},");
|
||||
}
|
||||
|
||||
void operator()(TrackedTypeSite site, const char* mirType) override {
|
||||
void operator()(JS::TrackedTypeSite site, const char* mirType) override {
|
||||
if (startedTypes_) {
|
||||
// Clear trailing ,
|
||||
if ((*sp)[sp->getOffset() - 1] == ',')
|
||||
|
@ -4361,7 +4387,7 @@ class SprintOptimizationTypeInfoOp : public ForEachTrackedOptimizationTypeInfoOp
|
|||
}
|
||||
};
|
||||
|
||||
class SprintOptimizationAttemptsOp : public ForEachTrackedOptimizationAttemptOp
|
||||
class SprintOptimizationAttemptsOp : public JS::ForEachTrackedOptimizationAttemptOp
|
||||
{
|
||||
Sprinter* sp;
|
||||
|
||||
|
@ -4370,7 +4396,7 @@ class SprintOptimizationAttemptsOp : public ForEachTrackedOptimizationAttemptOp
|
|||
: sp(sp)
|
||||
{ }
|
||||
|
||||
void operator()(TrackedStrategy strategy, TrackedOutcome outcome) override {
|
||||
void operator()(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome) override {
|
||||
Sprint(sp, "{\"strategy\":\"%s\",\"outcome\":\"%s\"},",
|
||||
TrackedStrategyString(strategy), TrackedOutcomeString(outcome));
|
||||
}
|
||||
|
|
|
@ -2490,6 +2490,7 @@ js::GetDebugScopeForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
|
|||
assertSameCompartment(cx, frame);
|
||||
if (CanUseDebugScopeMaps(cx) && !DebugScopes::updateLiveScopes(cx))
|
||||
return nullptr;
|
||||
|
||||
ScopeIter si(cx, frame, pc);
|
||||
return GetDebugScope(cx, si);
|
||||
}
|
||||
|
|
|
@ -382,10 +382,6 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
|
|||
};
|
||||
nscoord spanISize = ReflowSpans(reflowState);
|
||||
isize = std::max(isize, spanISize);
|
||||
if (isize > aReflowState.AvailableISize() &&
|
||||
aReflowState.mLineLayout->HasOptionalBreakPosition()) {
|
||||
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < rtcCount; i++) {
|
||||
|
|
|
@ -803,8 +803,6 @@ marquee[direction="up"], marquee[direction="down"] {
|
|||
}
|
||||
rt {
|
||||
display: ruby-text;
|
||||
font-variant-east-asian: ruby;
|
||||
text-emphasis: none;
|
||||
}
|
||||
rtc {
|
||||
display: ruby-text-container;
|
||||
|
@ -813,6 +811,12 @@ marquee[direction="up"], marquee[direction="down"] {
|
|||
white-space: nowrap;
|
||||
font-size: 50%;
|
||||
line-height: 1;
|
||||
font-variant-east-asian: ruby;
|
||||
}
|
||||
@supports (text-emphasis: none) {
|
||||
rtc, rt {
|
||||
text-emphasis: none;
|
||||
}
|
||||
}
|
||||
rtc:lang(zh), rt:lang(zh) {
|
||||
ruby-align: center;
|
||||
|
|
|
@ -171,7 +171,7 @@ pref("dom.undo_manager.enabled", false);
|
|||
|
||||
// Whether URL,nsLocation,Link::GetHash should be percent encoded
|
||||
// in setter and percent decoded in getter (old behaviour = true)
|
||||
pref("dom.url.encode_decode_hash", false);
|
||||
pref("dom.url.encode_decode_hash", true);
|
||||
|
||||
// Whether to run add-on code in different compartments from browser code. This
|
||||
// causes a separate compartment for each (addon, global) combination, which may
|
||||
|
|
|
@ -342,3 +342,17 @@
|
|||
[Parsing: <x> against <test:test>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <#\xce\xb2> against <http://example.org/foo/bar>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://www.google.com/foo?bar=baz# \xc2\xbb> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <#β> against <http://example.org/foo/bar>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
|
|
@ -361,3 +361,17 @@
|
|||
[Parsing: <x> against <test:test>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <#\xce\xb2> against <http://example.org/foo/bar>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://www.google.com/foo?bar=baz# \xc2\xbb> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <#β> against <http://example.org/foo/bar>]
|
||||
expected: FAIL
|
||||
|
||||
[Parsing: <http://www.google.com/foo?bar=baz# »> against <about:blank>]
|
||||
expected: FAIL
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
type: testharness
|
||||
[ MessageChannel: port message queue is initially disabled ]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139
|
||||
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
type: testharness
|
||||
[ MessageChannel: port.onmessage enables message queue ]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[WorkerLocation_hash_encoding.htm]
|
||||
type: testharness
|
||||
[ WorkerLocation.hash with url encoding string ]
|
||||
expected: FAIL
|
|
@ -2,6 +2,7 @@
|
|||
type: testharness
|
||||
[WorkerGlobalScope interface: attribute onlanguagechange]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1154779
|
||||
|
||||
[WorkerGlobalScope interface: operation importScripts(DOMString)]
|
||||
expected: FAIL
|
||||
|
@ -29,6 +30,7 @@
|
|||
|
||||
[WorkerGlobalScope interface: self must inherit property "onlanguagechange" with the proper type (4)]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1154779
|
||||
|
||||
[WorkerGlobalScope interface: calling importScripts(DOMString) on self with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[members.html]
|
||||
type: testharness
|
||||
[members of WorkerLocation]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[redirect.html]
|
||||
type: testharness
|
||||
[location with a worker in separate file that redirects]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[setting-members.html]
|
||||
type: testharness
|
||||
[setting members of WorkerLocation]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[worker-separate-file.html]
|
||||
type: testharness
|
||||
[location with a worker in separate file]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[007.html]
|
||||
type: testharness
|
||||
[readonlyness of members of Navigator]
|
||||
expected: FAIL
|
||||
|
|
@ -2,4 +2,5 @@
|
|||
type: testharness
|
||||
[ postMessage(): MessageEvent properties ]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139
|
||||
|
||||
|
|
|
@ -22,10 +22,6 @@ function run_test() {
|
|||
assert_equals(navigator.product, "Gecko");
|
||||
}, "product");
|
||||
|
||||
test(function() {
|
||||
assert_false(navigator.taintEnabled());
|
||||
}, "taintEnabled");
|
||||
|
||||
test(function() {
|
||||
assert_equals(typeof navigator.userAgent, "string",
|
||||
"navigator.userAgent should be a string");
|
||||
|
|
|
@ -96,7 +96,6 @@ interface NavigatorID {
|
|||
readonly attribute DOMString appVersion;
|
||||
readonly attribute DOMString platform;
|
||||
readonly attribute DOMString product; // constant "Gecko"
|
||||
boolean taintEnabled(); // constant false
|
||||
readonly attribute DOMString userAgent;
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<script>
|
||||
async_test(function() {
|
||||
var worker = new Worker('helper-redirect.py?fail');
|
||||
worker.onmessage = this.step_func(function(e) {
|
||||
worker.onmessage = this.step_func_done(function(e) {
|
||||
assert_equals(e.data[0], location.href.replace(/\/[^\/]+$/, '/post-location-members.js?a'));
|
||||
assert_equals(e.data[1], location.protocol);
|
||||
assert_equals(e.data[2], location.host);
|
||||
|
|
|
@ -22,15 +22,12 @@ function section(number, url)
|
|||
}
|
||||
|
||||
let CompatWarning = {
|
||||
warn: function(msg, addon, warning) {
|
||||
if (addon) {
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("ADDON_SHIM_USAGE");
|
||||
histogram.add(addon, warning ? warning.number : 0);
|
||||
}
|
||||
|
||||
if (!Preferences.get("dom.ipc.shims.enabledWarnings", false))
|
||||
return;
|
||||
|
||||
// Sometimes we want to generate a warning, but put off issuing it
|
||||
// until later. For example, if someone registers a listener, we
|
||||
// might only want to warn about it if the listener actually
|
||||
// fires. However, we want the warning to show a stack for the
|
||||
// registration site.
|
||||
delayedWarning: function(msg, addon, warning) {
|
||||
function isShimLayer(filename) {
|
||||
return filename.indexOf("CompatWarning.jsm") != -1 ||
|
||||
filename.indexOf("RemoteAddonsParent.jsm") != -1 ||
|
||||
|
@ -42,6 +39,22 @@ let CompatWarning = {
|
|||
while (stack && isShimLayer(stack.filename))
|
||||
stack = stack.caller;
|
||||
|
||||
let alreadyWarned = false;
|
||||
|
||||
return function() {
|
||||
if (alreadyWarned) {
|
||||
return;
|
||||
}
|
||||
alreadyWarned = true;
|
||||
|
||||
if (addon) {
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("ADDON_SHIM_USAGE");
|
||||
histogram.add(addon, warning ? warning.number : 0);
|
||||
}
|
||||
|
||||
if (!Preferences.get("dom.ipc.shims.enabledWarnings", false))
|
||||
return;
|
||||
|
||||
let error = Cc['@mozilla.org/scripterror;1'].createInstance(Ci.nsIScriptError);
|
||||
if (!error || !Services.console) {
|
||||
// Too late during shutdown to use the nsIConsole
|
||||
|
@ -50,7 +63,7 @@ let CompatWarning = {
|
|||
|
||||
let message = `Warning: ${msg}`;
|
||||
if (warning)
|
||||
message += `\nMore info at: ${url}`;
|
||||
message += `\nMore info at: ${warning.url}`;
|
||||
|
||||
error.init(
|
||||
/*message*/ message,
|
||||
|
@ -61,6 +74,12 @@ let CompatWarning = {
|
|||
/*flags*/ Ci.nsIScriptError.warningFlag,
|
||||
/*category*/ "chrome javascript");
|
||||
Services.console.logMessage(error);
|
||||
};
|
||||
},
|
||||
|
||||
warn: function(msg, addon, warning) {
|
||||
let delayed = this.delayedWarning(msg, addon, warning);
|
||||
delayed();
|
||||
},
|
||||
|
||||
warnings: {
|
||||
|
|
|
@ -375,11 +375,12 @@ let ObserverInterposition = new Interposition("ObserverInterposition");
|
|||
ObserverInterposition.methods.addObserver =
|
||||
function(addon, target, observer, topic, ownsWeak) {
|
||||
if (TOPIC_WHITELIST.indexOf(topic) >= 0) {
|
||||
CompatWarning.warn(`${topic} observer should be added from the child process only.`,
|
||||
addon, CompatWarning.warnings.observers);
|
||||
|
||||
ObserverParent.addObserver(addon, observer, topic);
|
||||
}
|
||||
|
||||
CompatWarning.warn(`${topic} observer should be added from the child process only.`,
|
||||
addon, CompatWarning.warnings.observers);
|
||||
target.addObserver(observer, topic, ownsWeak);
|
||||
};
|
||||
|
||||
|
@ -446,7 +447,7 @@ let EventTargetParent = {
|
|||
return [browser, window];
|
||||
},
|
||||
|
||||
addEventListener: function(addon, target, type, listener, useCapture, wantsUntrusted) {
|
||||
addEventListener: function(addon, target, type, listener, useCapture, wantsUntrusted, delayedWarning) {
|
||||
let newTarget = this.redirectEventTarget(target);
|
||||
if (!newTarget) {
|
||||
return;
|
||||
|
@ -477,7 +478,8 @@ let EventTargetParent = {
|
|||
forType.push({listener: listener,
|
||||
target: target,
|
||||
wantsUntrusted: wantsUntrusted,
|
||||
useCapture: useCapture});
|
||||
useCapture: useCapture,
|
||||
delayedWarning: delayedWarning});
|
||||
},
|
||||
|
||||
removeEventListener: function(addon, target, type, listener, useCapture) {
|
||||
|
@ -527,8 +529,11 @@ let EventTargetParent = {
|
|||
|
||||
// Make a copy in case they call removeEventListener in the listener.
|
||||
let handlers = [];
|
||||
for (let {listener, target, wantsUntrusted, useCapture} of forType) {
|
||||
for (let {listener, target, wantsUntrusted, useCapture, delayedWarning} of forType) {
|
||||
if ((wantsUntrusted || isTrusted) && useCapture == capturing) {
|
||||
// Issue a warning for this listener.
|
||||
delayedWarning();
|
||||
|
||||
handlers.push([listener, target]);
|
||||
}
|
||||
}
|
||||
|
@ -615,10 +620,12 @@ let EventTargetInterposition = new Interposition("EventTargetInterposition");
|
|||
|
||||
EventTargetInterposition.methods.addEventListener =
|
||||
function(addon, target, type, listener, useCapture, wantsUntrusted) {
|
||||
CompatWarning.warn("Registering an event listener on content DOM nodes" +
|
||||
let delayed = CompatWarning.delayedWarning(
|
||||
"Registering an event listener on content DOM nodes" +
|
||||
" needs to happen in the content process.",
|
||||
addon, CompatWarning.warnings.DOM_events);
|
||||
EventTargetParent.addEventListener(addon, target, type, listener, useCapture, wantsUntrusted);
|
||||
|
||||
EventTargetParent.addEventListener(addon, target, type, listener, useCapture, wantsUntrusted, delayed);
|
||||
target.addEventListener(type, makeFilteringListener(type, listener), useCapture, wantsUntrusted);
|
||||
};
|
||||
|
||||
|
|
|
@ -48,6 +48,11 @@ function removeAddon(addon)
|
|||
}
|
||||
|
||||
add_task(function* test_addon_shims() {
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv({set: [["dom.ipc.shims.enabledWarnings", true]]},
|
||||
resolve);
|
||||
});
|
||||
|
||||
let addon = yield addAddon(ADDON_URL);
|
||||
yield window.runAddonShimTests({ok: ok, is: is, info: info});
|
||||
yield removeAddon(addon);
|
||||
|
|
Загрузка…
Ссылка в новой задаче