Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-10-21 11:22:34 +08:00
commit ce8751185f
12 changed files with 240 additions and 169 deletions

View file

@ -308,13 +308,20 @@ RTCStatsReport.prototype = {
// Since maplike is recent, we still also make the stats available as legacy // Since maplike is recent, we still also make the stats available as legacy
// enumerable read-only properties directly on our content-facing object. // enumerable read-only properties directly on our content-facing object.
// Must be called after our webidl sandwich is made. // Must be called after our webidl sandwich is made.
_specToLegacyFieldMapping: {
'inbound-rtp' : 'inboundrtp',
'outbound-rtp':'outboundrtp',
'candidate-pair':'candidatepair',
'local-candidate':'localcandidate',
'remote-candidate':'remotecandidate'
},
makeStatsPublic: function(warnNullable) { makeStatsPublic: function(warnNullable) {
let legacyProps = {}; let legacyProps = {};
for (let key in this._report) { for (let key in this._report) {
this.setInternal(key, Cu.cloneInto(this._report[key], this._win));
let value = Cu.cloneInto(this._report[key], this._win); let value = Cu.cloneInto(this._report[key], this._win);
this.setInternal(key, value); value.type = this._specToLegacyFieldMapping[value.type] || value.type;
legacyProps[key] = { legacyProps[key] = {
enumerable: true, configurable: false, enumerable: true, configurable: false,
get: Cu.exportFunction(function() { get: Cu.exportFunction(function() {

View file

@ -1415,62 +1415,26 @@ PeerConnectionWrapper.prototype = {
* A promise that resolves when media is flowing. * A promise that resolves when media is flowing.
*/ */
waitForRtpFlow(track) { waitForRtpFlow(track) {
var hasFlow = (stats, retries) => { var hasFlow = stats => {
info("Checking for stats in " + JSON.stringify(stats) + " for " + track.kind var rtp = stats.get([...stats.keys()].find(key =>
+ " track " + track.id + ", retry number " + retries); !stats.get(key).isRemote && stats.get(key).type.endsWith("bound-rtp")));
var rtp = stats.get([...Object.keys(stats)].find(key => ok(rtp, "Should have RTP stats for track " + track.id);
!stats.get(key).isRemote && stats.get(key).type.endsWith("boundrtp")));
if (!rtp) { if (!rtp) {
return false; return false;
} }
info("Should have RTP stats for track " + track.id); var nrPackets = rtp[rtp.type == "outbound-rtp" ? "packetsSent"
info("RTP stats: "+JSON.stringify(rtp));
var nrPackets = rtp[rtp.type == "outboundrtp" ? "packetsSent"
: "packetsReceived"]; : "packetsReceived"];
info("Track " + track.id + " has " + nrPackets + " " + info("Track " + track.id + " has " + nrPackets + " " +
rtp.type + " RTP packets."); rtp.type + " RTP packets.");
return nrPackets > 0; return nrPackets > 0;
}; };
// Time between stats checks
var retryInterval = 500;
// Timeout in ms
var timeoutInterval = 30000;
// Check hasFlow at a reasonable interval
var checkStats = new Promise((resolve, reject)=>{
var retries = 0;
var timer = setInterval(()=>{
this._pc.getStats(track).then(stats=>{
if (hasFlow(stats, retries)) {
clearInterval(timer);
ok(true, "RTP flowing for " + track.kind + " track " + track.id);
resolve();
}
retries = retries + 1;
// This is not accurate but it will tear down
// the timer eventually and probably not
// before timeoutInterval has elapsed.
if ((retries * retryInterval) > timeoutInterval) {
clearInterval(timer);
}
});
}, retryInterval);
});
info("Checking RTP packet flow for track " + track.id); info("Checking RTP packet flow for track " + track.id);
var retry = Promise.race([checkStats.then(new Promise((resolve, reject)=>{
info("checkStats completed for " + track.kind + " track " + track.id);
resolve();
})),
new Promise((accept,reject)=>wait(timeoutInterval).then(()=>{
info("Timeout checking for stats for track " + track.id + " after " + timeoutInterval + "ms");
reject("Timeout checking for stats for " + track.kind
+ " track " + track.id + " after " + timeoutInterval + "ms");
})
)]);
return retry; var retry = (delay) => this._pc.getStats(track)
.then(stats => hasFlow(stats)? ok(true, "RTP flowing for track " + track.id) :
wait(delay).then(retry(1000)));
return retry(200);
}, },
/** /**
@ -1572,9 +1536,7 @@ PeerConnectionWrapper.prototype = {
var minimum = this.whenCreated - 1000; // on Windows XP (Bug 979649) var minimum = this.whenCreated - 1000; // on Windows XP (Bug 979649)
if (isWinXP) { if (isWinXP) {
todo(false, "Can't reliably test rtcp timestamps on WinXP (Bug 979649)"); todo(false, "Can't reliably test rtcp timestamps on WinXP (Bug 979649)");
} else if (!twoMachines) {
} else if (false) { // Bug 1325430 - timestamps aren't working properly in update 49
// else if (!twoMachines) {
// Bug 1225729: On android, sometimes the first RTCP of the first // Bug 1225729: On android, sometimes the first RTCP of the first
// test run gets this value, likely because no RTP has been sent yet. // test run gets this value, likely because no RTP has been sent yet.
if (res.timestamp != 2085978496000) { if (res.timestamp != 2085978496000) {
@ -1597,15 +1559,15 @@ PeerConnectionWrapper.prototype = {
counters[res.type] = (counters[res.type] || 0) + 1; counters[res.type] = (counters[res.type] || 0) + 1;
switch (res.type) { switch (res.type) {
case "inboundrtp": case "inbound-rtp":
case "outboundrtp": { case "outbound-rtp": {
// ssrc is a 32 bit number returned as a string by spec // ssrc is a 32 bit number returned as a string by spec
ok(res.ssrc.length > 0, "Ssrc has length"); ok(res.ssrc.length > 0, "Ssrc has length");
ok(res.ssrc.length < 11, "Ssrc not lengthy"); ok(res.ssrc.length < 11, "Ssrc not lengthy");
ok(!/[^0-9]/.test(res.ssrc), "Ssrc numeric"); ok(!/[^0-9]/.test(res.ssrc), "Ssrc numeric");
ok(parseInt(res.ssrc) < Math.pow(2,32), "Ssrc within limits"); ok(parseInt(res.ssrc) < Math.pow(2,32), "Ssrc within limits");
if (res.type == "outboundrtp") { if (res.type == "outbound-rtp") {
ok(res.packetsSent !== undefined, "Rtp packetsSent"); ok(res.packetsSent !== undefined, "Rtp packetsSent");
// We assume minimum payload to be 1 byte (guess from RFC 3550) // We assume minimum payload to be 1 byte (guess from RFC 3550)
ok(res.bytesSent >= res.packetsSent, "Rtp bytesSent"); ok(res.bytesSent >= res.packetsSent, "Rtp bytesSent");
@ -1614,25 +1576,16 @@ PeerConnectionWrapper.prototype = {
ok(res.bytesReceived >= res.packetsReceived, "Rtp bytesReceived"); ok(res.bytesReceived >= res.packetsReceived, "Rtp bytesReceived");
} }
if (res.remoteId) { if (res.remoteId) {
var rem = stats[res.remoteId]; var rem = stats.get(res.remoteId);
ok(rem.isRemote, "Remote is rtcp"); ok(rem.isRemote, "Remote is rtcp");
ok(rem.remoteId == res.id, "Remote backlink match"); ok(rem.remoteId == res.id, "Remote backlink match");
if(res.type == "outboundrtp") { if(res.type == "outbound-rtp") {
ok(rem.type == "inboundrtp", "Rtcp is inbound"); ok(rem.type == "inbound-rtp", "Rtcp is inbound");
ok(rem.packetsReceived !== undefined, "Rtcp packetsReceived"); ok(rem.packetsReceived !== undefined, "Rtcp packetsReceived");
ok(rem.packetsLost !== undefined, "Rtcp packetsLost"); ok(rem.packetsLost !== undefined, "Rtcp packetsLost");
ok(rem.bytesReceived >= rem.packetsReceived, "Rtcp bytesReceived"); ok(rem.bytesReceived >= rem.packetsReceived, "Rtcp bytesReceived");
if (false) { // Bug 1325430 if (!this.disableRtpCountChecking) { if (!this.disableRtpCountChecking) {
// no guarantee which one is newer!
// Note: this must change when we add a timestamp field to remote RTCP reports
// and make rem.timestamp be the reception time
if (res.timestamp >= rem.timestamp) {
ok(rem.packetsReceived <= res.packetsSent, "No more than sent packets"); ok(rem.packetsReceived <= res.packetsSent, "No more than sent packets");
} else {
info("REVERSED timestamps: rec:" +
rem.packetsReceived + " time:" + rem.timestamp + " sent:" + res.packetsSent + " time:" + res.timestamp);
}
// Else we may have received more than outdated Rtcp packetsSent
ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes"); ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes");
} }
ok(rem.jitter !== undefined, "Rtcp jitter"); ok(rem.jitter !== undefined, "Rtcp jitter");
@ -1640,7 +1593,7 @@ PeerConnectionWrapper.prototype = {
ok(rem.mozRtt >= 0, "Rtcp rtt " + rem.mozRtt + " >= 0"); ok(rem.mozRtt >= 0, "Rtcp rtt " + rem.mozRtt + " >= 0");
ok(rem.mozRtt < 60000, "Rtcp rtt " + rem.mozRtt + " < 1 min"); ok(rem.mozRtt < 60000, "Rtcp rtt " + rem.mozRtt + " < 1 min");
} else { } else {
ok(rem.type == "outboundrtp", "Rtcp is outbound"); ok(rem.type == "outbound-rtp", "Rtcp is outbound");
ok(rem.packetsSent !== undefined, "Rtcp packetsSent"); ok(rem.packetsSent !== undefined, "Rtcp packetsSent");
// We may have received more than outdated Rtcp packetsSent // We may have received more than outdated Rtcp packetsSent
ok(rem.bytesSent >= rem.packetsSent, "Rtcp bytesSent"); ok(rem.bytesSent >= rem.packetsSent, "Rtcp bytesSent");
@ -1654,6 +1607,13 @@ PeerConnectionWrapper.prototype = {
} }
} }
var legacyToSpecMapping = {
'inboundrtp':'inbound-rtp',
'outboundrtp':'outbound-rtp',
'candidatepair':'candidate-pair',
'localcandidate':'local-candidate',
'remotecandidate':'remote-candidate'
};
// Use legacy way of enumerating stats // Use legacy way of enumerating stats
var counters2 = {}; var counters2 = {};
for (let key in stats) { for (let key in stats) {
@ -1661,8 +1621,9 @@ PeerConnectionWrapper.prototype = {
continue; continue;
} }
var res = stats[key]; var res = stats[key];
var type = legacyToSpecMapping[res.type] || res.type;
if (!res.isRemote) { if (!res.isRemote) {
counters2[res.type] = (counters2[res.type] || 0) + 1; counters2[type] = (counters2[type] || 0) + 1;
} }
} }
is(JSON.stringify(counters), JSON.stringify(counters2), is(JSON.stringify(counters), JSON.stringify(counters2),
@ -1671,21 +1632,21 @@ PeerConnectionWrapper.prototype = {
var nout = Object.keys(this.expectedLocalTrackInfoById).length; var nout = Object.keys(this.expectedLocalTrackInfoById).length;
var ndata = this.dataChannels.length; var ndata = this.dataChannels.length;
// TODO(Bug 957145): Restore stronger inboundrtp test once Bug 948249 is fixed // TODO(Bug 957145): Restore stronger inbound-rtp test once Bug 948249 is fixed
//is((counters["inboundrtp"] || 0), nin, "Have " + nin + " inboundrtp stat(s)"); //is((counters["inbound-rtp"] || 0), nin, "Have " + nin + " inbound-rtp stat(s)");
ok((counters.inboundrtp || 0) >= nin, "Have at least " + nin + " inboundrtp stat(s) *"); ok((counters["inbound-rtp"] || 0) >= nin, "Have at least " + nin + " inbound-rtp stat(s) *");
is(counters.outboundrtp || 0, nout, "Have " + nout + " outboundrtp stat(s)"); is(counters["outbound-rtp"] || 0, nout, "Have " + nout + " outbound-rtp stat(s)");
var numLocalCandidates = counters.localcandidate || 0; var numLocalCandidates = counters["local-candidate"] || 0;
var numRemoteCandidates = counters.remotecandidate || 0; var numRemoteCandidates = counters["remote-candidate"] || 0;
// If there are no tracks, there will be no stats either. // If there are no tracks, there will be no stats either.
if (nin + nout + ndata > 0) { if (nin + nout + ndata > 0) {
ok(numLocalCandidates, "Have localcandidate stat(s)"); ok(numLocalCandidates, "Have local-candidate stat(s)");
ok(numRemoteCandidates, "Have remotecandidate stat(s)"); ok(numRemoteCandidates, "Have remote-candidate stat(s)");
} else { } else {
is(numLocalCandidates, 0, "Have no localcandidate stats"); is(numLocalCandidates, 0, "Have no local-candidate stats");
is(numRemoteCandidates, 0, "Have no remotecandidate stats"); is(numRemoteCandidates, 0, "Have no remote-candidate stats");
} }
}, },
@ -1700,7 +1661,7 @@ PeerConnectionWrapper.prototype = {
let lId; let lId;
let rId; let rId;
for (let stat of stats.values()) { for (let stat of stats.values()) {
if (stat.type == "candidatepair" && stat.selected) { if (stat.type == "candidate-pair" && stat.selected) {
lId = stat.localCandidateId; lId = stat.localCandidateId;
rId = stat.remoteCandidateId; rId = stat.remoteCandidateId;
break; break;
@ -1751,8 +1712,8 @@ PeerConnectionWrapper.prototype = {
checkStatsIceConnections : function(stats, checkStatsIceConnections : function(stats,
offerConstraintsList, offerOptions, testOptions) { offerConstraintsList, offerOptions, testOptions) {
var numIceConnections = 0; var numIceConnections = 0;
Object.keys(stats).forEach(key => { stats.forEach(stat => {
if ((stats[key].type === "candidatepair") && stats[key].selected) { if ((stat.type === "candidate-pair") && stat.selected) {
numIceConnections += 1; numIceConnections += 1;
} }
}); });

View file

@ -90,12 +90,12 @@ function checkTrackStats(pc, rtpSenderOrReceiver, outbound) {
(audio ? "audio" : "video") + " rtp track id " + track.id; (audio ? "audio" : "video") + " rtp track id " + track.id;
return pc.getStats(track).then(stats => { return pc.getStats(track).then(stats => {
ok(pc.hasStat(stats, { ok(pc.hasStat(stats, {
type: outbound ? "outboundrtp" : "inboundrtp", type: outbound ? "outbound-rtp" : "inbound-rtp",
isRemote: false, isRemote: false,
mediaType: audio ? "audio" : "video" mediaType: audio ? "audio" : "video"
}), msg + " - found expected stats"); }), msg + " - found expected stats");
ok(!pc.hasStat(stats, { ok(!pc.hasStat(stats, {
type: outbound ? "inboundrtp" : "outboundrtp", type: outbound ? "inbound-rtp" : "outbound-rtp",
isRemote: false isRemote: false
}), msg + " - did not find extra stats with wrong direction"); }), msg + " - did not find extra stats with wrong direction");
ok(!pc.hasStat(stats, { ok(!pc.hasStat(stats, {

View file

@ -72,7 +72,7 @@ template<>
struct ParamTraits<mozilla::dom::RTCStatsType> : struct ParamTraits<mozilla::dom::RTCStatsType> :
public ContiguousEnumSerializer< public ContiguousEnumSerializer<
mozilla::dom::RTCStatsType, mozilla::dom::RTCStatsType,
mozilla::dom::RTCStatsType::Inboundrtp, mozilla::dom::RTCStatsType::Inbound_rtp,
mozilla::dom::RTCStatsType::EndGuard_> mozilla::dom::RTCStatsType::EndGuard_>
{}; {};

View file

@ -9,14 +9,14 @@
*/ */
enum RTCStatsType { enum RTCStatsType {
"inboundrtp", "inbound-rtp",
"outboundrtp", "outbound-rtp",
"session", "session",
"track", "track",
"transport", "transport",
"candidatepair", "candidate-pair",
"localcandidate", "local-candidate",
"remotecandidate" "remote-candidate"
}; };
dictionary RTCStats { dictionary RTCStats {

View file

@ -647,34 +647,64 @@ function GetOption(options, property, type, values, fallback) {
return fallback; return fallback;
} }
/**
* The abstract operation DefaultNumberOption converts value to a Number value,
* checks whether it is in the allowed range, and fills in a fallback value if
* necessary.
*
* Spec: ECMAScript Internationalization API Specification, 9.2.11.
*/
function DefaultNumberOption(value, minimum, maximum, fallback) {
assert(
typeof minimum === "number" && (minimum | 0) === minimum,
"DefaultNumberOption"
);
assert(
typeof maximum === "number" && (maximum | 0) === maximum,
"DefaultNumberOption"
);
assert(
fallback === undefined ||
(typeof fallback === "number" && (fallback | 0) === fallback),
"DefaultNumberOption"
);
assert(
fallback === undefined || (minimum <= fallback && fallback <= maximum),
"DefaultNumberOption"
);
// Step 1.
if (value === undefined) {
return fallback;
}
// Step 2.
value = ToNumber(value);
// Step 3.
if (Number_isNaN(value) || value < minimum || value > maximum) {
ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value);
}
// Step 4.
// Apply bitwise-or to convert -0 to +0 per ES2017, 5.2 and to ensure the
// result is an int32 value.
return std_Math_floor(value) | 0;
}
/** /**
* Extracts a property value from the provided options object, converts it to a * Extracts a property value from the provided options object, converts it to a
* Number value, checks whether it is in the allowed range, and fills in a * Number value, checks whether it is in the allowed range, and fills in a
* fallback value if necessary. * fallback value if necessary.
* *
* Spec: ECMAScript Internationalization API Specification, 9.2.10. * Spec: ECMAScript Internationalization API Specification, 9.2.12.
*/ */
function GetNumberOption(options, property, minimum, maximum, fallback) { function GetNumberOption(options, property, minimum, maximum, fallback) {
assert(typeof minimum === "number", "GetNumberOption"); // Steps 1-3.
assert(typeof maximum === "number", "GetNumberOption"); return DefaultNumberOption(options[property], minimum, maximum, fallback);
assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption");
// Step 1.
var value = options[property];
// Step 2.
if (value !== undefined) {
value = ToNumber(value);
if (Number_isNaN(value) || value < minimum || value > maximum)
ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value);
return std_Math_floor(value);
}
// Step 3.
return fallback;
} }
// Symbols in the self-hosting compartment can't be cloned, use a separate // Symbols in the self-hosting compartment can't be cloned, use a separate
// object to hold the actual symbol value. // object to hold the actual symbol value.
// TODO: Can we add support to clone symbols? // TODO: Can we add support to clone symbols?

View file

@ -353,10 +353,6 @@ NewUNumberFormat(JSContext* cx, Handle<NumberFormatObject*> numberFormat)
return nullptr; return nullptr;
uMaximumSignificantDigits = value.toInt32(); uMaximumSignificantDigits = value.toInt32();
} else { } else {
if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
&value))
return nullptr;
uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
if (!GetProperty(cx, internals, internals, cx->names().minimumFractionDigits, if (!GetProperty(cx, internals, internals, cx->names().minimumFractionDigits,
&value)) &value))
return nullptr; return nullptr;
@ -367,6 +363,11 @@ NewUNumberFormat(JSContext* cx, Handle<NumberFormatObject*> numberFormat)
uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32()); uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());
} }
if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
&value))
return nullptr;
uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
if (!GetProperty(cx, internals, internals, cx->names().useGrouping, &value)) if (!GetProperty(cx, internals, internals, cx->names().useGrouping, &value))
return nullptr; return nullptr;
uUseGrouping = value.toBoolean(); uUseGrouping = value.toBoolean();

View file

@ -55,8 +55,14 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
// Step 22. // Step 22.
internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits; internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits;
if ("minimumFractionDigits" in lazyNumberFormatData) {
// Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the
// actual presence (versus undefined-ness) of these properties.
assert("maximumFractionDigits" in lazyNumberFormatData, "min/max frac digits mismatch");
internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits; internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits;
internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits; internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits;
}
if ("minimumSignificantDigits" in lazyNumberFormatData) { if ("minimumSignificantDigits" in lazyNumberFormatData) {
// Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the // Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the
@ -122,33 +128,89 @@ function UnwrapNumberFormat(nf, methodName) {
* *
* Spec: ECMAScript Internationalization API Specification, 11.1.1. * Spec: ECMAScript Internationalization API Specification, 11.1.1.
*/ */
function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault) { function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault, mxfdDefault) {
// We skip step 1 because we set the properties on a lazyData object. // We skip step 1 because we set the properties on a lazyData object.
// Steps 2-4. // Steps 2-4.
assert(IsObject(options), "SetNumberFormatDigitOptions"); assert(IsObject(options), "SetNumberFormatDigitOptions");
assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions"); assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions");
// Steps 5-8. assert(typeof mxfdDefault === "number", "SetNumberFormatDigitOptions");
const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); assert(mnfdDefault <= mxfdDefault, "SetNumberFormatDigitOptions");
const mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault);
const mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20);
// Steps 9-10. // Steps 5-9.
const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1);
let mnfd = options.minimumFractionDigits;
let mxfd = options.maximumFractionDigits;
let mnsd = options.minimumSignificantDigits; let mnsd = options.minimumSignificantDigits;
let mxsd = options.maximumSignificantDigits; let mxsd = options.maximumSignificantDigits;
// Steps 9-11. // Step 10.
lazyData.minimumIntegerDigits = mnid; lazyData.minimumIntegerDigits = mnid;
lazyData.minimumFractionDigits = mnfd;
lazyData.maximumFractionDigits = mxfd; // Step 11.
if (mnsd !== undefined || mxsd !== undefined) {
// Step 11.a (Omitted).
// Step 11.b.
mnsd = DefaultNumberOption(mnsd, 1, 21, 1);
// Step 11.c.
mxsd = DefaultNumberOption(mxsd, mnsd, 21, 21);
// Step 11.d.
lazyData.minimumSignificantDigits = mnsd;
// Step 11.e.
lazyData.maximumSignificantDigits = mxsd;
}
// Step 12. // Step 12.
if (mnsd !== undefined || mxsd !== undefined) { else if (mnfd !== undefined || mxfd !== undefined) {
mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); // Step 12.a (Omitted).
mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21);
lazyData.minimumSignificantDigits = mnsd; // Step 12.b.
lazyData.maximumSignificantDigits = mxsd; mnfd = DefaultNumberOption(mnfd, 0, 20, undefined);
// Step 12.c.
mxfd = DefaultNumberOption(mxfd, 0, 20, undefined);
// Steps 12.d-e.
// Inlined DefaultNumberOption, only the fallback case applies here.
if (mnfd === undefined) {
assert(mxfd !== undefined, "mxfd isn't undefined when mnfd is undefined");
mnfd = std_Math_min(mnfdDefault, mxfd);
}
// Step 12.f.
// Inlined DefaultNumberOption, only the fallback case applies here.
else if (mxfd === undefined) {
mxfd = std_Math_max(mxfdDefault, mnfd);
}
// Step 12.g.
else if (mnfd > mxfd) {
ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, mxfd);
}
// Step 12.h.
lazyData.minimumFractionDigits = mnfd;
// Step 12.i.
lazyData.maximumFractionDigits = mxfd;
}
// Step 13 (TODO: Not yet implemented).
// Step 14.
else {
// Step 14.a (Omitted).
// Step 14.b.
lazyData.minimumFractionDigits = mnfdDefault;
// Step 14.c.
lazyData.maximumFractionDigits = mxfdDefault;
} }
} }
@ -291,19 +353,16 @@ function InitializeNumberFormat(numberFormat, thisValue, locales, options) {
if (s === "currency") if (s === "currency")
lazyNumberFormatData.currencyDisplay = cd; lazyNumberFormatData.currencyDisplay = cd;
// Steps 20-22. // Steps 22-25.
SetNumberFormatDigitOptions(lazyNumberFormatData, options, s === "currency" ? cDigits: 0); var mnfdDefault, mxfdDefault;
if (s === "currency") {
// Step 25. mnfdDefault = cDigits;
if (lazyNumberFormatData.maximumFractionDigits === undefined) { mxfdDefault = cDigits;
let mxfdDefault = s === "currency" } else {
? cDigits mnfdDefault = 0;
: s === "percent" mxfdDefault = s === "percent" ? 0 : 3;
? 0
: 3;
lazyNumberFormatData.maximumFractionDigits =
std_Math_max(lazyNumberFormatData.minimumFractionDigits, mxfdDefault);
} }
SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault);
// Steps 23. // Steps 23.
var g = GetOption(options, "useGrouping", "boolean", undefined, true); var g = GetOption(options, "useGrouping", "boolean", undefined, true);
@ -520,8 +579,6 @@ function Intl_NumberFormat_resolvedOptions() {
numberingSystem: internals.numberingSystem, numberingSystem: internals.numberingSystem,
style: internals.style, style: internals.style,
minimumIntegerDigits: internals.minimumIntegerDigits, minimumIntegerDigits: internals.minimumIntegerDigits,
minimumFractionDigits: internals.minimumFractionDigits,
maximumFractionDigits: internals.maximumFractionDigits,
useGrouping: internals.useGrouping useGrouping: internals.useGrouping
}; };
@ -536,6 +593,15 @@ function Intl_NumberFormat_resolvedOptions() {
_DefineDataProperty(result, "currencyDisplay", internals.currencyDisplay); _DefineDataProperty(result, "currencyDisplay", internals.currencyDisplay);
} }
// Min/Max fraction digits are either both present or not present at all.
assert(hasOwn("minimumFractionDigits", internals) ===
hasOwn("maximumFractionDigits", internals),
"minimumFractionDigits is present iff maximumFractionDigits is present");
if (hasOwn("minimumFractionDigits", internals)) {
_DefineDataProperty(result, "minimumFractionDigits", internals.minimumFractionDigits);
_DefineDataProperty(result, "maximumFractionDigits", internals.maximumFractionDigits);
}
// Min/Max significant digits are either both present or not at all. // Min/Max significant digits are either both present or not at all.
assert(hasOwn("minimumSignificantDigits", internals) === assert(hasOwn("minimumSignificantDigits", internals) ===
hasOwn("maximumSignificantDigits", internals), hasOwn("maximumSignificantDigits", internals),

View file

@ -224,11 +224,6 @@ NewUNumberFormatForPluralRules(JSContext* cx, Handle<PluralRulesObject*> pluralR
return nullptr; return nullptr;
uMaximumSignificantDigits = value.toInt32(); uMaximumSignificantDigits = value.toInt32();
} else { } else {
if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
&value))
return nullptr;
uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
if (!GetProperty(cx, internals, internals, cx->names().minimumFractionDigits, if (!GetProperty(cx, internals, internals, cx->names().minimumFractionDigits,
&value)) &value))
return nullptr; return nullptr;
@ -240,6 +235,11 @@ NewUNumberFormatForPluralRules(JSContext* cx, Handle<PluralRulesObject*> pluralR
uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32()); uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());
} }
if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
&value))
return nullptr;
uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
UNumberFormat* nf = unum_open(UNUM_DECIMAL, nullptr, 0, IcuLocale(locale.ptr()), nullptr, &status); UNumberFormat* nf = unum_open(UNUM_DECIMAL, nullptr, 0, IcuLocale(locale.ptr()), nullptr, &status);
if (U_FAILURE(status)) { if (U_FAILURE(status)) {

View file

@ -53,8 +53,12 @@ function resolvePluralRulesInternals(lazyPluralRulesData) {
// Step 9. // Step 9.
internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits; internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits;
if ("minimumFractionDigits" in lazyPluralRulesData) {
assert("maximumFractionDigits" in lazyPluralRulesData, "min/max frac digits mismatch");
internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits; internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits;
internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits; internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits;
}
if ("minimumSignificantDigits" in lazyPluralRulesData) { if ("minimumSignificantDigits" in lazyPluralRulesData) {
assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch"); assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch");
@ -149,14 +153,8 @@ function InitializePluralRules(pluralRules, locales, options) {
const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal"); const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal");
lazyPluralRulesData.type = type; lazyPluralRulesData.type = type;
// Step 9. // Steps 11-12.
SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0); SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3);
// Step 12.
if (lazyPluralRulesData.maximumFractionDigits === undefined) {
lazyPluralRulesData.maximumFractionDigits =
std_Math_max(lazyPluralRulesData.minimumFractionDigits, 3);
}
// Step 15. // Step 15.
// //
@ -246,11 +244,19 @@ function Intl_PluralRules_resolvedOptions() {
type: internals.type, type: internals.type,
pluralCategories: callFunction(std_Array_slice, internals.pluralCategories, 0), pluralCategories: callFunction(std_Array_slice, internals.pluralCategories, 0),
minimumIntegerDigits: internals.minimumIntegerDigits, minimumIntegerDigits: internals.minimumIntegerDigits,
minimumFractionDigits: internals.minimumFractionDigits,
maximumFractionDigits: internals.maximumFractionDigits,
}; };
// Min/Max significant digits are either both present or not at all. // Min/Max fraction digits are either both present or not present at all.
assert(hasOwn("minimumFractionDigits", internals) ===
hasOwn("maximumFractionDigits", internals),
"minimumFractionDigits is present iff maximumFractionDigits is present");
if (hasOwn("minimumFractionDigits", internals)) {
_DefineDataProperty(result, "minimumFractionDigits", internals.minimumFractionDigits);
_DefineDataProperty(result, "maximumFractionDigits", internals.maximumFractionDigits);
}
// Min/Max significant digits are either both present or not present at all.
assert(hasOwn("minimumSignificantDigits", internals) === assert(hasOwn("minimumSignificantDigits", internals) ===
hasOwn("maximumSignificantDigits", internals), hasOwn("maximumSignificantDigits", internals),
"minimumSignificantDigits is present iff maximumSignificantDigits is present"); "minimumSignificantDigits is present iff maximumSignificantDigits is present");

View file

@ -3611,7 +3611,7 @@ static void ToRTCIceCandidateStats(
cand.mPortNumber.Construct(c->cand_addr.port); cand.mPortNumber.Construct(c->cand_addr.port);
cand.mTransport.Construct( cand.mTransport.Construct(
NS_ConvertASCIItoUTF16(c->cand_addr.transport.c_str())); NS_ConvertASCIItoUTF16(c->cand_addr.transport.c_str()));
if (candidateType == RTCStatsType::Localcandidate) { if (candidateType == RTCStatsType::Local_candidate) {
cand.mMozLocalTransport.Construct( cand.mMozLocalTransport.Construct(
NS_ConvertASCIItoUTF16(c->local_addr.transport.c_str())); NS_ConvertASCIItoUTF16(c->local_addr.transport.c_str()));
} }
@ -3645,7 +3645,7 @@ static void RecordIceStats_s(
s.mId.Construct(codeword); s.mId.Construct(codeword);
s.mComponentId.Construct(componentId); s.mComponentId.Construct(componentId);
s.mTimestamp.Construct(now); s.mTimestamp.Construct(now);
s.mType.Construct(RTCStatsType::Candidatepair); s.mType.Construct(RTCStatsType::Candidate_pair);
s.mLocalCandidateId.Construct(localCodeword); s.mLocalCandidateId.Construct(localCodeword);
s.mRemoteCandidateId.Construct(remoteCodeword); s.mRemoteCandidateId.Construct(remoteCodeword);
s.mNominated.Construct(p->nominated); s.mNominated.Construct(p->nominated);
@ -3658,7 +3658,7 @@ static void RecordIceStats_s(
std::vector<NrIceCandidate> candidates; std::vector<NrIceCandidate> candidates;
if (NS_SUCCEEDED(mediaStream.GetLocalCandidates(&candidates))) { if (NS_SUCCEEDED(mediaStream.GetLocalCandidates(&candidates))) {
ToRTCIceCandidateStats(candidates, ToRTCIceCandidateStats(candidates,
RTCStatsType::Localcandidate, RTCStatsType::Local_candidate,
componentId, componentId,
now, now,
report); report);
@ -3667,7 +3667,7 @@ static void RecordIceStats_s(
if (NS_SUCCEEDED(mediaStream.GetRemoteCandidates(&candidates))) { if (NS_SUCCEEDED(mediaStream.GetRemoteCandidates(&candidates))) {
ToRTCIceCandidateStats(candidates, ToRTCIceCandidateStats(candidates,
RTCStatsType::Remotecandidate, RTCStatsType::Remote_candidate,
componentId, componentId,
now, now,
report); report);
@ -3721,7 +3721,7 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
RTCInboundRTPStreamStats s; RTCInboundRTPStreamStats s;
s.mTimestamp.Construct(timestamp); s.mTimestamp.Construct(timestamp);
s.mId.Construct(remoteId); s.mId.Construct(remoteId);
s.mType.Construct(RTCStatsType::Inboundrtp); s.mType.Construct(RTCStatsType::Inbound_rtp);
if (ssrc.Length()) { if (ssrc.Length()) {
s.mSsrc.Construct(ssrc); s.mSsrc.Construct(ssrc);
} }
@ -3742,7 +3742,7 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
RTCOutboundRTPStreamStats s; RTCOutboundRTPStreamStats s;
s.mTimestamp.Construct(query->now); s.mTimestamp.Construct(query->now);
s.mId.Construct(localId); s.mId.Construct(localId);
s.mType.Construct(RTCStatsType::Outboundrtp); s.mType.Construct(RTCStatsType::Outbound_rtp);
if (ssrc.Length()) { if (ssrc.Length()) {
s.mSsrc.Construct(ssrc); s.mSsrc.Construct(ssrc);
} }
@ -3795,7 +3795,7 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
RTCOutboundRTPStreamStats s; RTCOutboundRTPStreamStats s;
s.mTimestamp.Construct(timestamp); s.mTimestamp.Construct(timestamp);
s.mId.Construct(remoteId); s.mId.Construct(remoteId);
s.mType.Construct(RTCStatsType::Outboundrtp); s.mType.Construct(RTCStatsType::Outbound_rtp);
if (ssrc.Length()) { if (ssrc.Length()) {
s.mSsrc.Construct(ssrc); s.mSsrc.Construct(ssrc);
} }
@ -3812,7 +3812,7 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
RTCInboundRTPStreamStats s; RTCInboundRTPStreamStats s;
s.mTimestamp.Construct(query->now); s.mTimestamp.Construct(query->now);
s.mId.Construct(localId); s.mId.Construct(localId);
s.mType.Construct(RTCStatsType::Inboundrtp); s.mType.Construct(RTCStatsType::Inbound_rtp);
if (ssrc.Length()) { if (ssrc.Length()) {
s.mSsrc.Construct(ssrc); s.mSsrc.Construct(ssrc);
} }

View file

@ -1066,7 +1066,7 @@ static void StoreLongTermICEStatisticsImpl_m(
uint32_t candBitmask = GetCandidateIpAndTransportMask(&cand); uint32_t candBitmask = GetCandidateIpAndTransportMask(&cand);
// Note: shift values need to result in the above enum table // Note: shift values need to result in the above enum table
if (cand.mType.Value() == RTCStatsType::Localcandidate) { if (cand.mType.Value() == RTCStatsType::Local_candidate) {
candBitmask <<= kLocalShift; candBitmask <<= kLocalShift;
} }