mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to f-t
This commit is contained in:
commit
a7a1d85013
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="53517af1f57810bef745f03602f407161a475d76"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "5bcc08a732163087999251b523e3643db397412c",
|
||||
"git_revision": "7cd4130d4f988562a77d126860408ada65bb95ef",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "66ad152ea50938f799bf7edd4bc2088f47b85c00",
|
||||
"revision": "70c21fc8fb4b014e751d1442161c4beabbfaa6bd",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="53517af1f57810bef745f03602f407161a475d76"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="5bcc08a732163087999251b523e3643db397412c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7cd4130d4f988562a77d126860408ada65bb95ef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -174,7 +174,9 @@ public:
|
||||
mMethodString = aString;
|
||||
|
||||
for (uint32_t i = 0; i < aArguments.Length(); ++i) {
|
||||
mArguments.AppendElement(aArguments[i]);
|
||||
if (!mArguments.AppendElement(aArguments[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -666,7 +668,9 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
arguments.AppendElement(value);
|
||||
if (!arguments.AppendElement(value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mConsole->ProfileMethod(aCx, mAction, arguments);
|
||||
@ -826,8 +830,8 @@ Console::Time(JSContext* aCx, const JS::Handle<JS::Value> aTime)
|
||||
Sequence<JS::Value> data;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &data);
|
||||
|
||||
if (!aTime.isUndefined()) {
|
||||
data.AppendElement(aTime);
|
||||
if (!aTime.isUndefined() && !data.AppendElement(aTime)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method(aCx, MethodTime, NS_LITERAL_STRING("time"), data);
|
||||
@ -839,8 +843,8 @@ Console::TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime)
|
||||
Sequence<JS::Value> data;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &data);
|
||||
|
||||
if (!aTime.isUndefined()) {
|
||||
data.AppendElement(aTime);
|
||||
if (!aTime.isUndefined() && !data.AppendElement(aTime)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method(aCx, MethodTimeEnd, NS_LITERAL_STRING("timeEnd"), data);
|
||||
@ -852,8 +856,8 @@ Console::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
|
||||
Sequence<JS::Value> data;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &data);
|
||||
|
||||
if (aData.isString()) {
|
||||
data.AppendElement(aData);
|
||||
if (aData.isString() && !data.AppendElement(aData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
|
||||
@ -892,7 +896,9 @@ Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
|
||||
Sequence<JS::Value>& sequence = event.mArguments.Value();
|
||||
|
||||
for (uint32_t i = 0; i < aData.Length(); ++i) {
|
||||
sequence.AppendElement(aData[i]);
|
||||
if (!sequence.AppendElement(aData[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> eventValue(aCx);
|
||||
@ -1293,13 +1299,18 @@ Console::ProcessCallData(ConsoleCallData* aData)
|
||||
case MethodAssert:
|
||||
event.mArguments.Construct();
|
||||
event.mStyles.Construct();
|
||||
ProcessArguments(cx, aData->mArguments, event.mArguments.Value(),
|
||||
event.mStyles.Value());
|
||||
if (!ProcessArguments(cx, aData->mArguments, event.mArguments.Value(),
|
||||
event.mStyles.Value())) {
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
event.mArguments.Construct();
|
||||
ArgumentsToValueList(aData->mArguments, event.mArguments.Value());
|
||||
if (!ArgumentsToValueList(aData->mArguments, event.mArguments.Value())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (aData->mMethodName == MethodGroup ||
|
||||
@ -1418,48 +1429,52 @@ Console::ProcessCallData(ConsoleCallData* aData)
|
||||
namespace {
|
||||
|
||||
// Helper method for ProcessArguments. Flushes output, if non-empty, to aSequence.
|
||||
void
|
||||
FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &output)
|
||||
bool
|
||||
FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &aOutput)
|
||||
{
|
||||
if (!output.IsEmpty()) {
|
||||
if (!aOutput.IsEmpty()) {
|
||||
JS::Rooted<JSString*> str(aCx, JS_NewUCStringCopyN(aCx,
|
||||
output.get(),
|
||||
output.Length()));
|
||||
aOutput.get(),
|
||||
aOutput.Length()));
|
||||
if (!str) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
aSequence.AppendElement(JS::StringValue(str));
|
||||
output.Truncate();
|
||||
if (!aSequence.AppendElement(JS::StringValue(str))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutput.Truncate();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
bool
|
||||
Console::ProcessArguments(JSContext* aCx,
|
||||
const nsTArray<JS::Heap<JS::Value>>& aData,
|
||||
Sequence<JS::Value>& aSequence,
|
||||
Sequence<JS::Value>& aStyles)
|
||||
{
|
||||
if (aData.IsEmpty()) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aData.Length() == 1 || !aData[0].isString()) {
|
||||
ArgumentsToValueList(aData, aSequence);
|
||||
return;
|
||||
return ArgumentsToValueList(aData, aSequence);
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> format(aCx, aData[0]);
|
||||
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, format));
|
||||
if (!jsString) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoJSString string;
|
||||
if (!string.init(aCx, jsString)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsString::const_iterator start, end;
|
||||
@ -1547,35 +1562,47 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
case 'o':
|
||||
case 'O':
|
||||
{
|
||||
FlushOutput(aCx, aSequence, output);
|
||||
if (!FlushOutput(aCx, aSequence, output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
if (index < aData.Length()) {
|
||||
v = aData[index++];
|
||||
}
|
||||
|
||||
aSequence.AppendElement(v);
|
||||
if (!aSequence.AppendElement(v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c':
|
||||
{
|
||||
FlushOutput(aCx, aSequence, output);
|
||||
if (!FlushOutput(aCx, aSequence, output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index < aData.Length()) {
|
||||
JS::Rooted<JS::Value> v(aCx, aData[index++]);
|
||||
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, v));
|
||||
if (!jsString) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t diff = aSequence.Length() - aStyles.Length();
|
||||
if (diff > 0) {
|
||||
for (int32_t i = 0; i < diff; i++) {
|
||||
aStyles.AppendElement(JS::NullValue());
|
||||
if (!aStyles.AppendElement(JS::NullValue())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
aStyles.AppendElement(JS::StringValue(jsString));
|
||||
|
||||
if (!aStyles.AppendElement(JS::StringValue(jsString))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1585,12 +1612,12 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
JS::Rooted<JS::Value> value(aCx, aData[index++]);
|
||||
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
|
||||
if (!jsString) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoJSString v;
|
||||
if (!v.init(aCx, jsString)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
output.Append(v);
|
||||
@ -1604,7 +1631,7 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
|
||||
int32_t v;
|
||||
if (!JS::ToInt32(aCx, value, &v)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCString format;
|
||||
@ -1619,7 +1646,7 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
|
||||
double v;
|
||||
if (!JS::ToNumber(aCx, value, &v)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCString format;
|
||||
@ -1634,7 +1661,9 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
FlushOutput(aCx, aSequence, output);
|
||||
if (!FlushOutput(aCx, aSequence, output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Discard trailing style element if there is no output to apply it to.
|
||||
if (aStyles.Length() > aSequence.Length()) {
|
||||
@ -1643,8 +1672,12 @@ Console::ProcessArguments(JSContext* aCx,
|
||||
|
||||
// The rest of the array, if unused by the format string.
|
||||
for (; index < aData.Length(); ++index) {
|
||||
aSequence.AppendElement(aData[index]);
|
||||
if (!aSequence.AppendElement(aData[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1770,13 +1803,17 @@ Console::StopTimer(JSContext* aCx, const JS::Value& aName,
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
Console::ArgumentsToValueList(const nsTArray<JS::Heap<JS::Value>>& aData,
|
||||
Sequence<JS::Value>& aSequence)
|
||||
{
|
||||
for (uint32_t i = 0; i < aData.Length(); ++i) {
|
||||
aSequence.AppendElement(aData[i]);
|
||||
if (!aSequence.AppendElement(aData[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
|
@ -158,7 +158,7 @@ private:
|
||||
// finds based the format string. The index of the styles matches the indexes
|
||||
// of elements that need the custom styling from aSequence. For elements with
|
||||
// no custom styling the array is padded with null elements.
|
||||
void
|
||||
bool
|
||||
ProcessArguments(JSContext* aCx, const nsTArray<JS::Heap<JS::Value>>& aData,
|
||||
Sequence<JS::Value>& aSequence,
|
||||
Sequence<JS::Value>& aStyles);
|
||||
@ -182,7 +182,7 @@ private:
|
||||
DOMHighResTimeStamp aTimestamp);
|
||||
|
||||
// The method populates a Sequence from an array of JS::Value.
|
||||
void
|
||||
bool
|
||||
ArgumentsToValueList(const nsTArray<JS::Heap<JS::Value>>& aData,
|
||||
Sequence<JS::Value>& aSequence);
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceEntry, mPerformance)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceEntry, mParent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceEntry)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceEntry)
|
||||
@ -20,14 +20,15 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceEntry)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
PerformanceEntry::PerformanceEntry(nsPerformance* aPerformance,
|
||||
PerformanceEntry::PerformanceEntry(nsISupports* aParent,
|
||||
const nsAString& aName,
|
||||
const nsAString& aEntryType)
|
||||
: mPerformance(aPerformance),
|
||||
: mParent(aParent),
|
||||
mName(aName),
|
||||
mEntryType(aEntryType)
|
||||
{
|
||||
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
|
||||
// mParent is null in workers.
|
||||
MOZ_ASSERT(mParent || !NS_IsMainThread());
|
||||
}
|
||||
|
||||
PerformanceEntry::~PerformanceEntry()
|
||||
|
@ -7,9 +7,10 @@
|
||||
#ifndef mozilla_dom_PerformanceEntry_h___
|
||||
#define mozilla_dom_PerformanceEntry_h___
|
||||
|
||||
#include "nsPerformance.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
|
||||
class nsISupports;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -21,7 +22,7 @@ protected:
|
||||
virtual ~PerformanceEntry();
|
||||
|
||||
public:
|
||||
PerformanceEntry(nsPerformance* aPerformance,
|
||||
PerformanceEntry(nsISupports* aParent,
|
||||
const nsAString& aName,
|
||||
const nsAString& aEntryType);
|
||||
|
||||
@ -30,9 +31,9 @@ public:
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsPerformance* GetParentObject() const
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return mPerformance;
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void GetName(nsAString& aName) const
|
||||
@ -76,7 +77,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
nsRefPtr<nsPerformance> mPerformance;
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsString mName;
|
||||
nsString mEntryType;
|
||||
};
|
||||
|
@ -9,12 +9,14 @@
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
PerformanceMark::PerformanceMark(nsPerformance* aPerformance,
|
||||
const nsAString& aName)
|
||||
: PerformanceEntry(aPerformance, aName, NS_LITERAL_STRING("mark"))
|
||||
PerformanceMark::PerformanceMark(nsISupports* aParent,
|
||||
const nsAString& aName,
|
||||
DOMHighResTimeStamp aStartTime)
|
||||
: PerformanceEntry(aParent, aName, NS_LITERAL_STRING("mark"))
|
||||
, mStartTime(aStartTime)
|
||||
{
|
||||
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
|
||||
mStartTime = aPerformance->GetDOMTiming()->TimeStampToDOMHighRes(mozilla::TimeStamp::Now());
|
||||
// mParent is null in workers.
|
||||
MOZ_ASSERT(mParent || !NS_IsMainThread());
|
||||
}
|
||||
|
||||
PerformanceMark::~PerformanceMark()
|
||||
|
@ -16,8 +16,9 @@ namespace dom {
|
||||
class PerformanceMark final : public PerformanceEntry
|
||||
{
|
||||
public:
|
||||
PerformanceMark(nsPerformance* aPerformance,
|
||||
const nsAString& aName);
|
||||
PerformanceMark(nsISupports* aParent,
|
||||
const nsAString& aName,
|
||||
DOMHighResTimeStamp aStartTime);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
|
@ -9,15 +9,16 @@
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
PerformanceMeasure::PerformanceMeasure(nsPerformance* aPerformance,
|
||||
PerformanceMeasure::PerformanceMeasure(nsISupports* aParent,
|
||||
const nsAString& aName,
|
||||
DOMHighResTimeStamp aStartTime,
|
||||
DOMHighResTimeStamp aEndTime)
|
||||
: PerformanceEntry(aPerformance, aName, NS_LITERAL_STRING("measure")),
|
||||
: PerformanceEntry(aParent, aName, NS_LITERAL_STRING("measure")),
|
||||
mStartTime(aStartTime),
|
||||
mDuration(aEndTime - aStartTime)
|
||||
{
|
||||
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
|
||||
// mParent is null in workers.
|
||||
MOZ_ASSERT(mParent || !NS_IsMainThread());
|
||||
}
|
||||
|
||||
PerformanceMeasure::~PerformanceMeasure()
|
||||
|
@ -16,7 +16,7 @@ namespace dom {
|
||||
class PerformanceMeasure final : public PerformanceEntry
|
||||
{
|
||||
public:
|
||||
PerformanceMeasure(nsPerformance* aPerformance,
|
||||
PerformanceMeasure(nsISupports* aParent,
|
||||
const nsAString& aName,
|
||||
DOMHighResTimeStamp aStartTime,
|
||||
DOMHighResTimeStamp aEndTime);
|
||||
|
@ -960,7 +960,11 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
Sequence<nsString> protocols;
|
||||
protocols.AppendElement(aProtocol);
|
||||
if (!protocols.AppendElement(aProtocol)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WebSocket::Constructor(aGlobal, aUrl, protocols, aRv);
|
||||
}
|
||||
|
||||
|
@ -693,7 +693,9 @@ nsDOMMutationObserver::TakeRecords(
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMMutationObserver::GetObservingInfo(nsTArray<Nullable<MutationObservingInfo> >& aResult)
|
||||
nsDOMMutationObserver::GetObservingInfo(
|
||||
nsTArray<Nullable<MutationObservingInfo>>& aResult,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
aResult.SetCapacity(mReceivers.Count());
|
||||
for (int32_t i = 0; i < mReceivers.Count(); ++i) {
|
||||
@ -712,7 +714,10 @@ nsDOMMutationObserver::GetObservingInfo(nsTArray<Nullable<MutationObservingInfo>
|
||||
mozilla::dom::Sequence<nsString>& filtersAsStrings =
|
||||
info.mAttributeFilter.Value();
|
||||
for (int32_t j = 0; j < filters.Count(); ++j) {
|
||||
filtersAsStrings.AppendElement(nsDependentAtomString(filters[j]));
|
||||
if (!filtersAsStrings.AppendElement(nsDependentAtomString(filters[j]))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
info.mObservedNode = mr->Target();
|
||||
|
@ -493,7 +493,8 @@ public:
|
||||
|
||||
void HandleMutation();
|
||||
|
||||
void GetObservingInfo(nsTArray<Nullable<MutationObservingInfo> >& aResult);
|
||||
void GetObservingInfo(nsTArray<Nullable<MutationObservingInfo>>& aResult,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
mozilla::dom::MutationCallback* MutationCallback() { return mCallback; }
|
||||
|
||||
|
@ -57,7 +57,8 @@ nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp) const
|
||||
return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
|
||||
}
|
||||
|
||||
DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart(){
|
||||
DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart()
|
||||
{
|
||||
return TimeStampToDOM(mozilla::TimeStamp::Now());
|
||||
}
|
||||
|
||||
|
@ -2455,6 +2455,33 @@ nsDOMWindowUtils::SetAsyncScrollOffset(nsIDOMNode* aNode,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SetAsyncZoom(nsIDOMNode* aRootElement, float aValue)
|
||||
{
|
||||
nsCOMPtr<Element> element = do_QueryInterface(aRootElement);
|
||||
if (!element) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
FrameMetrics::ViewID viewId;
|
||||
if (!nsLayoutUtils::FindIDFor(element, &viewId)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
nsIWidget* widget = GetWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LayerManager* manager = widget->GetLayerManager();
|
||||
if (!manager) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
ShadowLayerForwarder* forwarder = manager->AsShadowForwarder();
|
||||
if (!forwarder || !forwarder->HasShadowManager()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
forwarder->GetShadowManager()->SendSetAsyncZoom(viewId, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
|
||||
const nsAString& aProperty,
|
||||
|
@ -23,9 +23,12 @@
|
||||
#include "mozilla/dom/PerformanceBinding.h"
|
||||
#include "mozilla/dom/PerformanceTimingBinding.h"
|
||||
#include "mozilla/dom/PerformanceNavigationBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#define PERFLOG(msg, ...) __android_log_print(ANDROID_LOG_INFO, "PerformanceTiming", msg, ##__VA_ARGS__)
|
||||
@ -35,6 +38,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::workers;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPerformanceTiming, mPerformance)
|
||||
|
||||
@ -398,40 +402,36 @@ nsPerformanceNavigation::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenP
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsPerformance)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsPerformance, DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow, mTiming,
|
||||
mNavigation, mUserEntries,
|
||||
mResourceEntries,
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsPerformance, PerformanceBase)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTiming,
|
||||
mNavigation,
|
||||
mParentPerformance)
|
||||
tmp->mMozMemory = nullptr;
|
||||
mozilla::DropJSObjects(this);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsPerformance, DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow, mTiming,
|
||||
mNavigation, mUserEntries,
|
||||
mResourceEntries,
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsPerformance, PerformanceBase)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTiming,
|
||||
mNavigation,
|
||||
mParentPerformance)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsPerformance, DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsPerformance, PerformanceBase)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMozMemory)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsPerformance, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(nsPerformance, DOMEventTargetHelper)
|
||||
NS_IMPL_ADDREF_INHERITED(nsPerformance, PerformanceBase)
|
||||
NS_IMPL_RELEASE_INHERITED(nsPerformance, PerformanceBase)
|
||||
|
||||
nsPerformance::nsPerformance(nsPIDOMWindow* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel,
|
||||
nsPerformance* aParentPerformance)
|
||||
: DOMEventTargetHelper(aWindow),
|
||||
mWindow(aWindow),
|
||||
: PerformanceBase(aWindow),
|
||||
mDOMTiming(aDOMTiming),
|
||||
mChannel(aChannel),
|
||||
mParentPerformance(aParentPerformance),
|
||||
mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
|
||||
mParentPerformance(aParentPerformance)
|
||||
{
|
||||
MOZ_ASSERT(aWindow, "Parent window object should be provided");
|
||||
}
|
||||
@ -499,7 +499,7 @@ nsPerformance::Navigation()
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformance::Now()
|
||||
nsPerformance::Now() const
|
||||
{
|
||||
return GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now());
|
||||
}
|
||||
@ -510,90 +510,6 @@ nsPerformance::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
return PerformanceBinding::Wrap(cx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& retval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
retval = mResourceEntries;
|
||||
retval.AppendElements(mUserEntries);
|
||||
retval.Sort(PerformanceEntryComparator());
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::GetEntriesByType(const nsAString& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& retval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
retval.Clear();
|
||||
if (entryType.EqualsLiteral("resource")) {
|
||||
retval = mResourceEntries;
|
||||
} else if (entryType.EqualsLiteral("mark") ||
|
||||
entryType.EqualsLiteral("measure")) {
|
||||
for (PerformanceEntry* entry : mUserEntries) {
|
||||
if (entry->GetEntryType().Equals(entryType)) {
|
||||
retval.AppendElement(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::GetEntriesByName(const nsAString& name,
|
||||
const Optional<nsAString>& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& retval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
retval.Clear();
|
||||
for (PerformanceEntry* entry : mResourceEntries) {
|
||||
if (entry->GetName().Equals(name) &&
|
||||
(!entryType.WasPassed() ||
|
||||
entry->GetEntryType().Equals(entryType.Value()))) {
|
||||
retval.AppendElement(entry);
|
||||
}
|
||||
}
|
||||
for (PerformanceEntry* entry : mUserEntries) {
|
||||
if (entry->GetName().Equals(name) &&
|
||||
(!entryType.WasPassed() ||
|
||||
entry->GetEntryType().Equals(entryType.Value()))) {
|
||||
retval.AppendElement(entry);
|
||||
}
|
||||
}
|
||||
retval.Sort(PerformanceEntryComparator());
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::ClearUserEntries(const Optional<nsAString>& aEntryName,
|
||||
const nsAString& aEntryType)
|
||||
{
|
||||
for (uint32_t i = 0; i < mUserEntries.Length();) {
|
||||
if ((!aEntryName.WasPassed() ||
|
||||
mUserEntries[i]->GetName().Equals(aEntryName.Value())) &&
|
||||
(aEntryType.IsEmpty() ||
|
||||
mUserEntries[i]->GetEntryType().Equals(aEntryType))) {
|
||||
mUserEntries.RemoveElementAt(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::ClearResourceTimings()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mResourceEntries.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::SetResourceTimingBufferSize(uint64_t maxSize)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mResourceTimingBufferSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry should be added only after the resource is loaded.
|
||||
* This method is not thread safe and can only be called on the main thread.
|
||||
@ -609,7 +525,7 @@ nsPerformance::AddEntry(nsIHttpChannel* channel,
|
||||
}
|
||||
|
||||
// Don't add the entry if the buffer is full
|
||||
if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
|
||||
if (IsResourceEntryLimitReached()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -652,174 +568,6 @@ nsPerformance::AddEntry(nsIHttpChannel* channel,
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsPerformance::PerformanceEntryComparator::Equals(
|
||||
const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const
|
||||
{
|
||||
MOZ_ASSERT(aElem1 && aElem2,
|
||||
"Trying to compare null performance entries");
|
||||
return aElem1->StartTime() == aElem2->StartTime();
|
||||
}
|
||||
|
||||
bool
|
||||
nsPerformance::PerformanceEntryComparator::LessThan(
|
||||
const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const
|
||||
{
|
||||
MOZ_ASSERT(aElem1 && aElem2,
|
||||
"Trying to compare null performance entries");
|
||||
return aElem1->StartTime() < aElem2->StartTime();
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::InsertResourceEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
MOZ_ASSERT(aEntry);
|
||||
MOZ_ASSERT(mResourceEntries.Length() < mResourceTimingBufferSize);
|
||||
if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
mResourceEntries.InsertElementSorted(aEntry,
|
||||
PerformanceEntryComparator());
|
||||
if (mResourceEntries.Length() == mResourceTimingBufferSize) {
|
||||
// call onresourcetimingbufferfull
|
||||
DispatchBufferFullEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::InsertUserEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled()) {
|
||||
nsAutoCString uri;
|
||||
nsresult rv = mWindow->GetDocumentURI()->GetHost(uri);
|
||||
if(NS_FAILED(rv)) {
|
||||
// If we have no URI, just put in "none".
|
||||
uri.AssignLiteral("none");
|
||||
}
|
||||
PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n",
|
||||
uri.get(),
|
||||
NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(),
|
||||
NS_ConvertUTF16toUTF8(aEntry->GetName()).get(),
|
||||
aEntry->StartTime(),
|
||||
aEntry->Duration(),
|
||||
static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
|
||||
}
|
||||
mUserEntries.InsertElementSorted(aEntry,
|
||||
PerformanceEntryComparator());
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::Mark(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
|
||||
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
if (IsPerformanceTimingAttribute(aName)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
nsRefPtr<PerformanceMark> performanceMark =
|
||||
new PerformanceMark(this, aName);
|
||||
InsertUserEntry(performanceMark);
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::ClearMarks(const Optional<nsAString>& aName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ClearUserEntries(aName, NS_LITERAL_STRING("mark"));
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformance::ResolveTimestampFromName(const nsAString& aName,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoTArray<nsRefPtr<PerformanceEntry>, 1> arr;
|
||||
DOMHighResTimeStamp ts;
|
||||
Optional<nsAString> typeParam;
|
||||
nsAutoString str;
|
||||
str.AssignLiteral("mark");
|
||||
typeParam = &str;
|
||||
GetEntriesByName(aName, typeParam, arr);
|
||||
if (!arr.IsEmpty()) {
|
||||
return arr.LastElement()->StartTime();
|
||||
}
|
||||
if (!IsPerformanceTimingAttribute(aName)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return 0;
|
||||
}
|
||||
ts = GetPerformanceTimingFromString(aName);
|
||||
if (!ts) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return 0;
|
||||
}
|
||||
return ConvertDOMMilliSecToHighRes(ts);
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::Measure(const nsAString& aName,
|
||||
const Optional<nsAString>& aStartMark,
|
||||
const Optional<nsAString>& aEndMark,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
|
||||
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
DOMHighResTimeStamp startTime;
|
||||
DOMHighResTimeStamp endTime;
|
||||
|
||||
if (IsPerformanceTimingAttribute(aName)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aStartMark.WasPassed()) {
|
||||
startTime = ResolveTimestampFromName(aStartMark.Value(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Navigation start is used in this case, but since DOMHighResTimeStamp is
|
||||
// in relation to navigation start, this will be zero if a name is not
|
||||
// passed.
|
||||
startTime = 0;
|
||||
}
|
||||
if (aEndMark.WasPassed()) {
|
||||
endTime = ResolveTimestampFromName(aEndMark.Value(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
endTime = Now();
|
||||
}
|
||||
nsRefPtr<PerformanceMeasure> performanceMeasure =
|
||||
new PerformanceMeasure(this, aName, startTime, endTime);
|
||||
InsertUserEntry(performanceMeasure);
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::ClearMeasures(const Optional<nsAString>& aName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ClearUserEntries(aName, NS_LITERAL_STRING("measure"));
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformance::ConvertDOMMilliSecToHighRes(DOMTimeMilliSec aTime) {
|
||||
// If the time we're trying to convert is equal to zero, it hasn't been set
|
||||
// yet so just return 0.
|
||||
if (aTime == 0) {
|
||||
return 0;
|
||||
}
|
||||
return aTime - GetDOMTiming()->GetNavigationStart();
|
||||
}
|
||||
|
||||
// To be removed once bug 1124165 lands
|
||||
bool
|
||||
nsPerformance::IsPerformanceTimingAttribute(const nsAString& aName)
|
||||
@ -841,7 +589,7 @@ nsPerformance::IsPerformanceTimingAttribute(const nsAString& aName)
|
||||
return false;
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
DOMHighResTimeStamp
|
||||
nsPerformance::GetPerformanceTimingFromString(const nsAString& aProperty)
|
||||
{
|
||||
if (!IsPerformanceTimingAttribute(aProperty)) {
|
||||
@ -913,3 +661,346 @@ nsPerformance::GetPerformanceTimingFromString(const nsAString& aProperty)
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper classes
|
||||
class MOZ_STACK_CLASS PerformanceEntryComparator final
|
||||
{
|
||||
public:
|
||||
bool Equals(const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const
|
||||
{
|
||||
MOZ_ASSERT(aElem1 && aElem2,
|
||||
"Trying to compare null performance entries");
|
||||
return aElem1->StartTime() == aElem2->StartTime();
|
||||
}
|
||||
|
||||
bool LessThan(const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const
|
||||
{
|
||||
MOZ_ASSERT(aElem1 && aElem2,
|
||||
"Trying to compare null performance entries");
|
||||
return aElem1->StartTime() < aElem2->StartTime();
|
||||
}
|
||||
};
|
||||
|
||||
class PrefEnabledRunnable final : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
explicit PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate)
|
||||
, mEnabled(false)
|
||||
{ }
|
||||
|
||||
bool MainThreadRun() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mEnabled = Preferences::GetBool("dom.enable_user_timing", false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsEnabled() const
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mEnabled;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */ bool
|
||||
nsPerformance::IsEnabled(JSContext* aCx, JSObject* aGlobal)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
return Preferences::GetBool("dom.enable_user_timing", false);
|
||||
}
|
||||
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<PrefEnabledRunnable> runnable =
|
||||
new PrefEnabledRunnable(workerPrivate);
|
||||
runnable->Dispatch(workerPrivate->GetJSContext());
|
||||
|
||||
return runnable->IsEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::InsertUserEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled()) {
|
||||
nsAutoCString uri;
|
||||
nsresult rv = GetOwner()->GetDocumentURI()->GetHost(uri);
|
||||
if(NS_FAILED(rv)) {
|
||||
// If we have no URI, just put in "none".
|
||||
uri.AssignLiteral("none");
|
||||
}
|
||||
PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n",
|
||||
uri.get(),
|
||||
NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(),
|
||||
NS_ConvertUTF16toUTF8(aEntry->GetName()).get(),
|
||||
aEntry->StartTime(),
|
||||
aEntry->Duration(),
|
||||
static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
|
||||
}
|
||||
|
||||
PerformanceBase::InsertUserEntry(aEntry);
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformance::DeltaFromNavigationStart(DOMHighResTimeStamp aTime)
|
||||
{
|
||||
// If the time we're trying to convert is equal to zero, it hasn't been set
|
||||
// yet so just return 0.
|
||||
if (aTime == 0) {
|
||||
return 0;
|
||||
}
|
||||
return aTime - GetDOMTiming()->GetNavigationStart();
|
||||
}
|
||||
|
||||
// PerformanceBase
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PerformanceBase)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceBase,
|
||||
DOMEventTargetHelper,
|
||||
mUserEntries,
|
||||
mResourceEntries);
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(PerformanceBase, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(PerformanceBase, DOMEventTargetHelper)
|
||||
|
||||
PerformanceBase::PerformanceBase()
|
||||
: mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
}
|
||||
|
||||
PerformanceBase::PerformanceBase(nsPIDOMWindow* aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
, mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
PerformanceBase::~PerformanceBase()
|
||||
{}
|
||||
|
||||
void
|
||||
PerformanceBase::GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
|
||||
{
|
||||
aRetval = mResourceEntries;
|
||||
aRetval.AppendElements(mUserEntries);
|
||||
aRetval.Sort(PerformanceEntryComparator());
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::GetEntriesByType(const nsAString& aEntryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
|
||||
{
|
||||
if (aEntryType.EqualsLiteral("resource")) {
|
||||
aRetval = mResourceEntries;
|
||||
return;
|
||||
}
|
||||
|
||||
aRetval.Clear();
|
||||
|
||||
if (aEntryType.EqualsLiteral("mark") ||
|
||||
aEntryType.EqualsLiteral("measure")) {
|
||||
for (PerformanceEntry* entry : mUserEntries) {
|
||||
if (entry->GetEntryType().Equals(aEntryType)) {
|
||||
aRetval.AppendElement(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::GetEntriesByName(const nsAString& aName,
|
||||
const Optional<nsAString>& aEntryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
|
||||
{
|
||||
aRetval.Clear();
|
||||
|
||||
for (PerformanceEntry* entry : mResourceEntries) {
|
||||
if (entry->GetName().Equals(aName) &&
|
||||
(!aEntryType.WasPassed() ||
|
||||
entry->GetEntryType().Equals(aEntryType.Value()))) {
|
||||
aRetval.AppendElement(entry);
|
||||
}
|
||||
}
|
||||
|
||||
for (PerformanceEntry* entry : mUserEntries) {
|
||||
if (entry->GetName().Equals(aName) &&
|
||||
(!aEntryType.WasPassed() ||
|
||||
entry->GetEntryType().Equals(aEntryType.Value()))) {
|
||||
aRetval.AppendElement(entry);
|
||||
}
|
||||
}
|
||||
|
||||
aRetval.Sort(PerformanceEntryComparator());
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::ClearUserEntries(const Optional<nsAString>& aEntryName,
|
||||
const nsAString& aEntryType)
|
||||
{
|
||||
for (uint32_t i = 0; i < mUserEntries.Length();) {
|
||||
if ((!aEntryName.WasPassed() ||
|
||||
mUserEntries[i]->GetName().Equals(aEntryName.Value())) &&
|
||||
(aEntryType.IsEmpty() ||
|
||||
mUserEntries[i]->GetEntryType().Equals(aEntryType))) {
|
||||
mUserEntries.RemoveElementAt(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::ClearResourceTimings()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mResourceEntries.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::Mark(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
// Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
|
||||
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsPerformanceTimingAttribute(aName)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<PerformanceMark> performanceMark =
|
||||
new PerformanceMark(GetAsISupports(), aName, Now());
|
||||
InsertUserEntry(performanceMark);
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::ClearMarks(const Optional<nsAString>& aName)
|
||||
{
|
||||
ClearUserEntries(aName, NS_LITERAL_STRING("mark"));
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
PerformanceBase::ResolveTimestampFromName(const nsAString& aName,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoTArray<nsRefPtr<PerformanceEntry>, 1> arr;
|
||||
DOMHighResTimeStamp ts;
|
||||
Optional<nsAString> typeParam;
|
||||
nsAutoString str;
|
||||
str.AssignLiteral("mark");
|
||||
typeParam = &str;
|
||||
GetEntriesByName(aName, typeParam, arr);
|
||||
if (!arr.IsEmpty()) {
|
||||
return arr.LastElement()->StartTime();
|
||||
}
|
||||
|
||||
if (!IsPerformanceTimingAttribute(aName)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ts = GetPerformanceTimingFromString(aName);
|
||||
if (!ts) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DeltaFromNavigationStart(ts);
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::Measure(const nsAString& aName,
|
||||
const Optional<nsAString>& aStartMark,
|
||||
const Optional<nsAString>& aEndMark,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Don't add the entry if the buffer is full. XXX should be removed by bug
|
||||
// 1159003.
|
||||
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp startTime;
|
||||
DOMHighResTimeStamp endTime;
|
||||
|
||||
if (IsPerformanceTimingAttribute(aName)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aStartMark.WasPassed()) {
|
||||
startTime = ResolveTimestampFromName(aStartMark.Value(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Navigation start is used in this case, but since DOMHighResTimeStamp is
|
||||
// in relation to navigation start, this will be zero if a name is not
|
||||
// passed.
|
||||
startTime = 0;
|
||||
}
|
||||
|
||||
if (aEndMark.WasPassed()) {
|
||||
endTime = ResolveTimestampFromName(aEndMark.Value(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
endTime = Now();
|
||||
}
|
||||
|
||||
nsRefPtr<PerformanceMeasure> performanceMeasure =
|
||||
new PerformanceMeasure(GetAsISupports(), aName, startTime, endTime);
|
||||
InsertUserEntry(performanceMeasure);
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::ClearMeasures(const Optional<nsAString>& aName)
|
||||
{
|
||||
ClearUserEntries(aName, NS_LITERAL_STRING("measure"));
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::InsertUserEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
mUserEntries.InsertElementSorted(aEntry,
|
||||
PerformanceEntryComparator());
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::SetResourceTimingBufferSize(uint64_t aMaxSize)
|
||||
{
|
||||
mResourceTimingBufferSize = aMaxSize;
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::InsertResourceEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
MOZ_ASSERT(aEntry);
|
||||
MOZ_ASSERT(mResourceEntries.Length() < mResourceTimingBufferSize);
|
||||
if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
mResourceEntries.InsertElementSorted(aEntry,
|
||||
PerformanceEntryComparator());
|
||||
if (mResourceEntries.Length() == mResourceTimingBufferSize) {
|
||||
// call onresourcetimingbufferfull
|
||||
DispatchBufferFullEvent();
|
||||
}
|
||||
}
|
||||
|
@ -288,18 +288,90 @@ private:
|
||||
nsRefPtr<nsPerformance> mPerformance;
|
||||
};
|
||||
|
||||
// Script "performance" object
|
||||
class nsPerformance final : public mozilla::DOMEventTargetHelper
|
||||
// Base class for main-thread and worker Performance API
|
||||
class PerformanceBase : public mozilla::DOMEventTargetHelper
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PerformanceBase,
|
||||
DOMEventTargetHelper)
|
||||
|
||||
PerformanceBase();
|
||||
explicit PerformanceBase(nsPIDOMWindow* aWindow);
|
||||
|
||||
typedef mozilla::dom::PerformanceEntry PerformanceEntry;
|
||||
|
||||
void GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
|
||||
void GetEntriesByType(const nsAString& aEntryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
|
||||
void GetEntriesByName(const nsAString& aName,
|
||||
const mozilla::dom::Optional<nsAString>& aEntryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
|
||||
void ClearResourceTimings();
|
||||
|
||||
virtual DOMHighResTimeStamp Now() const = 0;
|
||||
|
||||
void Mark(const nsAString& aName, mozilla::ErrorResult& aRv);
|
||||
void ClearMarks(const mozilla::dom::Optional<nsAString>& aName);
|
||||
void Measure(const nsAString& aName,
|
||||
const mozilla::dom::Optional<nsAString>& aStartMark,
|
||||
const mozilla::dom::Optional<nsAString>& aEndMark,
|
||||
mozilla::ErrorResult& aRv);
|
||||
void ClearMeasures(const mozilla::dom::Optional<nsAString>& aName);
|
||||
|
||||
void SetResourceTimingBufferSize(uint64_t aMaxSize);
|
||||
|
||||
protected:
|
||||
virtual ~PerformanceBase();
|
||||
|
||||
virtual void InsertUserEntry(PerformanceEntry* aEntry);
|
||||
void InsertResourceEntry(PerformanceEntry* aEntry);
|
||||
|
||||
void ClearUserEntries(const mozilla::dom::Optional<nsAString>& aEntryName,
|
||||
const nsAString& aEntryType);
|
||||
|
||||
DOMHighResTimeStamp ResolveTimestampFromName(const nsAString& aName,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
virtual nsISupports* GetAsISupports() = 0;
|
||||
|
||||
virtual void DispatchBufferFullEvent() = 0;
|
||||
|
||||
virtual DOMHighResTimeStamp
|
||||
DeltaFromNavigationStart(DOMHighResTimeStamp aTime) = 0;
|
||||
|
||||
virtual bool IsPerformanceTimingAttribute(const nsAString& aName) = 0;
|
||||
|
||||
virtual DOMHighResTimeStamp
|
||||
GetPerformanceTimingFromString(const nsAString& aTimingName) = 0;
|
||||
|
||||
bool IsResourceEntryLimitReached() const
|
||||
{
|
||||
return mResourceEntries.Length() >= mResourceTimingBufferSize;
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<nsRefPtr<PerformanceEntry>> mUserEntries;
|
||||
nsTArray<nsRefPtr<PerformanceEntry>> mResourceEntries;
|
||||
|
||||
uint64_t mResourceTimingBufferSize;
|
||||
static const uint64_t kDefaultResourceTimingBufferSize = 150;
|
||||
};
|
||||
|
||||
// Script "performance" object
|
||||
class nsPerformance final : public PerformanceBase
|
||||
{
|
||||
public:
|
||||
nsPerformance(nsPIDOMWindow* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel,
|
||||
nsPerformance* aParentPerformance);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsPerformance, DOMEventTargetHelper)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsPerformance,
|
||||
PerformanceBase)
|
||||
|
||||
static bool IsEnabled(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
nsDOMNavigationTiming* GetDOMTiming() const
|
||||
{
|
||||
@ -316,35 +388,28 @@ public:
|
||||
return mParentPerformance;
|
||||
}
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return mWindow.get();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
JSObject* WrapObject(JSContext *cx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// Performance WebIDL methods
|
||||
DOMHighResTimeStamp Now();
|
||||
DOMHighResTimeStamp Now() const override;
|
||||
|
||||
nsPerformanceTiming* Timing();
|
||||
nsPerformanceNavigation* Navigation();
|
||||
|
||||
void GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& retval);
|
||||
void GetEntriesByType(const nsAString& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& retval);
|
||||
void GetEntriesByName(const nsAString& name,
|
||||
const mozilla::dom::Optional< nsAString >& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry>>& retval);
|
||||
void AddEntry(nsIHttpChannel* channel,
|
||||
nsITimedChannel* timedChannel);
|
||||
void ClearResourceTimings();
|
||||
void SetResourceTimingBufferSize(uint64_t maxSize);
|
||||
void Mark(const nsAString& aName, mozilla::ErrorResult& aRv);
|
||||
void ClearMarks(const mozilla::dom::Optional<nsAString>& aName);
|
||||
void Measure(const nsAString& aName,
|
||||
const mozilla::dom::Optional<nsAString>& aStartMark,
|
||||
const mozilla::dom::Optional<nsAString>& aEndMark,
|
||||
mozilla::ErrorResult& aRv);
|
||||
void ClearMeasures(const mozilla::dom::Optional<nsAString>& aName);
|
||||
|
||||
using PerformanceBase::GetEntries;
|
||||
using PerformanceBase::GetEntriesByType;
|
||||
using PerformanceBase::GetEntriesByName;
|
||||
using PerformanceBase::ClearResourceTimings;
|
||||
|
||||
using PerformanceBase::Mark;
|
||||
using PerformanceBase::ClearMarks;
|
||||
using PerformanceBase::Measure;
|
||||
using PerformanceBase::ClearMeasures;
|
||||
using PerformanceBase::SetResourceTimingBufferSize;
|
||||
|
||||
void GetMozMemory(JSContext *aCx, JS::MutableHandle<JSObject*> aObj);
|
||||
|
||||
@ -352,36 +417,30 @@ public:
|
||||
|
||||
private:
|
||||
~nsPerformance();
|
||||
bool IsPerformanceTimingAttribute(const nsAString& aName);
|
||||
DOMHighResTimeStamp ResolveTimestampFromName(const nsAString& aName, mozilla::ErrorResult& aRv);
|
||||
DOMTimeMilliSec GetPerformanceTimingFromString(const nsAString& aTimingName);
|
||||
DOMHighResTimeStamp ConvertDOMMilliSecToHighRes(const DOMTimeMilliSec aTime);
|
||||
void DispatchBufferFullEvent();
|
||||
|
||||
nsISupports* GetAsISupports() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void InsertUserEntry(PerformanceEntry* aEntry);
|
||||
void ClearUserEntries(const mozilla::dom::Optional<nsAString>& aEntryName,
|
||||
const nsAString& aEntryType);
|
||||
void InsertResourceEntry(PerformanceEntry* aEntry);
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
bool IsPerformanceTimingAttribute(const nsAString& aName) override;
|
||||
|
||||
DOMHighResTimeStamp
|
||||
DeltaFromNavigationStart(DOMHighResTimeStamp aTime) override;
|
||||
|
||||
DOMHighResTimeStamp
|
||||
GetPerformanceTimingFromString(const nsAString& aTimingName) override;
|
||||
|
||||
void DispatchBufferFullEvent() override;
|
||||
|
||||
nsRefPtr<nsDOMNavigationTiming> mDOMTiming;
|
||||
nsCOMPtr<nsITimedChannel> mChannel;
|
||||
nsRefPtr<nsPerformanceTiming> mTiming;
|
||||
nsRefPtr<nsPerformanceNavigation> mNavigation;
|
||||
nsTArray<nsRefPtr<PerformanceEntry>> mResourceEntries;
|
||||
nsTArray<nsRefPtr<PerformanceEntry>> mUserEntries;
|
||||
nsRefPtr<nsPerformance> mParentPerformance;
|
||||
uint64_t mResourceTimingBufferSize;
|
||||
JS::Heap<JSObject*> mMozMemory;
|
||||
|
||||
static const uint64_t kDefaultResourceTimingBufferSize = 150;
|
||||
|
||||
// Helper classes
|
||||
class PerformanceEntryComparator {
|
||||
public:
|
||||
bool Equals(const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const;
|
||||
bool LessThan(const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const;
|
||||
};
|
||||
};
|
||||
|
||||
inline nsDOMNavigationTiming*
|
||||
|
@ -119,20 +119,29 @@ NS_IMPL_ISUPPORTS(
|
||||
nsISupportsWeakReference,
|
||||
nsIMemoryReporter)
|
||||
|
||||
static const PLDHashTableOps hash_table_ops =
|
||||
{
|
||||
GlobalNameHashHashKey,
|
||||
GlobalNameHashMatchEntry,
|
||||
PL_DHashMoveEntryStub,
|
||||
GlobalNameHashClearEntry,
|
||||
GlobalNameHashInitEntry
|
||||
};
|
||||
|
||||
#define GLOBALNAME_HASHTABLE_INITIAL_LENGTH 512
|
||||
|
||||
nsScriptNameSpaceManager::nsScriptNameSpaceManager()
|
||||
: mIsInitialized(false)
|
||||
: mGlobalNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH)
|
||||
, mNavigatorNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
|
||||
}
|
||||
|
||||
nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
|
||||
{
|
||||
if (mIsInitialized) {
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
// Destroy the hash
|
||||
PL_DHashTableFinish(&mGlobalNames);
|
||||
PL_DHashTableFinish(&mNavigatorNames);
|
||||
}
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
|
||||
}
|
||||
|
||||
@ -309,30 +318,9 @@ nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define GLOBALNAME_HASHTABLE_INITIAL_LENGTH 512
|
||||
|
||||
nsresult
|
||||
nsScriptNameSpaceManager::Init()
|
||||
{
|
||||
static const PLDHashTableOps hash_table_ops =
|
||||
{
|
||||
GlobalNameHashHashKey,
|
||||
GlobalNameHashMatchEntry,
|
||||
PL_DHashMoveEntryStub,
|
||||
GlobalNameHashClearEntry,
|
||||
GlobalNameHashInitEntry
|
||||
};
|
||||
|
||||
PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
|
||||
sizeof(GlobalNameMapEntry),
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
|
||||
|
||||
PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
|
||||
sizeof(GlobalNameMapEntry),
|
||||
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
|
||||
|
||||
mIsInitialized = true;
|
||||
|
||||
RegisterWeakMemoryReporter(this);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -234,10 +234,8 @@ private:
|
||||
nsGlobalNameStruct* LookupNameInternal(const nsAString& aName,
|
||||
const char16_t **aClassName = nullptr);
|
||||
|
||||
PLDHashTable mGlobalNames;
|
||||
PLDHashTable mNavigatorNames;
|
||||
|
||||
bool mIsInitialized;
|
||||
PLDHashTable2 mGlobalNames;
|
||||
PLDHashTable2 mNavigatorNames;
|
||||
};
|
||||
|
||||
#endif /* nsScriptNameSpaceManager_h__ */
|
||||
|
@ -80,6 +80,7 @@ function createTest(schemeFrom, schemeTo, policy) {
|
||||
<iframe src="' + _create2ndLevelIframeUrl('form') + '"></iframe>\n\
|
||||
<iframe src="' + _create2ndLevelIframeUrl('window.location') + '"></iframe>\n\
|
||||
<script>\n\
|
||||
var _testFinished = 0\n\
|
||||
(function() {\n\
|
||||
var x = new XMLHttpRequest();\n\
|
||||
x.open("GET", "' + _createTestUrl('xmlhttprequest') + '");\n\
|
||||
@ -113,8 +114,10 @@ function createTest(schemeFrom, schemeTo, policy) {
|
||||
// called by the two things that must complete: window.open page
|
||||
// and the window load event. When both are complete, this
|
||||
// "finishes" the iframe subtest by clicking the link.
|
||||
// _testFinished avoids calling this function twice (which may happen)
|
||||
'function checkForFinish() {\n\
|
||||
if (window._isLoaded && window._openedWindowLoaded) {\n\
|
||||
if (window._isLoaded && window._openedWindowLoaded && !window._testFinished) {\n\
|
||||
window._testFinished = 1;\n\
|
||||
document.getElementById("link").click();\n\
|
||||
}\n\
|
||||
}\n\
|
||||
|
@ -243,6 +243,7 @@ support-files =
|
||||
wholeTexty-helper.xml
|
||||
file_nonascii_blob_url.html
|
||||
referrerHelper.js
|
||||
test_performance_user_timing.js
|
||||
|
||||
[test_anonymousContent_api.html]
|
||||
[test_anonymousContent_append_after_reflow.html]
|
||||
@ -611,8 +612,16 @@ skip-if = buildapp == 'b2g'
|
||||
[test_bug698381.html]
|
||||
[test_bug698384.html]
|
||||
[test_bug704063.html]
|
||||
[test_bug704320.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g (Needs multiple window.open support) android(times out, bug 1100609) e10s(randomly fails, bug 1100362)
|
||||
[test_bug704320_http_http.html]
|
||||
support-files = referrerHelper.js
|
||||
[test_bug704320_http_https.html]
|
||||
support-files = referrerHelper.js
|
||||
[test_bug704320_https_http.html]
|
||||
support-files = referrerHelper.js
|
||||
skip-if = buildapp == 'b2g' # b2g (https://example.com not working bug 1162353)
|
||||
[test_bug704320_https_https.html]
|
||||
support-files = referrerHelper.js
|
||||
skip-if = buildapp == 'b2g' # b2g (https://example.com not working bug 1162353)
|
||||
[test_bug704320_policyset.html]
|
||||
support-files = referrerHelper.js
|
||||
[test_bug704320_preload.html]
|
||||
|
@ -19,7 +19,6 @@ window.addEventListener("message", function(event) {
|
||||
|
||||
/**
|
||||
* helper to perform an XHR.
|
||||
* Used by resetCounter() and checkResults().
|
||||
*/
|
||||
function doXHR(url, onSuccess, onFail) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
@ -51,7 +50,7 @@ function resetCounter() {
|
||||
/**
|
||||
* Grabs the results via XHR and passes to checker.
|
||||
*/
|
||||
function checkResults(testname, expected) {
|
||||
function checkIndividualResults(testname, expected) {
|
||||
doXHR('/tests/dom/base/test/bug704320_counter.sjs?results',
|
||||
function(xhr) {
|
||||
var results = JSON.parse(xhr.responseText);
|
||||
@ -74,3 +73,163 @@ function checkResults(testname, expected) {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs the results via XHR and checks them
|
||||
*/
|
||||
function checkExpectedGlobalResults() {
|
||||
var url = 'bug704320.sjs?action=get-test-results';
|
||||
doXHR(url,
|
||||
function(xhr) {
|
||||
var response = JSON.parse(xhr.response);
|
||||
|
||||
for (type in response) {
|
||||
for (scheme in response[type]) {
|
||||
for (policy in response[type][scheme]) {
|
||||
var expectedResult = EXPECTED_RESULTS[type] === undefined ?
|
||||
EXPECTED_RESULTS['default'][scheme][policy] :
|
||||
EXPECTED_RESULTS[type][scheme][policy];
|
||||
is(response[type][scheme][policy], expectedResult, type + ' ' + scheme + ' ' + policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
advance();
|
||||
},
|
||||
function(xhr) {
|
||||
ok(false, "Can't get results from the counter server.");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var EXPECTED_RESULTS = {
|
||||
// From docshell/base/nsDocShell.cpp:
|
||||
// "If the document containing the hyperlink being audited was not retrieved
|
||||
// over an encrypted connection and its address does not have the same
|
||||
// origin as "ping URL", send a referrer."
|
||||
'link-ping': {
|
||||
// Same-origin
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': '',
|
||||
'origin': '',
|
||||
'origin-when-cross-origin': '',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade'
|
||||
},
|
||||
// Encrypted and not same-origin
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': '',
|
||||
'origin': '',
|
||||
'origin-when-cross-origin': '',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
// Encrypted
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': '',
|
||||
'origin': '',
|
||||
'origin-when-cross-origin': '',
|
||||
'no-referrer-when-downgrade': ''
|
||||
}
|
||||
},
|
||||
// form is tested in a 2nd level iframe.
|
||||
'form': {
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url&type=form',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin&type=form',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade&type=form'
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url&type=form',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade&type=form'
|
||||
},
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url&type=form',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url&type=form',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin&type=form',
|
||||
'no-referrer-when-downgrade': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade&type=form'
|
||||
}
|
||||
},
|
||||
// window.location is tested in a 2nd level iframe.
|
||||
'window.location': {
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url&type=window.location',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin&type=window.location',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade&type=window.location'
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url&type=window.location',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade&type=window.location'
|
||||
},
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url&type=window.location',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url&type=window.location',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin&type=window.location',
|
||||
'no-referrer-when-downgrade': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade&type=window.location'
|
||||
}
|
||||
},
|
||||
'default': {
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade'
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade'
|
||||
},
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin',
|
||||
'no-referrer-when-downgrade': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -27,7 +27,7 @@ var tests = (function() {
|
||||
// origin when crossorigin (trimming whitespace)
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape(' origin-when-crossorigin');
|
||||
yield checkResults("origin-when-cross-origin", ["origin", "full"]);
|
||||
yield checkIndividualResults("origin-when-cross-origin", ["origin", "full"]);
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
|
@ -1,252 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTP to HTTP
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin',
|
||||
// HTTP to HTTPS
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin-when-cross-origin',
|
||||
// HTTPS to HTTP
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=no-referrer-when-downgrade',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=no-referrer',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=origin',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=origin-when-cross-origin',
|
||||
// HTTPS to HTTPS
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin'
|
||||
];
|
||||
|
||||
var expectedResults = {
|
||||
// From docshell/base/nsDocShell.cpp:
|
||||
// "If the document containing the hyperlink being audited was not retrieved
|
||||
// over an encrypted connection and its address does not have the same
|
||||
// origin as "ping URL", send a referrer."
|
||||
'link-ping': {
|
||||
// Same-origin
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': '',
|
||||
'origin': '',
|
||||
'origin-when-cross-origin': '',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade'
|
||||
},
|
||||
// Encrypted and not same-origin
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': '',
|
||||
'origin': '',
|
||||
'origin-when-cross-origin': '',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
// Encrypted
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': '',
|
||||
'origin': '',
|
||||
'origin-when-cross-origin': '',
|
||||
'no-referrer-when-downgrade': ''
|
||||
}
|
||||
},
|
||||
// form is tested in a 2nd level iframe.
|
||||
'form': {
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url&type=form',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin&type=form',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade&type=form'
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url&type=form',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade&type=form'
|
||||
},
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url&type=form',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url&type=form',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin&type=form',
|
||||
'no-referrer-when-downgrade': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade&type=form'
|
||||
}
|
||||
},
|
||||
// window.location is tested in a 2nd level iframe.
|
||||
'window.location': {
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url&type=window.location',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin&type=window.location',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade&type=window.location'
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url&type=window.location',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade&type=window.location'
|
||||
},
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url&type=window.location',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url&type=window.location',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin&type=window.location',
|
||||
'no-referrer-when-downgrade': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade&type=window.location'
|
||||
}
|
||||
},
|
||||
'default': {
|
||||
'http-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade'
|
||||
},
|
||||
'http-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url',
|
||||
'origin': 'http://example.com',
|
||||
'origin-when-cross-origin': 'http://example.com',
|
||||
'no-referrer-when-downgrade': 'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade'
|
||||
},
|
||||
'https-to-http': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com',
|
||||
'no-referrer-when-downgrade': ''
|
||||
},
|
||||
'https-to-https': {
|
||||
'no-referrer': '',
|
||||
'unsafe-url': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url',
|
||||
'origin': 'https://example.com',
|
||||
'origin-when-cross-origin': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin',
|
||||
'no-referrer-when-downgrade': 'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function runit() {
|
||||
var url = 'bug704320.sjs?action=get-test-results';
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('GET', url);
|
||||
xhr.onreadystatechange = function() {
|
||||
//dump("\n\n >>>>>>>>>>> XHR ReadyState change \n" + url + "\n\n\n\n");
|
||||
if (this.readyState == 4) {
|
||||
document.getElementById('content').textContent +=
|
||||
JSON.stringify(JSON.parse(this.response), null, 4);
|
||||
|
||||
//dump("\n\n >>>>>>>>>>> GOT RESPONSE: \n" + this.response + "\n\n\n\n");
|
||||
var response = JSON.parse(this.response);
|
||||
|
||||
for (type in response) {
|
||||
for (scheme in response[type]) {
|
||||
for (policy in response[type][scheme]) {
|
||||
var expectedResult = expectedResults[type] === undefined ?
|
||||
expectedResults['default'][scheme][policy] :
|
||||
expectedResults[type][scheme][policy];
|
||||
|
||||
is(response[type][scheme][policy], expectedResult,
|
||||
type + ' ' + scheme + ' ' + policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// BEGIN
|
||||
// Currently triggers assertions on e10s due to bug 820466. If you try to run
|
||||
// this on e10s, you'll get some ssl-related assertions and should add this line:
|
||||
// SimpleTest.expectAssertions(0,15);
|
||||
// But this test is disabled on e10s for unexpected failures. See bug 1100362.
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({
|
||||
'set': [['security.mixed_content.block_active_content', false],
|
||||
['security.mixed_content.block_display_content', false],
|
||||
['browser.send_pings', true],
|
||||
['browser.send_pings.max_per_link', 1],
|
||||
['browser.send_pings.require_same_host', false]]
|
||||
},
|
||||
function() {
|
||||
var testContainer = document.getElementById('test');
|
||||
|
||||
testIframeUrls.forEach(function(url) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('class', 'test');
|
||||
iframe.src = url;
|
||||
testContainer.appendChild(iframe);
|
||||
});
|
||||
|
||||
var numFrames = testIframeUrls.length;
|
||||
var numFramesReady = 0;
|
||||
|
||||
window.addEventListener('message', function(event) {
|
||||
++numFramesReady;
|
||||
if (numFramesReady >= numFrames) {
|
||||
runit();
|
||||
}
|
||||
}, false);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
62
dom/base/test/test_bug704320_http_http.html
Normal file
62
dom/base/test/test_bug704320_http_http.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTP to HTTP</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTP to HTTP
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin',
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It performs all tests in sequence using in the same iframe.
|
||||
*/
|
||||
var tests = (function() {
|
||||
var iframe = document.getElementById("testframe");
|
||||
iframe.onload = function() {
|
||||
advance();
|
||||
}
|
||||
|
||||
// load the test frame from testIframeUrls[url]
|
||||
// it will call back into this function via postMessage when it finishes loading.
|
||||
// and continue beyond the yield.
|
||||
for(url in testIframeUrls) {
|
||||
yield iframe.src = testIframeUrls[url];
|
||||
// run test and check result for loaded test URL
|
||||
yield checkExpectedGlobalResults();
|
||||
}
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP to HTTP</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
62
dom/base/test/test_bug704320_http_https.html
Normal file
62
dom/base/test/test_bug704320_http_https.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTP to HTTPS</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTP to HTTPS
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin-when-cross-origin',
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It performs all tests in sequence using in the same iframe.
|
||||
*/
|
||||
var tests = (function() {
|
||||
var iframe = document.getElementById("testframe");
|
||||
iframe.onload = function() {
|
||||
advance();
|
||||
}
|
||||
|
||||
// load the test frame from testIframeUrls[url]
|
||||
// it will call back into this function via postMessage when it finishes loading.
|
||||
// and continue beyond the yield.
|
||||
for(url in testIframeUrls) {
|
||||
yield iframe.src = testIframeUrls[url];
|
||||
// run test and check result for loaded test URL
|
||||
yield checkExpectedGlobalResults();
|
||||
}
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP to HTTPS</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
62
dom/base/test/test_bug704320_https_http.html
Normal file
62
dom/base/test/test_bug704320_https_http.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTPS to HTTP</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTPS to HTTP
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=no-referrer-when-downgrade',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=no-referrer',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=origin',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=origin-when-cross-origin',
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It performs all tests in sequence using in the same iframe.
|
||||
*/
|
||||
var tests = (function() {
|
||||
var iframe = document.getElementById("testframe");
|
||||
iframe.onload = function() {
|
||||
advance();
|
||||
}
|
||||
|
||||
// load the test frame from testIframeUrls[url]
|
||||
// it will call back into this function via postMessage when it finishes loading.
|
||||
// and continue beyond the yield.
|
||||
for(url in testIframeUrls) {
|
||||
yield iframe.src = testIframeUrls[url];
|
||||
// run test and check result for loaded test URL
|
||||
yield checkExpectedGlobalResults();
|
||||
}
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTPS to HTTP</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
62
dom/base/test/test_bug704320_https_https.html
Normal file
62
dom/base/test/test_bug704320_https_https.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTPS to HTTPS</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTPS to HTTPS
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin'
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It performs all tests in sequence using in the same iframe.
|
||||
*/
|
||||
var tests = (function() {
|
||||
var iframe = document.getElementById("testframe");
|
||||
iframe.onload = function() {
|
||||
advance();
|
||||
}
|
||||
|
||||
// load the test frame from testIframeUrls[url]
|
||||
// it will call back into this function via postMessage when it finishes loading.
|
||||
// and continue beyond the yield.
|
||||
for(url in testIframeUrls) {
|
||||
yield iframe.src = testIframeUrls[url];
|
||||
// run test and check result for loaded test URL
|
||||
yield checkExpectedGlobalResults();
|
||||
}
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTPS to HTTPS</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -37,7 +37,7 @@ var tests = (function() {
|
||||
yield iframe.src = sjs + "&policy=" + escape('default');
|
||||
|
||||
// check the first test (two images, no referrers)
|
||||
yield checkResults("default", ["full"]);
|
||||
yield checkIndividualResults("default", ["full"]);
|
||||
|
||||
// check invalid policy
|
||||
// According to the spec section 6.4, if there is a policy token
|
||||
@ -45,7 +45,7 @@ var tests = (function() {
|
||||
// should be the policy used.
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape('invalid-policy');
|
||||
yield checkResults("invalid", ["none"]);
|
||||
yield checkIndividualResults("invalid", ["none"]);
|
||||
|
||||
// whitespace checks.
|
||||
// according to the spec section 4.1, the content attribute's value
|
||||
@ -53,20 +53,20 @@ var tests = (function() {
|
||||
// trailing whitespace.
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape('default ');
|
||||
yield checkResults("trailing whitespace", ["full"]);
|
||||
yield checkIndividualResults("trailing whitespace", ["full"]);
|
||||
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape(' origin\f');
|
||||
yield checkResults("trailing form feed", ["origin"]);
|
||||
yield checkIndividualResults("trailing form feed", ["origin"]);
|
||||
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape('\f origin');
|
||||
yield checkResults("leading form feed", ["origin"]);
|
||||
yield checkIndividualResults("leading form feed", ["origin"]);
|
||||
|
||||
// origin when cross-origin (trimming whitespace)
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape(' origin-when-cross-origin');
|
||||
yield checkResults("origin-when-cross-origin", ["origin", "full"]);
|
||||
yield checkIndividualResults("origin-when-cross-origin", ["origin", "full"]);
|
||||
|
||||
// according to the spec section 4.1:
|
||||
// "If the meta element lacks a content attribute, or if that attribute’s
|
||||
@ -77,16 +77,16 @@ var tests = (function() {
|
||||
// http://www.w3.org/html/wg/drafts/html/CR/infrastructure.html#space-character
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape(' \t ');
|
||||
yield checkResults("basic whitespace only policy", ["full"]);
|
||||
yield checkIndividualResults("basic whitespace only policy", ["full"]);
|
||||
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape(' \f\r\n\t ');
|
||||
yield checkResults("whitespace only policy", ["full"]);
|
||||
yield checkIndividualResults("whitespace only policy", ["full"]);
|
||||
|
||||
// and double-check that no-referrer works.
|
||||
yield resetCounter();
|
||||
yield iframe.src = sjs + "&policy=" + escape('no-referrer');
|
||||
yield checkResults("no-referrer", ["none"]);
|
||||
yield checkIndividualResults("no-referrer", ["none"]);
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
|
@ -9,6 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
<meta charset="utf-8">
|
||||
<title>Test preloads for Bug 704320</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
@ -16,24 +17,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* Listen for notifications from the child.
|
||||
* These are sent in case of error, or when the loads we await have completed.
|
||||
*/
|
||||
window.addEventListener("message", function(event) {
|
||||
if (event.data == "childLoadComplete") {
|
||||
// all three loads happen, continue the test.
|
||||
advance();
|
||||
} else if (event.data == "childOverload") {
|
||||
// too many loads happened in a test frame, abort.
|
||||
ok(false, "Too many load handlers called in test.");
|
||||
SimpleTest.finish();
|
||||
} else if (event.data.indexOf("fail-") == 0) {
|
||||
// something else failed in the test frame, abort.
|
||||
ok(false, "Child failed the test with error " + event.data.substr(5));
|
||||
SimpleTest.finish();
|
||||
}});
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It resets the counter, then performs two tests in sequence using
|
||||
@ -138,33 +121,6 @@ function finalizePreloadReuse(results) {
|
||||
advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* helper to perform an XHR.
|
||||
* Used by resetCounter() and checkResults().
|
||||
*/
|
||||
function doXHR(url, onSuccess, onFail) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onload = function () {
|
||||
if (xhr.status == 200) {
|
||||
onSuccess(xhr);
|
||||
} else {
|
||||
onFail(xhr);
|
||||
}
|
||||
};
|
||||
xhr.open('GET', url, true);
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This triggers state-resetting on the counter server.
|
||||
*/
|
||||
function resetCounter() {
|
||||
doXHR('/tests/dom/base/test/bug704320_counter.sjs?reset',
|
||||
advance,
|
||||
function(xhr) {
|
||||
ok(false, "Need to be able to reset the request counter");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs the results via XHR and passes to checker.
|
||||
|
@ -102,27 +102,21 @@
|
||||
|
||||
addEventListener("load", function() {
|
||||
var principal = SpecialPowers.wrap(document).nodePrincipal;
|
||||
SpecialPowers.addPermission("browser", true, { url: SpecialPowers.wrap(principal.URI).spec,
|
||||
appId: principal.appId,
|
||||
isInBrowserElement: false });
|
||||
SpecialPowers.addPermission("browser", true, { url: SpecialPowers.wrap(principal.URI).spec,
|
||||
appId: principal.appId,
|
||||
isInBrowserElement: true });
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", false],
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
SimpleTest.registerCleanupFunction(function () {
|
||||
var principal = SpecialPowers.wrap(document).nodePrincipal;
|
||||
SpecialPowers.removePermission("browser", { url: SpecialPowers.wrap(principal.URI).spec,
|
||||
appId: principal.appId,
|
||||
isInBrowserElement: false });
|
||||
SpecialPowers.removePermission("browser", { url: SpecialPowers.wrap(principal.URI).spec,
|
||||
appId: principal.appId,
|
||||
isInBrowserElement: true });
|
||||
SpecialPowers.pushPermissions([
|
||||
{ "type": "browser", "allow": 1, "context": { "url": principal.URI.spec,
|
||||
"appId": principal.appId,
|
||||
"isInBrowserElement": false }},
|
||||
{ "type": "browser", "allow": 1, "context": { "url": principal.URI.spec,
|
||||
"appId": principal.appId,
|
||||
"isInBrowserElement": true }}
|
||||
], () => {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", false],
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<title>Test for Bug 782751</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="test_performance_user_timing.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=782751">Mozilla Bug 782751 - User Timing API</a>
|
||||
@ -15,271 +16,6 @@
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var index = 0;
|
||||
var steps = [
|
||||
// Test single mark addition
|
||||
function () {
|
||||
ok(true, "Running mark addition test");
|
||||
performance.mark("test");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "Number of marks should be 1");
|
||||
var mark = marks[0];
|
||||
is(mark.name, "test", "mark name should be 'test'");
|
||||
is(mark.entryType, "mark", "mark type should be 'mark'");
|
||||
isnot(mark.startTime, 0, "mark start time should not be 0");
|
||||
is(mark.duration, 0, "mark duration should be 0");
|
||||
},
|
||||
// Test multiple mark addition
|
||||
function () {
|
||||
ok(true, "Running multiple mark with same name addition test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
var marks_type = performance.getEntriesByType("mark");
|
||||
is(marks_type.length, 3, "Number of marks by type should be 3");
|
||||
var marks_name = performance.getEntriesByName("test");
|
||||
is(marks_name.length, 3, "Number of marks by name should be 3");
|
||||
var mark = marks_name[0];
|
||||
is(mark.name, "test", "mark name should be 'test'");
|
||||
is(mark.entryType, "mark", "mark type should be 'mark'");
|
||||
isnot(mark.startTime, 0, "mark start time should not be 0");
|
||||
is(mark.duration, 0, "mark duration should be 0");
|
||||
var times = [];
|
||||
// This also tests the chronological ordering specified as
|
||||
// required for getEntries in the performance timeline spec.
|
||||
marks_name.forEach(function(s) {
|
||||
times.forEach(function(time) {
|
||||
ok(s.startTime >= time.startTime,
|
||||
"Times should be equal or increasing between similarly named marks: " + s.startTime + " >= " + time.startTime);
|
||||
});
|
||||
times.push(s);
|
||||
});
|
||||
},
|
||||
// Test all marks removal
|
||||
function () {
|
||||
ok(true, "Running all mark removal test");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 2, "number of marks before all removal");
|
||||
performance.clearMarks();
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
// Test single mark removal
|
||||
function () {
|
||||
ok(true, "Running removal test (0 'test' marks with other marks)");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks after all removal");
|
||||
},
|
||||
// Test single mark removal
|
||||
function () {
|
||||
ok(true, "Running removal test (0 'test' marks with no other marks)");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (1 'test' mark with other marks)");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 2, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (1 'test' mark with no other marks)");
|
||||
performance.mark("test");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (2 'test' marks with other marks)");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 3, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (2 'test' marks with no other marks)");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 2, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
// Test mark name being same as navigation timing parameter
|
||||
function () {
|
||||
ok(true, "Running mark name collision test");
|
||||
for (n in performance.timing) {
|
||||
try {
|
||||
if (n == "toJSON") {
|
||||
ok(true, "Skipping toJSON entry in collision test");
|
||||
continue;
|
||||
}
|
||||
performance.mark(n);
|
||||
ok(false, "Mark name collision test failed for name " + n + ", shouldn't make it here!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for mark named " + n);
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for name collision is syntax error");
|
||||
}
|
||||
};
|
||||
},
|
||||
// Test measure
|
||||
function () {
|
||||
ok(true, "Running measure addition with no start/end time test");
|
||||
performance.measure("test");
|
||||
var measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 1, "number of measures should be 1");
|
||||
var measure = measures[0];
|
||||
is(measure.name, "test", "measure name should be 'test'");
|
||||
is(measure.entryType, "measure", "measure type should be 'measure'");
|
||||
is(measure.startTime, 0, "measure start time should be zero");
|
||||
ok(measure.duration >= 0, "measure duration should not be negative");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running measure addition with only start time test");
|
||||
performance.mark("test1");
|
||||
performance.measure("test", "test1", undefined);
|
||||
var measures = performance.getEntriesByName("test", "measure");
|
||||
var marks = performance.getEntriesByName("test1", "mark");
|
||||
var measure = measures[0];
|
||||
var mark = marks[0];
|
||||
is(measure.startTime, mark.startTime, "measure start time should be equal to the mark startTime");
|
||||
ok(measure.duration >= 0, "measure duration should not be negative");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running measure addition with only end time test");
|
||||
performance.mark("test1");
|
||||
performance.measure("test", undefined, "test1");
|
||||
var measures = performance.getEntriesByName("test", "measure");
|
||||
var marks = performance.getEntriesByName("test1", "mark");
|
||||
var measure = measures[0];
|
||||
var mark = marks[0];
|
||||
ok(measure.duration >= 0, "measure duration should not be negative");
|
||||
},
|
||||
// Test measure picking latest version of similarly named tags
|
||||
function () {
|
||||
ok(true, "Running multiple mark with same name addition test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks_name = performance.getEntriesByName("test");
|
||||
is(marks_name.length, 3, "Number of marks by name should be 3");
|
||||
var marks_name2 = performance.getEntriesByName("test2");
|
||||
is(marks_name2.length, 1, "Number of marks by name should be 1");
|
||||
var test_mark = marks_name2[0];
|
||||
performance.measure("test", "test", "test2");
|
||||
var measures_type = performance.getEntriesByType("measure");
|
||||
var last_mark = marks_name[marks_name.length - 1];
|
||||
is(measures_type.length, 1, "Number of measures by type should be 1");
|
||||
var measure = measures_type[0];
|
||||
is(measure.startTime, last_mark.startTime, "Measure start time should be the start time of the latest 'test' mark");
|
||||
// Tolerance testing to avoid oranges, since we're doing double math across two different languages.
|
||||
ok(measure.duration - (test_mark.startTime - last_mark.startTime) < .00001,
|
||||
"Measure duration ( " + measure.duration + ") should be difference between two marks");
|
||||
},
|
||||
// Test all measure removal
|
||||
function () {
|
||||
ok(true, "Running all measure removal test");
|
||||
performance.measure("test");
|
||||
performance.measure("test2");
|
||||
var measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 2, "measure entries should be length 2");
|
||||
performance.clearMeasures();
|
||||
measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 0, "measure entries should be length 0");
|
||||
},
|
||||
// Test single measure removal
|
||||
function () {
|
||||
ok(true, "Running all measure removal test");
|
||||
performance.measure("test");
|
||||
performance.measure("test2");
|
||||
var measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 2, "measure entries should be length 2");
|
||||
performance.clearMeasures("test");
|
||||
measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 1, "measure entries should be length 1");
|
||||
},
|
||||
// Test measure with invalid start time mark name
|
||||
function () {
|
||||
ok(true, "Running measure invalid start test");
|
||||
try {
|
||||
performance.measure("test", "notamark");
|
||||
ok(false, "invalid measure start time exception not thrown!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for invalid measure");
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for invalid time is syntax error");
|
||||
}
|
||||
},
|
||||
// Test measure with invalid end time mark name
|
||||
function () {
|
||||
ok(true, "Running measure invalid end test");
|
||||
try {
|
||||
performance.measure("test", undefined, "notamark");
|
||||
ok(false, "invalid measure end time exception not thrown!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for invalid measure");
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for invalid time is syntax error");
|
||||
}
|
||||
},
|
||||
// Test measure name being same as navigation timing parameter
|
||||
function () {
|
||||
ok(true, "Running measure name collision test");
|
||||
for (n in performance.timing) {
|
||||
try {
|
||||
if (n == "toJSON") {
|
||||
ok(true, "Skipping toJSON entry in collision test");
|
||||
continue;
|
||||
}
|
||||
performance.measure(n);
|
||||
ok(false, "Measure name collision test failed for name " + n + ", shouldn't make it here!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for measure named " + n);
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for name collision is syntax error");
|
||||
}
|
||||
};
|
||||
},
|
||||
// Test measure mark being a reserved name
|
||||
function () {
|
||||
ok(true, "Create measures using all reserved names");
|
||||
for (n in performance.timing) {
|
||||
try {
|
||||
if (n == "toJSON") {
|
||||
ok(true, "Skipping toJSON entry in collision test");
|
||||
continue;
|
||||
}
|
||||
performance.measure("test", n);
|
||||
ok(true, "Measure created from reserved name as starting time: " + n);
|
||||
} catch (e) {
|
||||
ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd"].indexOf(n) >= 0,
|
||||
"Measure created from reserved name as starting time: " + n + " and threw expected error");
|
||||
}
|
||||
};
|
||||
},
|
||||
function () {
|
||||
ok(true, "all done!");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
// TODO: Test measure picking latest version of similarly named tags
|
||||
];
|
||||
|
||||
function next() {
|
||||
ok(true, "Begin!");
|
||||
@ -296,6 +32,8 @@
|
||||
ok(false, "Caught exception", ex);
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
272
dom/base/test/test_performance_user_timing.js
Normal file
272
dom/base/test/test_performance_user_timing.js
Normal file
@ -0,0 +1,272 @@
|
||||
var steps = [
|
||||
// Test single mark addition
|
||||
function () {
|
||||
ok(true, "Running mark addition test");
|
||||
performance.mark("test");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "Number of marks should be 1");
|
||||
var mark = marks[0];
|
||||
is(mark.name, "test", "mark name should be 'test'");
|
||||
is(mark.entryType, "mark", "mark type should be 'mark'");
|
||||
isnot(mark.startTime, 0, "mark start time should not be 0");
|
||||
is(mark.duration, 0, "mark duration should be 0");
|
||||
},
|
||||
// Test multiple mark addition
|
||||
function () {
|
||||
ok(true, "Running multiple mark with same name addition test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
var marks_type = performance.getEntriesByType("mark");
|
||||
is(marks_type.length, 3, "Number of marks by type should be 3");
|
||||
var marks_name = performance.getEntriesByName("test");
|
||||
is(marks_name.length, 3, "Number of marks by name should be 3");
|
||||
var mark = marks_name[0];
|
||||
is(mark.name, "test", "mark name should be 'test'");
|
||||
is(mark.entryType, "mark", "mark type should be 'mark'");
|
||||
isnot(mark.startTime, 0, "mark start time should not be 0");
|
||||
is(mark.duration, 0, "mark duration should be 0");
|
||||
var times = [];
|
||||
// This also tests the chronological ordering specified as
|
||||
// required for getEntries in the performance timeline spec.
|
||||
marks_name.forEach(function(s) {
|
||||
times.forEach(function(time) {
|
||||
ok(s.startTime >= time.startTime,
|
||||
"Times should be equal or increasing between similarly named marks: " + s.startTime + " >= " + time.startTime);
|
||||
});
|
||||
times.push(s);
|
||||
});
|
||||
},
|
||||
// Test all marks removal
|
||||
function () {
|
||||
ok(true, "Running all mark removal test");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 2, "number of marks before all removal");
|
||||
performance.clearMarks();
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
// Test single mark removal
|
||||
function () {
|
||||
ok(true, "Running removal test (0 'test' marks with other marks)");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks after all removal");
|
||||
},
|
||||
// Test single mark removal
|
||||
function () {
|
||||
ok(true, "Running removal test (0 'test' marks with no other marks)");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (1 'test' mark with other marks)");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 2, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (1 'test' mark with no other marks)");
|
||||
performance.mark("test");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (2 'test' marks with other marks)");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 3, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 1, "number of marks after all removal");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running removal test (2 'test' marks with no other marks)");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
var marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 2, "number of marks before all removal");
|
||||
performance.clearMarks("test");
|
||||
marks = performance.getEntriesByType("mark");
|
||||
is(marks.length, 0, "number of marks after all removal");
|
||||
},
|
||||
// Test mark name being same as navigation timing parameter
|
||||
function () {
|
||||
ok(true, "Running mark name collision test");
|
||||
for (n in performance.timing) {
|
||||
try {
|
||||
if (n == "toJSON") {
|
||||
ok(true, "Skipping toJSON entry in collision test");
|
||||
continue;
|
||||
}
|
||||
performance.mark(n);
|
||||
ok(false, "Mark name collision test failed for name " + n + ", shouldn't make it here!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for mark named " + n);
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for name collision is syntax error");
|
||||
}
|
||||
};
|
||||
},
|
||||
// Test measure
|
||||
function () {
|
||||
ok(true, "Running measure addition with no start/end time test");
|
||||
performance.measure("test");
|
||||
var measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 1, "number of measures should be 1");
|
||||
var measure = measures[0];
|
||||
is(measure.name, "test", "measure name should be 'test'");
|
||||
is(measure.entryType, "measure", "measure type should be 'measure'");
|
||||
is(measure.startTime, 0, "measure start time should be zero");
|
||||
ok(measure.duration >= 0, "measure duration should not be negative");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running measure addition with only start time test");
|
||||
performance.mark("test1");
|
||||
performance.measure("test", "test1", undefined);
|
||||
var measures = performance.getEntriesByName("test", "measure");
|
||||
var marks = performance.getEntriesByName("test1", "mark");
|
||||
var measure = measures[0];
|
||||
var mark = marks[0];
|
||||
is(measure.startTime, mark.startTime, "measure start time should be equal to the mark startTime");
|
||||
ok(measure.duration >= 0, "measure duration should not be negative");
|
||||
},
|
||||
function () {
|
||||
ok(true, "Running measure addition with only end time test");
|
||||
performance.mark("test1");
|
||||
performance.measure("test", undefined, "test1");
|
||||
var measures = performance.getEntriesByName("test", "measure");
|
||||
var marks = performance.getEntriesByName("test1", "mark");
|
||||
var measure = measures[0];
|
||||
var mark = marks[0];
|
||||
ok(measure.duration >= 0, "measure duration should not be negative");
|
||||
},
|
||||
// Test measure picking latest version of similarly named tags
|
||||
function () {
|
||||
ok(true, "Running multiple mark with same name addition test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test");
|
||||
performance.mark("test2");
|
||||
var marks_name = performance.getEntriesByName("test");
|
||||
is(marks_name.length, 3, "Number of marks by name should be 3");
|
||||
var marks_name2 = performance.getEntriesByName("test2");
|
||||
is(marks_name2.length, 1, "Number of marks by name should be 1");
|
||||
var test_mark = marks_name2[0];
|
||||
performance.measure("test", "test", "test2");
|
||||
var measures_type = performance.getEntriesByType("measure");
|
||||
var last_mark = marks_name[marks_name.length - 1];
|
||||
is(measures_type.length, 1, "Number of measures by type should be 1");
|
||||
var measure = measures_type[0];
|
||||
is(measure.startTime, last_mark.startTime, "Measure start time should be the start time of the latest 'test' mark");
|
||||
// Tolerance testing to avoid oranges, since we're doing double math across two different languages.
|
||||
ok(measure.duration - (test_mark.startTime - last_mark.startTime) < .00001,
|
||||
"Measure duration ( " + measure.duration + ") should be difference between two marks");
|
||||
},
|
||||
function() {
|
||||
ok(true, "Running measure addition with no start/end time test");
|
||||
performance.measure("test", "navigationStart");
|
||||
var measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 1, "number of measures should be 1");
|
||||
var measure = measures[0];
|
||||
is(measure.name, "test", "measure name should be 'test'");
|
||||
is(measure.entryType, "measure", "measure type should be 'measure'");
|
||||
is(measure.startTime, 0, "measure start time should be zero");
|
||||
ok(measure.duration >= 0, "measure duration should not be negative");
|
||||
},
|
||||
// Test all measure removal
|
||||
function () {
|
||||
ok(true, "Running all measure removal test");
|
||||
performance.measure("test");
|
||||
performance.measure("test2");
|
||||
var measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 2, "measure entries should be length 2");
|
||||
performance.clearMeasures();
|
||||
measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 0, "measure entries should be length 0");
|
||||
},
|
||||
// Test single measure removal
|
||||
function () {
|
||||
ok(true, "Running all measure removal test");
|
||||
performance.measure("test");
|
||||
performance.measure("test2");
|
||||
var measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 2, "measure entries should be length 2");
|
||||
performance.clearMeasures("test");
|
||||
measures = performance.getEntriesByType("measure");
|
||||
is(measures.length, 1, "measure entries should be length 1");
|
||||
},
|
||||
// Test measure with invalid start time mark name
|
||||
function () {
|
||||
ok(true, "Running measure invalid start test");
|
||||
try {
|
||||
performance.measure("test", "notamark");
|
||||
ok(false, "invalid measure start time exception not thrown!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for invalid measure");
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for invalid time is syntax error");
|
||||
}
|
||||
},
|
||||
// Test measure with invalid end time mark name
|
||||
function () {
|
||||
ok(true, "Running measure invalid end test");
|
||||
try {
|
||||
performance.measure("test", undefined, "notamark");
|
||||
ok(false, "invalid measure end time exception not thrown!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for invalid measure");
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for invalid time is syntax error");
|
||||
}
|
||||
},
|
||||
// Test measure name being same as navigation timing parameter
|
||||
function () {
|
||||
ok(true, "Running measure name collision test");
|
||||
for (n in performance.timing) {
|
||||
try {
|
||||
if (n == "toJSON") {
|
||||
ok(true, "Skipping toJSON entry in collision test");
|
||||
continue;
|
||||
}
|
||||
performance.measure(n);
|
||||
ok(false, "Measure name collision test failed for name " + n + ", shouldn't make it here!");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "DOM exception thrown for measure named " + n);
|
||||
is(e.code, e.SYNTAX_ERR, "DOM exception for name collision is syntax error");
|
||||
}
|
||||
};
|
||||
},
|
||||
// Test measure mark being a reserved name
|
||||
function () {
|
||||
ok(true, "Create measures using all reserved names");
|
||||
for (n in performance.timing) {
|
||||
try {
|
||||
if (n == "toJSON") {
|
||||
ok(true, "Skipping toJSON entry in collision test");
|
||||
continue;
|
||||
}
|
||||
performance.measure("test", n);
|
||||
ok(true, "Measure created from reserved name as starting time: " + n);
|
||||
} catch (e) {
|
||||
ok(["redirectStart", "redirectEnd", "unloadEventStart", "unloadEventEnd", "loadEventEnd"].indexOf(n) >= 0,
|
||||
"Measure created from reserved name as starting time: " + n + " and threw expected error");
|
||||
}
|
||||
};
|
||||
},
|
||||
// TODO: Test measure picking latest version of similarly named tags
|
||||
];
|
@ -41,4 +41,9 @@
|
||||
/* SDP AVRCP 1.5 feature */
|
||||
#define SDP_AVRCP_1_5 FALSE
|
||||
|
||||
/* BLE Feature */
|
||||
#define BTA_GATT_INCLUDED TRUE
|
||||
#define BLE_INCLUDED TRUE
|
||||
#define SMP_INCLUDED TRUE
|
||||
|
||||
#endif /* B2G_BDROID_BUILDCFG_H */
|
||||
|
@ -179,7 +179,7 @@ nsGonkCameraControl::Initialize()
|
||||
mCurrentConfiguration.mRecorderProfile.Truncate();
|
||||
|
||||
// Initialize our camera configuration database.
|
||||
PullParametersImpl();
|
||||
mCameraHw->PullParameters(mParams);
|
||||
|
||||
// Set preferred preview frame format.
|
||||
mParams.Set(CAMERA_PARAM_PREVIEWFORMAT, NS_LITERAL_STRING("yuv420sp"));
|
||||
@ -1127,7 +1127,13 @@ nsGonkCameraControl::PullParametersImpl()
|
||||
DOM_CAMERA_LOGI("Pulling camera parameters\n");
|
||||
RETURN_IF_NO_CAMERA_HW();
|
||||
|
||||
return mCameraHw->PullParameters(mParams);
|
||||
nsresult rv = mCameraHw->PullParameters(mParams);
|
||||
mParams.Get(CAMERA_PARAM_THUMBNAILSIZE, mLastThumbnailSize);
|
||||
mParams.Get(CAMERA_PARAM_PICTURE_SIZE, mCurrentConfiguration.mPictureSize);
|
||||
mParams.Get(CAMERA_PARAM_PREVIEWSIZE, mCurrentConfiguration.mPreviewSize);
|
||||
mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -527,6 +527,33 @@ suite.test('bug-1052851', function() {
|
||||
.then(resolve, suite.rejectGetCamera);
|
||||
});
|
||||
|
||||
suite.test('bug-1124338', function() {
|
||||
function triggerAutoFocus(p) {
|
||||
var sync = new Promise(function(resolve, reject) {
|
||||
function onEvent(e) {
|
||||
suite.camera.removeEventListener('focus', onEvent);
|
||||
var thumbnailSize = suite.camera.getThumbnailSize();
|
||||
ok(thumbnailSize.width == 640 && thumbnailSize.height == 480, 'thumbnail size reset with auto focus');
|
||||
resolve();
|
||||
}
|
||||
suite.camera.addEventListener('focus', onEvent);
|
||||
});
|
||||
|
||||
var initThumbnailSize = suite.camera.getThumbnailSize();
|
||||
ok(initThumbnailSize.width == 320 && initThumbnailSize.height == 240, 'initial thumbnail size incorrect');
|
||||
suite.hw.params['jpeg-thumbnail-width'] = '640';
|
||||
suite.hw.params['jpeg-thumbnail-height'] = '480';
|
||||
suite.hw.fireAutoFocusComplete(false);
|
||||
return sync;
|
||||
}
|
||||
|
||||
suite.hw.params['jpeg-thumbnail-size-values'] = '320x240,640x480';
|
||||
suite.hw.params['jpeg-thumbnail-width'] = '320';
|
||||
suite.hw.params['jpeg-thumbnail-height'] = '240';
|
||||
return suite.getCamera()
|
||||
.then(triggerAutoFocus)
|
||||
});
|
||||
|
||||
suite.setup()
|
||||
.then(suite.run);
|
||||
|
||||
|
@ -2642,7 +2642,8 @@ CanvasRenderingContext2D::Stroke(const CanvasPath& path)
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::DrawFocusIfNeeded(mozilla::dom::Element& aElement)
|
||||
void CanvasRenderingContext2D::DrawFocusIfNeeded(mozilla::dom::Element& aElement,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
EnsureUserSpacePath();
|
||||
|
||||
@ -2674,8 +2675,12 @@ void CanvasRenderingContext2D::DrawFocusIfNeeded(mozilla::dom::Element& aElement
|
||||
|
||||
// set dashing for foreground
|
||||
FallibleTArray<mozilla::gfx::Float>& dash = CurrentState().dash;
|
||||
dash.AppendElement(1);
|
||||
dash.AppendElement(1);
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
if (!dash.AppendElement(1)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// set the foreground focus color
|
||||
CurrentState().SetColorStyle(Style::STROKE, NS_RGBA(0,0,0, 255));
|
||||
@ -3947,7 +3952,8 @@ CanvasRenderingContext2D::SetMozDashOffset(double mozDashOffset)
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::SetLineDash(const Sequence<double>& aSegments)
|
||||
CanvasRenderingContext2D::SetLineDash(const Sequence<double>& aSegments,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
FallibleTArray<mozilla::gfx::Float> dash;
|
||||
|
||||
@ -3957,11 +3963,18 @@ CanvasRenderingContext2D::SetLineDash(const Sequence<double>& aSegments)
|
||||
// taken care of by WebIDL
|
||||
return;
|
||||
}
|
||||
dash.AppendElement(aSegments[x]);
|
||||
|
||||
if (!dash.AppendElement(aSegments[x])) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (aSegments.Length() % 2) { // If the number of elements is odd, concatenate again
|
||||
for (uint32_t x = 0; x < aSegments.Length(); x++) {
|
||||
dash.AppendElement(aSegments[x]);
|
||||
if (!dash.AppendElement(aSegments[x])) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ public:
|
||||
void Fill(const CanvasPath& path, const CanvasWindingRule& winding);
|
||||
void Stroke();
|
||||
void Stroke(const CanvasPath& path);
|
||||
void DrawFocusIfNeeded(mozilla::dom::Element& element);
|
||||
void DrawFocusIfNeeded(mozilla::dom::Element& element, ErrorResult& aRv);
|
||||
bool DrawCustomFocusRing(mozilla::dom::Element& element);
|
||||
void Clip(const CanvasWindingRule& winding);
|
||||
void Clip(const CanvasPath& path, const CanvasWindingRule& winding);
|
||||
@ -363,7 +363,8 @@ public:
|
||||
void SetMozDash(JSContext* cx, const JS::Value& mozDash,
|
||||
mozilla::ErrorResult& error);
|
||||
|
||||
void SetLineDash(const Sequence<double>& mSegments);
|
||||
void SetLineDash(const Sequence<double>& mSegments,
|
||||
mozilla::ErrorResult& aRv);
|
||||
void GetLineDash(nsTArray<double>& mSegments) const;
|
||||
|
||||
void SetLineDashOffset(double mOffset);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
class WebGLSampler;
|
||||
class WebGLSync;
|
||||
class WebGLTransformFeedback;
|
||||
@ -56,9 +57,10 @@ public:
|
||||
GLbitfield mask, GLenum filter);
|
||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval);
|
||||
void InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments);
|
||||
void InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
|
||||
ErrorResult& aRv);
|
||||
void InvalidateSubFramebuffer (GLenum target, const dom::Sequence<GLenum>& attachments, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height);
|
||||
GLsizei width, GLsizei height, ErrorResult& aRv);
|
||||
void ReadBuffer(GLenum mode);
|
||||
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
|
@ -343,26 +343,38 @@ WebGL2Context::GetInternalformatParameter(JSContext*, GLenum target, GLenum inte
|
||||
|
||||
// Map attachments intended for the default buffer, to attachments for a non-
|
||||
// default buffer.
|
||||
static void
|
||||
static bool
|
||||
TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
|
||||
{
|
||||
for (size_t i = 0; i < in.Length(); i++) {
|
||||
switch (in[i]) {
|
||||
case LOCAL_GL_COLOR:
|
||||
out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
if (!out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_DEPTH:
|
||||
out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT);
|
||||
if (!out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_STENCIL:
|
||||
out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT);
|
||||
if (!out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments)
|
||||
WebGL2Context::InvalidateFramebuffer(GLenum target,
|
||||
const dom::Sequence<GLenum>& attachments,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
@ -407,7 +419,11 @@ WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>&
|
||||
|
||||
if (!fb && !isDefaultFB) {
|
||||
dom::Sequence<GLenum> tmpAttachments;
|
||||
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
||||
if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
gl->fInvalidateFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements());
|
||||
} else {
|
||||
gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
|
||||
@ -416,7 +432,8 @@ WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>&
|
||||
|
||||
void
|
||||
WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height)
|
||||
GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
@ -461,7 +478,11 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
|
||||
|
||||
if (!fb && !isDefaultFB) {
|
||||
dom::Sequence<GLenum> tmpAttachments;
|
||||
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
||||
if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements(),
|
||||
x, y, width, height);
|
||||
} else {
|
||||
|
@ -1962,7 +1962,9 @@ private:
|
||||
|
||||
if (!mKeyUsages.IsEmpty()) {
|
||||
mJwk.mKey_ops.Construct();
|
||||
mJwk.mKey_ops.Value().AppendElements(mKeyUsages);
|
||||
if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -316,7 +316,9 @@ DataStoreDB::DatabaseOpened()
|
||||
}
|
||||
|
||||
StringOrStringSequence objectStores;
|
||||
objectStores.RawSetAsStringSequence().AppendElements(mObjectStores);
|
||||
if (!objectStores.RawSetAsStringSequence().AppendElements(mObjectStores)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBTransaction> txn;
|
||||
error = mDatabase->Transaction(objectStores,
|
||||
|
@ -1358,7 +1358,9 @@ DataStoreService::CreateFirstRevisionId(uint32_t aAppId,
|
||||
new FirstRevisionIdCallback(aAppId, aName, aManifestURL);
|
||||
|
||||
Sequence<nsString> dbs;
|
||||
dbs.AppendElement(NS_LITERAL_STRING(DATASTOREDB_REVISION));
|
||||
if (!dbs.AppendElement(NS_LITERAL_STRING(DATASTOREDB_REVISION))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return db->Open(IDBTransactionMode::Readwrite, dbs, callback);
|
||||
}
|
||||
|
@ -580,6 +580,15 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_ENTER_WIDGET:
|
||||
// In some cases on e10s NS_MOUSE_ENTER_WIDGET
|
||||
// event was sent twice into child process of content.
|
||||
// (From specific widget code (sending is not permanent) and
|
||||
// from ESM::DispatchMouseOrPointerEvent (sending is permanent)).
|
||||
// Flag mNoCrossProcessBoundaryForwarding helps to
|
||||
// suppress sending accidental event from widget code.
|
||||
aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
break;
|
||||
case NS_MOUSE_EXIT_WIDGET:
|
||||
// If this is a remote frame, we receive NS_MOUSE_EXIT_WIDGET from the parent
|
||||
// the mouse exits our content. Since the parent may update the cursor
|
||||
@ -592,6 +601,10 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
ClearCachedWidgetCursor(mCurrentTarget);
|
||||
}
|
||||
|
||||
// Flag helps to suppress double event sending into process of content.
|
||||
// For more information see comment above, at NS_MOUSE_ENTER_WIDGET case.
|
||||
aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
|
||||
// If the event is not a top-level window exit, then it's not
|
||||
// really an exit --- we may have traversed widget boundaries but
|
||||
// we're still in our toplevel window.
|
||||
@ -1183,7 +1196,6 @@ CrossProcessSafeEvent(const WidgetEvent& aEvent)
|
||||
case NS_CONTEXTMENU:
|
||||
case NS_MOUSE_ENTER_WIDGET:
|
||||
case NS_MOUSE_EXIT_WIDGET:
|
||||
case NS_MOUSE_OVER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -1860,7 +1860,11 @@ HTMLInputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
Sequence<nsString> list;
|
||||
list.AppendElement(aValue);
|
||||
if (!list.AppendElement(aValue)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
MozSetFileNameArray(list, aRv);
|
||||
return;
|
||||
}
|
||||
@ -2441,7 +2445,9 @@ HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames, uint32_t aLen
|
||||
|
||||
Sequence<nsString> list;
|
||||
for (uint32_t i = 0; i < aLength; ++i) {
|
||||
list.AppendElement(nsDependentString(aFileNames[i]));
|
||||
if (!list.AppendElement(nsDependentString(aFileNames[i]))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
@ -2492,7 +2498,10 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
|
||||
if (mType == NS_FORM_INPUT_FILE)
|
||||
{
|
||||
Sequence<nsString> list;
|
||||
list.AppendElement(aValue);
|
||||
if (!list.AppendElement(aValue)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
MozSetFileNameArray(list, rv);
|
||||
return rv.StealNSResult();
|
||||
|
@ -49,7 +49,7 @@ interface nsIJSRAIIHelper;
|
||||
interface nsIContentPermissionRequest;
|
||||
interface nsIObserver;
|
||||
|
||||
[scriptable, uuid(0ce789cc-3fb6-48b8-a58e-32deefc337b4)]
|
||||
[scriptable, uuid(7719798a-62fa-4dff-a6ed-782256649232)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -1428,6 +1428,14 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
*/
|
||||
void setAsyncScrollOffset(in nsIDOMNode aNode, in int32_t aX, in int32_t aY);
|
||||
|
||||
/**
|
||||
* Set async zoom value. aRootElement should be the document element of our
|
||||
* document. The next composite will render with that zoom added to any
|
||||
* existing zoom if async scrolling is enabled, and then the zoom will be
|
||||
* removed. Only call this while test-controlled refreshes is enabled.
|
||||
*/
|
||||
void setAsyncZoom(in nsIDOMNode aRootElement, in float aValue);
|
||||
|
||||
/**
|
||||
* Method for testing StyleAnimationValue::ComputeDistance.
|
||||
*
|
||||
|
@ -1226,25 +1226,21 @@ bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event)
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (widget) {
|
||||
// When we mouseenter the tab, the tab's cursor should become the current
|
||||
// cursor. When we mouseexit, we stop.
|
||||
if (event.message == NS_MOUSE_ENTER_WIDGET ||
|
||||
event.message == NS_MOUSE_OVER) {
|
||||
// When we mouseenter the tab, the tab's cursor should
|
||||
// become the current cursor. When we mouseexit, we stop.
|
||||
if (NS_MOUSE_ENTER_WIDGET == event.message) {
|
||||
mTabSetsCursor = true;
|
||||
if (mCustomCursor) {
|
||||
widget->SetCursor(mCustomCursor, mCustomCursorHotspotX, mCustomCursorHotspotY);
|
||||
} else if (mCursor != nsCursor(-1)) {
|
||||
widget->SetCursor(mCursor);
|
||||
}
|
||||
// We don't actually want to forward NS_MOUSE_ENTER_WIDGET messages.
|
||||
return true;
|
||||
} else if (event.message == NS_MOUSE_EXIT_WIDGET ||
|
||||
event.message == NS_MOUSE_OUT) {
|
||||
} else if (NS_MOUSE_EXIT_WIDGET == event.message) {
|
||||
mTabSetsCursor = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.message == NS_MOUSE_MOVE) {
|
||||
if (NS_MOUSE_MOVE == event.message) {
|
||||
return SendRealMouseMoveEvent(event);
|
||||
}
|
||||
return SendRealMouseButtonEvent(event);
|
||||
|
@ -6,16 +6,15 @@
|
||||
|
||||
#include "DecodedStream.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class DecodedStreamGraphListener : public MediaStreamListener {
|
||||
typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
|
||||
public:
|
||||
DecodedStreamGraphListener(MediaStream* aStream, DecodedStreamData* aData)
|
||||
: mData(aData)
|
||||
, mMutex("DecodedStreamGraphListener::mMutex")
|
||||
explicit DecodedStreamGraphListener(MediaStream* aStream)
|
||||
: mMutex("DecodedStreamGraphListener::mMutex")
|
||||
, mStream(aStream)
|
||||
, mLastOutputTime(aStream->StreamTimeToMicroseconds(aStream->GetCurrentTime()))
|
||||
, mStreamFinishedOnMainThread(false) {}
|
||||
@ -52,7 +51,6 @@ public:
|
||||
void Forget()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mData = nullptr;
|
||||
MutexAutoLock lock(mMutex);
|
||||
mStream = nullptr;
|
||||
}
|
||||
@ -64,9 +62,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// Main thread only
|
||||
DecodedStreamData* mData;
|
||||
|
||||
Mutex mMutex;
|
||||
// Members below are protected by mMutex.
|
||||
nsRefPtr<MediaStream> mStream;
|
||||
@ -74,14 +69,12 @@ private:
|
||||
bool mStreamFinishedOnMainThread;
|
||||
};
|
||||
|
||||
DecodedStreamData::DecodedStreamData(MediaDecoder* aDecoder,
|
||||
int64_t aInitialTime,
|
||||
DecodedStreamData::DecodedStreamData(int64_t aInitialTime,
|
||||
SourceMediaStream* aStream)
|
||||
: mAudioFramesWritten(0)
|
||||
, mInitialTime(aInitialTime)
|
||||
, mNextVideoTime(-1)
|
||||
, mNextAudioTime(-1)
|
||||
, mDecoder(aDecoder)
|
||||
, mStreamInitialized(false)
|
||||
, mHaveSentFinish(false)
|
||||
, mHaveSentFinishAudio(false)
|
||||
@ -91,7 +84,7 @@ DecodedStreamData::DecodedStreamData(MediaDecoder* aDecoder,
|
||||
, mHaveBlockedForStateMachineNotPlaying(false)
|
||||
, mEOSVideoCompensation(false)
|
||||
{
|
||||
mListener = new DecodedStreamGraphListener(mStream, this);
|
||||
mListener = new DecodedStreamGraphListener(mStream);
|
||||
mStream->AddListener(mListener);
|
||||
}
|
||||
|
||||
@ -116,8 +109,8 @@ DecodedStreamData::GetClock() const
|
||||
class OutputStreamListener : public MediaStreamListener {
|
||||
typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
|
||||
public:
|
||||
OutputStreamListener(MediaDecoder* aDecoder, MediaStream* aStream)
|
||||
: mDecoder(aDecoder), mStream(aStream) {}
|
||||
OutputStreamListener(DecodedStream* aDecodedStream, MediaStream* aStream)
|
||||
: mDecodedStream(aDecodedStream), mStream(aStream) {}
|
||||
|
||||
void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent event) override
|
||||
{
|
||||
@ -131,22 +124,22 @@ public:
|
||||
void Forget()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mDecoder = nullptr;
|
||||
mDecodedStream = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void DoNotifyFinished()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mDecoder) {
|
||||
if (!mDecodedStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the finished stream so it won't block the decoded stream.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
auto& streams = mDecoder->OutputStreams();
|
||||
// Don't read |mDecoder| in the loop since removing the element will lead
|
||||
// to ~OutputStreamData() which will call Forget() to reset |mDecoder|.
|
||||
ReentrantMonitorAutoEnter mon(mDecodedStream->GetReentrantMonitor());
|
||||
auto& streams = mDecodedStream->OutputStreams();
|
||||
// Don't read |mDecodedStream| in the loop since removing the element will lead
|
||||
// to ~OutputStreamData() which will call Forget() to reset |mDecodedStream|.
|
||||
for (int32_t i = streams.Length() - 1; i >= 0; --i) {
|
||||
auto& os = streams[i];
|
||||
MediaStream* p = os.mStream.get();
|
||||
@ -162,7 +155,7 @@ private:
|
||||
}
|
||||
|
||||
// Main thread only
|
||||
MediaDecoder* mDecoder;
|
||||
DecodedStream* mDecodedStream;
|
||||
nsRefPtr<MediaStream> mStream;
|
||||
};
|
||||
|
||||
@ -177,37 +170,54 @@ OutputStreamData::~OutputStreamData()
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamData::Init(MediaDecoder* aDecoder, ProcessedMediaStream* aStream)
|
||||
OutputStreamData::Init(DecodedStream* aDecodedStream, ProcessedMediaStream* aStream)
|
||||
{
|
||||
mStream = aStream;
|
||||
mListener = new OutputStreamListener(aDecoder, aStream);
|
||||
mListener = new OutputStreamListener(aDecodedStream, aStream);
|
||||
aStream->AddListener(mListener);
|
||||
}
|
||||
|
||||
DecodedStream::DecodedStream(ReentrantMonitor& aMonitor)
|
||||
: mMonitor(aMonitor)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
DecodedStreamData*
|
||||
DecodedStream::GetData()
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
return mData.get();
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::DestroyData()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
mData = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::RecreateData(MediaDecoder* aDecoder, int64_t aInitialTime,
|
||||
SourceMediaStream* aStream)
|
||||
DecodedStream::RecreateData(int64_t aInitialTime, SourceMediaStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
MOZ_ASSERT(!mData);
|
||||
mData.reset(new DecodedStreamData(aDecoder, aInitialTime, aStream));
|
||||
mData.reset(new DecodedStreamData(aInitialTime, aStream));
|
||||
}
|
||||
|
||||
nsTArray<OutputStreamData>&
|
||||
DecodedStream::OutputStreams()
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
return mOutputStreams;
|
||||
}
|
||||
|
||||
ReentrantMonitor&
|
||||
DecodedStream::GetReentrantMonitor()
|
||||
{
|
||||
return mMonitor;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -14,13 +14,14 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaDecoder;
|
||||
class MediaInputPort;
|
||||
class SourceMediaStream;
|
||||
class ProcessedMediaStream;
|
||||
class DecodedStream;
|
||||
class DecodedStreamGraphListener;
|
||||
class OutputStreamData;
|
||||
class OutputStreamListener;
|
||||
class ReentrantMonitor;
|
||||
|
||||
namespace layers {
|
||||
class Image;
|
||||
@ -36,8 +37,7 @@ class Image;
|
||||
*/
|
||||
class DecodedStreamData {
|
||||
public:
|
||||
DecodedStreamData(MediaDecoder* aDecoder, int64_t aInitialTime,
|
||||
SourceMediaStream* aStream);
|
||||
DecodedStreamData(int64_t aInitialTime, SourceMediaStream* aStream);
|
||||
~DecodedStreamData();
|
||||
bool IsFinished() const;
|
||||
int64_t GetClock() const;
|
||||
@ -55,7 +55,6 @@ public:
|
||||
// to the output stream.
|
||||
int64_t mNextVideoTime; // microseconds
|
||||
int64_t mNextAudioTime; // microseconds
|
||||
MediaDecoder* mDecoder;
|
||||
// The last video image sent to the stream. Useful if we need to replicate
|
||||
// the image.
|
||||
nsRefPtr<layers::Image> mLastVideoImage;
|
||||
@ -89,7 +88,7 @@ public:
|
||||
// to work.
|
||||
OutputStreamData();
|
||||
~OutputStreamData();
|
||||
void Init(MediaDecoder* aDecoder, ProcessedMediaStream* aStream);
|
||||
void Init(DecodedStream* aDecodedStream, ProcessedMediaStream* aStream);
|
||||
nsRefPtr<ProcessedMediaStream> mStream;
|
||||
// mPort connects DecodedStreamData::mStream to our mStream.
|
||||
nsRefPtr<MediaInputPort> mPort;
|
||||
@ -98,16 +97,18 @@ public:
|
||||
|
||||
class DecodedStream {
|
||||
public:
|
||||
explicit DecodedStream(ReentrantMonitor& aMonitor);
|
||||
DecodedStreamData* GetData();
|
||||
void DestroyData();
|
||||
void RecreateData(MediaDecoder* aDecoder, int64_t aInitialTime,
|
||||
SourceMediaStream* aStream);
|
||||
void RecreateData(int64_t aInitialTime, SourceMediaStream* aStream);
|
||||
nsTArray<OutputStreamData>& OutputStreams();
|
||||
ReentrantMonitor& GetReentrantMonitor();
|
||||
|
||||
private:
|
||||
UniquePtr<DecodedStreamData> mData;
|
||||
// Data about MediaStreams that are being fed by the decoder.
|
||||
nsTArray<OutputStreamData> mOutputStreams;
|
||||
ReentrantMonitor& mMonitor;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -11,6 +11,20 @@
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
// Specialization for nsTArray CopyChooser.
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
template<class T>
|
||||
class IntervalSet;
|
||||
}
|
||||
}
|
||||
|
||||
template<class E>
|
||||
struct nsTArray_CopyChooser<mozilla::media::IntervalSet<E>>
|
||||
{
|
||||
typedef nsTArray_CopyWithConstructors<mozilla::media::IntervalSet<E>> Type;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
@ -198,6 +212,15 @@ public:
|
||||
mFuzz = aFuzz;
|
||||
}
|
||||
|
||||
// Returns true if the two intervals intersect with this being on the right
|
||||
// of aOther
|
||||
bool TouchesOnRight(const SelfType& aOther) const
|
||||
{
|
||||
return aOther.mStart <= mStart &&
|
||||
(mStart - mFuzz <= aOther.mEnd + aOther.mFuzz) &&
|
||||
(aOther.mStart - aOther.mFuzz <= mEnd + mFuzz);
|
||||
}
|
||||
|
||||
T mStart;
|
||||
T mEnd;
|
||||
T mFuzz;
|
||||
@ -291,10 +314,14 @@ public:
|
||||
mIntervals.AppendElement(aInterval);
|
||||
return *this;
|
||||
}
|
||||
ElemType& last = mIntervals.LastElement();
|
||||
if (aInterval.TouchesOnRight(last)) {
|
||||
last = last.Span(aInterval);
|
||||
return *this;
|
||||
}
|
||||
// Most of our actual usage is adding an interval that will be outside the
|
||||
// range. We can speed up normalization here.
|
||||
if (aInterval.RightOf(mIntervals.LastElement()) &&
|
||||
!aInterval.Touches(mIntervals.LastElement())) {
|
||||
if (aInterval.RightOf(last)) {
|
||||
mIntervals.AppendElement(aInterval);
|
||||
return *this;
|
||||
}
|
||||
@ -510,12 +537,13 @@ public:
|
||||
}
|
||||
|
||||
// Shift all values by aOffset.
|
||||
void Shift(const T& aOffset)
|
||||
SelfType& Shift(const T& aOffset)
|
||||
{
|
||||
for (auto& interval : mIntervals) {
|
||||
interval.mStart = interval.mStart + aOffset;
|
||||
interval.mEnd = interval.mEnd + aOffset;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void SetFuzz(const T& aFuzz) {
|
||||
|
@ -85,6 +85,12 @@ public:
|
||||
// data is available.
|
||||
virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) { }
|
||||
|
||||
// Notifies the demuxer that the underlying resource has had data removed.
|
||||
// The demuxer can use this mechanism to inform all track demuxers to update
|
||||
// its TimeIntervals.
|
||||
// This will be called should the demuxer be used with MediaSource.
|
||||
virtual void NotifyDataRemoved() { }
|
||||
|
||||
protected:
|
||||
virtual ~MediaDataDemuxer()
|
||||
{
|
||||
|
@ -384,7 +384,7 @@ void MediaDecoder::RecreateDecodedStream(int64_t aStartTimeUSecs,
|
||||
}
|
||||
DestroyDecodedStream();
|
||||
|
||||
mDecodedStream.RecreateData(this, aStartTimeUSecs, aGraph->CreateSourceStream(nullptr));
|
||||
mDecodedStream.RecreateData(aStartTimeUSecs, aGraph->CreateSourceStream(nullptr));
|
||||
|
||||
// Note that the delay between removing ports in DestroyDecodedStream
|
||||
// and adding new ones won't cause a glitch since all graph operations
|
||||
@ -419,7 +419,7 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
RecreateDecodedStream(mLogicalPosition, aStream->Graph());
|
||||
}
|
||||
OutputStreamData* os = OutputStreams().AppendElement();
|
||||
os->Init(this, aStream);
|
||||
os->Init(&mDecodedStream, aStream);
|
||||
ConnectDecodedStreamToOutputStream(os);
|
||||
if (aFinishWhenEnded) {
|
||||
// Ensure that aStream finishes the moment mDecodedStream does.
|
||||
@ -483,6 +483,7 @@ MediaDecoder::MediaDecoder() :
|
||||
mMediaSeekable(true),
|
||||
mSameOriginMedia(false),
|
||||
mReentrantMonitor("media.decoder"),
|
||||
mDecodedStream(mReentrantMonitor),
|
||||
mPlayState(AbstractThread::MainThread(), PLAY_STATE_LOADING,
|
||||
"MediaDecoder::mPlayState (Canonical)"),
|
||||
mNextState(AbstractThread::MainThread(), PLAY_STATE_PAUSED,
|
||||
|
@ -247,6 +247,8 @@ public:
|
||||
// Only used by WebMReader and MediaOmxReader for now, so stub here rather
|
||||
// than in every reader than inherits from MediaDecoderReader.
|
||||
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {}
|
||||
// Notify the reader that data from the resource was evicted (MediaSource only)
|
||||
virtual void NotifyDataRemoved() {}
|
||||
virtual int64_t GetEvictionOffset(double aTime) { return -1; }
|
||||
|
||||
virtual MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
|
||||
|
@ -69,6 +69,7 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
||||
, mInitDone(false)
|
||||
, mSeekable(false)
|
||||
, mIsEncrypted(false)
|
||||
, mCachedTimeRangesStale(true)
|
||||
#if defined(READER_DORMANT_HEURISTIC)
|
||||
, mDormantEnabled(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false))
|
||||
#endif
|
||||
@ -107,6 +108,7 @@ MediaFormatReader::Shutdown()
|
||||
mAudio.mDecoder = nullptr;
|
||||
}
|
||||
if (mAudio.mTrackDemuxer) {
|
||||
mAudio.ResetDemuxer();
|
||||
mAudio.mTrackDemuxer->BreakCycles();
|
||||
mAudio.mTrackDemuxer = nullptr;
|
||||
}
|
||||
@ -123,6 +125,7 @@ MediaFormatReader::Shutdown()
|
||||
mVideo.mDecoder = nullptr;
|
||||
}
|
||||
if (mVideo.mTrackDemuxer) {
|
||||
mVideo.ResetDemuxer();
|
||||
mVideo.mTrackDemuxer->BreakCycles();
|
||||
mVideo.mTrackDemuxer = nullptr;
|
||||
}
|
||||
@ -509,6 +512,7 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideoSeekRequest.Exists());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudioSeekRequest.Exists());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mSkipRequest.Exists(), "called mid-skipping");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
|
||||
LOGV("RequestVideoData(%d, %lld)", aSkipToNextKeyframe, aTimeThreshold);
|
||||
|
||||
@ -656,6 +660,8 @@ void
|
||||
MediaFormatReader::NotifyNewOutput(TrackType aTrack, MediaData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("Received new sample time:%lld duration:%lld",
|
||||
aSample->mTime, aSample->mDuration);
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
if (!decoder.mOutputRequested) {
|
||||
LOG("MediaFormatReader produced output while flushing, discarding.");
|
||||
@ -670,6 +676,7 @@ void
|
||||
MediaFormatReader::NotifyInputExhausted(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("Decoder has requested more %s data", TrackTypeToStr(aTrack));
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mInputExhausted = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
@ -692,6 +699,7 @@ void
|
||||
MediaFormatReader::NotifyError(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mError = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
@ -718,6 +726,7 @@ MediaFormatReader::NeedInput(DecoderData& aDecoder)
|
||||
return
|
||||
!aDecoder.mError &&
|
||||
aDecoder.HasPromise() &&
|
||||
!aDecoder.mDemuxRequest.Exists() &&
|
||||
aDecoder.mOutput.IsEmpty() &&
|
||||
(aDecoder.mInputExhausted || !aDecoder.mQueuedSamples.IsEmpty() ||
|
||||
aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
|
||||
@ -766,13 +775,16 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack)
|
||||
decoder.mDemuxEOSServiced = false;
|
||||
}
|
||||
|
||||
if (!decoder.mError && decoder.HasWaitingPromise()) {
|
||||
if (decoder.mError) {
|
||||
return false;
|
||||
}
|
||||
if (decoder.HasWaitingPromise()) {
|
||||
MOZ_ASSERT(!decoder.HasPromise());
|
||||
LOG("We have new data. Resolving WaitingPromise");
|
||||
decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
|
||||
return true;
|
||||
}
|
||||
if (!decoder.mError && !mSeekPromise.IsEmpty()) {
|
||||
if (!mSeekPromise.IsEmpty()) {
|
||||
MOZ_ASSERT(!decoder.HasPromise());
|
||||
if (mVideoSeekRequest.Exists() || mAudioSeekRequest.Exists()) {
|
||||
// Already waiting for a seek to complete. Nothing more to do.
|
||||
@ -790,20 +802,19 @@ MediaFormatReader::RequestDemuxSamples(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
MOZ_ASSERT(!decoder.mDemuxRequest.Exists());
|
||||
|
||||
if (!decoder.mQueuedSamples.IsEmpty()) {
|
||||
// No need to demux new samples.
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoder.mDemuxRequest.Exists()) {
|
||||
// We are already in the process of demuxing.
|
||||
return;
|
||||
}
|
||||
if (decoder.mDemuxEOS) {
|
||||
// Nothing left to demux.
|
||||
return;
|
||||
}
|
||||
|
||||
LOGV("Requesting extra demux %s", TrackTypeToStr(aTrack));
|
||||
if (aTrack == TrackInfo::kVideoTrack) {
|
||||
DoDemuxVideo();
|
||||
} else {
|
||||
@ -821,7 +832,7 @@ MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
|
||||
if (decoder.mQueuedSamples.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGV("Giving %s input to decoder", TrackTypeToStr(aTrack));
|
||||
decoder.mOutputRequested = true;
|
||||
|
||||
// Decode all our demuxed frames.
|
||||
@ -845,9 +856,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
return;
|
||||
}
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
|
||||
LOGV("Processing update for %s", TrackTypeToStr(aTrack));
|
||||
|
||||
bool needInput = false;
|
||||
bool needOutput = false;
|
||||
@ -855,6 +864,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
decoder.mUpdateScheduled = false;
|
||||
|
||||
if (UpdateReceivedNewData(aTrack)) {
|
||||
LOGV("Nothing more to do");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -871,13 +881,14 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
}
|
||||
} else if (decoder.mWaitingForData) {
|
||||
// Nothing more we can do at present.
|
||||
LOGV("Still waiting for data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NeedInput(decoder)) {
|
||||
needInput = true;
|
||||
decoder.mInputExhausted = false;
|
||||
}
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
|
||||
|
||||
if (aTrack == TrackInfo::kVideoTrack) {
|
||||
uint64_t delta =
|
||||
decoder.mNumSamplesOutput - mLastReportedNumDecodedFrames;
|
||||
@ -898,18 +909,27 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
}
|
||||
}
|
||||
|
||||
LOGV("Update(%s) ni=%d no=%d", TrackTypeToStr(aTrack), needInput, needOutput);
|
||||
|
||||
if (decoder.mDemuxEOS && !decoder.mDemuxEOSServiced) {
|
||||
decoder.mOutputRequested = true;
|
||||
decoder.mDecoder->Drain();
|
||||
decoder.mDemuxEOSServiced = true;
|
||||
}
|
||||
|
||||
if (!needInput) {
|
||||
LOGV("Requesting decoder to drain");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NeedInput(decoder)) {
|
||||
LOGV("No need for additional input");
|
||||
return;
|
||||
}
|
||||
|
||||
needInput = true;
|
||||
decoder.mInputExhausted = false;
|
||||
|
||||
LOGV("Update(%s) ni=%d no=%d ie=%d, in:%d out:%d qs=%d",
|
||||
TrackTypeToStr(aTrack), needInput, needOutput, decoder.mInputExhausted,
|
||||
decoder.mNumSamplesInput, decoder.mNumSamplesOutput,
|
||||
size_t(decoder.mSizeOfQueue));
|
||||
|
||||
// Demux samples if we don't have some.
|
||||
RequestDemuxSamples(aTrack);
|
||||
// Decode all pending demuxed samples.
|
||||
@ -922,6 +942,7 @@ MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack)
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
MOZ_ASSERT(decoder.HasPromise());
|
||||
if (decoder.mDiscontinuity) {
|
||||
LOGV("Setting discontinuity flag");
|
||||
decoder.mDiscontinuity = false;
|
||||
aData->mDiscontinuity = true;
|
||||
}
|
||||
@ -941,6 +962,7 @@ MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack)
|
||||
} else if (aTrack == TrackInfo::kVideoTrack) {
|
||||
mVideo.mPromise.Resolve(static_cast<VideoData*>(aData), __func__);
|
||||
}
|
||||
LOG("Resolved data promise for %s", TrackTypeToStr(aTrack));
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -979,6 +1001,7 @@ MediaFormatReader::ResetDecode()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
LOGV("");
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
mAudioSeekRequest.DisconnectIfExists();
|
||||
@ -994,9 +1017,11 @@ MediaFormatReader::ResetDecode()
|
||||
mPendingSeekTime.reset();
|
||||
|
||||
if (HasVideo()) {
|
||||
mVideo.ResetDemuxer();
|
||||
Flush(TrackInfo::kVideoTrack);
|
||||
}
|
||||
if (HasAudio()) {
|
||||
mAudio.ResetDemuxer();
|
||||
Flush(TrackInfo::kAudioTrack);
|
||||
}
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
@ -1015,7 +1040,7 @@ MediaFormatReader::Output(TrackType aTrack, MediaData* aSample)
|
||||
}
|
||||
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArgs<TrackType, StorensRefPtrPassByPtr<MediaData>>(
|
||||
NS_NewRunnableMethodWithArgs<TrackType, MediaData*>(
|
||||
this, &MediaFormatReader::NotifyNewOutput, aTrack, aSample);
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
@ -1058,9 +1083,6 @@ MediaFormatReader::Flush(TrackType aTrack)
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear demuxer related data.
|
||||
decoder.mDemuxRequest.DisconnectIfExists();
|
||||
decoder.mTrackDemuxer->Reset();
|
||||
decoder.mDecoder->Flush();
|
||||
// Purge the current decoder's state.
|
||||
// ResetState clears mOutputRequested flag so that we ignore all output until
|
||||
@ -1167,6 +1189,7 @@ void
|
||||
MediaFormatReader::OnSeekFailed(TrackType aTrack, DemuxerFailureReason aResult)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("%s failure = %d", TrackTypeToStr(aTrack), aResult);
|
||||
if (aTrack == TrackType::kVideoTrack) {
|
||||
mVideoSeekRequest.Complete();
|
||||
} else {
|
||||
@ -1186,6 +1209,7 @@ void
|
||||
MediaFormatReader::DoVideoSeek()
|
||||
{
|
||||
MOZ_ASSERT(mPendingSeekTime.isSome());
|
||||
LOGV("Seeking video to %lld", mPendingSeekTime.ref().ToMicroseconds());
|
||||
media::TimeUnit seekTime = mPendingSeekTime.ref();
|
||||
mVideoSeekRequest.Begin(mVideo.mTrackDemuxer->Seek(seekTime)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
@ -1197,6 +1221,7 @@ void
|
||||
MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("Video seeked to %lld", aTime.ToMicroseconds());
|
||||
mVideoSeekRequest.Complete();
|
||||
|
||||
if (HasAudio()) {
|
||||
@ -1213,6 +1238,7 @@ void
|
||||
MediaFormatReader::DoAudioSeek()
|
||||
{
|
||||
MOZ_ASSERT(mPendingSeekTime.isSome());
|
||||
LOGV("Seeking audio to %lld", mPendingSeekTime.ref().ToMicroseconds());
|
||||
media::TimeUnit seekTime = mPendingSeekTime.ref();
|
||||
mAudioSeekRequest.Begin(mAudio.mTrackDemuxer->Seek(seekTime)
|
||||
->RefableThen(GetTaskQueue(), __func__, this,
|
||||
@ -1224,6 +1250,7 @@ void
|
||||
MediaFormatReader::OnAudioSeekCompleted(media::TimeUnit aTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOGV("Audio seeked to %lld", aTime.ToMicroseconds());
|
||||
mAudioSeekRequest.Complete();
|
||||
mPendingSeekTime.reset();
|
||||
mSeekPromise.Resolve(aTime.ToMicroseconds(), __func__);
|
||||
@ -1250,15 +1277,50 @@ MediaFormatReader::GetBuffered()
|
||||
{
|
||||
media::TimeIntervals videoti;
|
||||
media::TimeIntervals audioti;
|
||||
media::TimeIntervals intervals;
|
||||
|
||||
if (!mInitDone) {
|
||||
return intervals;
|
||||
}
|
||||
int64_t startTime;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(mStartTime != -1, "Need to finish metadata decode first");
|
||||
startTime = mStartTime;
|
||||
}
|
||||
if (NS_IsMainThread()) {
|
||||
if (mVideoTrackDemuxer) {
|
||||
videoti = mVideoTrackDemuxer->GetBuffered();
|
||||
}
|
||||
if (mAudioTrackDemuxer) {
|
||||
audioti = mAudioTrackDemuxer->GetBuffered();
|
||||
if (mCachedTimeRangesStale) {
|
||||
MOZ_ASSERT(mMainThreadDemuxer);
|
||||
if (!mDataRange.IsEmpty()) {
|
||||
mMainThreadDemuxer->NotifyDataArrived(mDataRange.Length(), mDataRange.mStart);
|
||||
}
|
||||
if (mVideoTrackDemuxer) {
|
||||
videoti = mVideoTrackDemuxer->GetBuffered();
|
||||
}
|
||||
if (mAudioTrackDemuxer) {
|
||||
audioti = mAudioTrackDemuxer->GetBuffered();
|
||||
}
|
||||
if (HasAudio() && HasVideo()) {
|
||||
mCachedTimeRanges = media::Intersection(Move(videoti), Move(audioti));
|
||||
} else if (HasAudio()) {
|
||||
mCachedTimeRanges = Move(audioti);
|
||||
} else if (HasVideo()) {
|
||||
mCachedTimeRanges = Move(videoti);
|
||||
}
|
||||
mDataRange = ByteInterval();
|
||||
mCachedTimeRangesStale = false;
|
||||
}
|
||||
intervals = mCachedTimeRanges;
|
||||
} else {
|
||||
if (OnTaskQueue()) {
|
||||
// Ensure we have up to date buffered time range.
|
||||
if (HasVideo()) {
|
||||
UpdateReceivedNewData(TrackType::kVideoTrack);
|
||||
}
|
||||
if (HasAudio()) {
|
||||
UpdateReceivedNewData(TrackType::kAudioTrack);
|
||||
}
|
||||
}
|
||||
if (HasVideo()) {
|
||||
MonitorAutoLock lock(mVideo.mMonitor);
|
||||
videoti = mVideo.mTimeRanges;
|
||||
@ -1267,17 +1329,16 @@ MediaFormatReader::GetBuffered()
|
||||
MonitorAutoLock lock(mAudio.mMonitor);
|
||||
audioti = mAudio.mTimeRanges;
|
||||
}
|
||||
}
|
||||
if (HasAudio() && HasVideo()) {
|
||||
videoti.Intersection(audioti);
|
||||
return videoti;
|
||||
} else if (HasAudio()) {
|
||||
return audioti;
|
||||
} else if (HasVideo()) {
|
||||
return videoti;
|
||||
if (HasAudio() && HasVideo()) {
|
||||
intervals = media::Intersection(Move(videoti), Move(audioti));
|
||||
} else if (HasAudio()) {
|
||||
intervals = Move(audioti);
|
||||
} else if (HasVideo()) {
|
||||
intervals = Move(videoti);
|
||||
}
|
||||
}
|
||||
|
||||
return media::TimeIntervals();
|
||||
return intervals.Shift(media::TimeUnit::FromMicroseconds(-startTime));
|
||||
}
|
||||
|
||||
bool MediaFormatReader::IsDormantNeeded()
|
||||
@ -1330,11 +1391,16 @@ MediaFormatReader::NotifyDemuxer(uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
LOGV("aLength=%u, aOffset=%lld", aLength, aOffset);
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDemuxer->NotifyDataArrived(aLength, aOffset);
|
||||
if (aLength || aOffset) {
|
||||
mDemuxer->NotifyDataArrived(aLength, aOffset);
|
||||
} else {
|
||||
mDemuxer->NotifyDataRemoved();
|
||||
}
|
||||
if (HasVideo()) {
|
||||
mVideo.mReceivedNewData = true;
|
||||
ScheduleUpdate(TrackType::kVideoTrack);
|
||||
@ -1350,13 +1416,18 @@ MediaFormatReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int6
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_ASSERT(aBuffer || aLength);
|
||||
if (mDataRange.IsEmpty()) {
|
||||
mDataRange = ByteInterval(aOffset, aOffset + aLength);
|
||||
} else {
|
||||
mDataRange = mDataRange.Span(ByteInterval(aOffset, aOffset + aLength));
|
||||
}
|
||||
mCachedTimeRangesStale = true;
|
||||
|
||||
if (!mInitDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mMainThreadDemuxer);
|
||||
mMainThreadDemuxer->NotifyDataArrived(aLength, aOffset);
|
||||
|
||||
// Queue a task to notify our main demuxer.
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArgs<int32_t, uint64_t>(
|
||||
@ -1365,4 +1436,27 @@ MediaFormatReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int6
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::NotifyDataRemoved()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mDataRange = ByteInterval();
|
||||
mCachedTimeRangesStale = true;
|
||||
|
||||
if (!mInitDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mMainThreadDemuxer);
|
||||
mMainThreadDemuxer->NotifyDataRemoved();
|
||||
|
||||
// Queue a task to notify our main demuxer.
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArgs<int32_t, uint64_t>(
|
||||
this, &MediaFormatReader::NotifyDemuxer,
|
||||
0, 0);
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -26,6 +26,7 @@ namespace mozilla {
|
||||
class MediaFormatReader final : public MediaDecoderReader
|
||||
{
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
typedef media::Interval<int64_t> ByteInterval;
|
||||
|
||||
public:
|
||||
explicit MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
||||
@ -76,6 +77,7 @@ public:
|
||||
virtual void NotifyDataArrived(const char* aBuffer,
|
||||
uint32_t aLength,
|
||||
int64_t aOffset) override;
|
||||
virtual void NotifyDataRemoved() override;
|
||||
|
||||
virtual media::TimeIntervals GetBuffered() override;
|
||||
|
||||
@ -103,6 +105,9 @@ public:
|
||||
|
||||
private:
|
||||
bool InitDemuxer();
|
||||
// Notify the demuxer that new data has been received.
|
||||
// The next queued task calling GetBuffered() is guaranteed to have up to date
|
||||
// buffered ranges.
|
||||
void NotifyDemuxer(uint32_t aLength, int64_t aOffset);
|
||||
void ReturnOutput(MediaData* aData, TrackType aTrack);
|
||||
|
||||
@ -251,6 +256,13 @@ private:
|
||||
virtual void RejectPromise(MediaDecoderReader::NotDecodedReason aReason,
|
||||
const char* aMethodName) = 0;
|
||||
|
||||
void ResetDemuxer()
|
||||
{
|
||||
// Clear demuxer related data.
|
||||
mDemuxRequest.DisconnectIfExists();
|
||||
mTrackDemuxer->Reset();
|
||||
}
|
||||
|
||||
void ResetState()
|
||||
{
|
||||
MOZ_ASSERT(mOwner->OnTaskQueue());
|
||||
@ -304,7 +316,6 @@ private:
|
||||
DecoderDataWithPromise<VideoDataPromise> mVideo;
|
||||
|
||||
// Returns true when the decoder for this track needs input.
|
||||
// aDecoder.mMonitor must be locked.
|
||||
bool NeedInput(DecoderData& aDecoder);
|
||||
|
||||
DecoderData& GetDecoderData(TrackType aTrack);
|
||||
@ -389,9 +400,14 @@ private:
|
||||
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
||||
|
||||
// Main thread objects
|
||||
// Those are only used to calculate our buffered range on the main thread.
|
||||
// The cached buffered range is calculated one when required.
|
||||
nsRefPtr<MediaDataDemuxer> mMainThreadDemuxer;
|
||||
nsRefPtr<MediaTrackDemuxer> mAudioTrackDemuxer;
|
||||
nsRefPtr<MediaTrackDemuxer> mVideoTrackDemuxer;
|
||||
ByteInterval mDataRange;
|
||||
media::TimeIntervals mCachedTimeRanges;
|
||||
bool mCachedTimeRangesStale;
|
||||
|
||||
#if defined(READER_DORMANT_HEURISTIC)
|
||||
const bool mDormantEnabled;
|
||||
|
@ -12,6 +12,18 @@
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
class TimeIntervals;
|
||||
}
|
||||
}
|
||||
// CopyChooser specalization for nsTArray
|
||||
template<>
|
||||
struct nsTArray_CopyChooser<mozilla::media::TimeIntervals>
|
||||
{
|
||||
typedef nsTArray_CopyWithConstructors<mozilla::media::TimeIntervals> Type;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
|
@ -114,6 +114,14 @@ MP4Demuxer::NotifyDataArrived(uint32_t aLength, int64_t aOffset)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4Demuxer::NotifyDataRemoved()
|
||||
{
|
||||
for (uint32_t i = 0; i < mDemuxers.Length(); i++) {
|
||||
mDemuxers[i]->NotifyDataArrived();
|
||||
}
|
||||
}
|
||||
|
||||
UniquePtr<EncryptionInfo>
|
||||
MP4Demuxer::GetCrypto()
|
||||
{
|
||||
@ -143,6 +151,7 @@ MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent,
|
||||
uint32_t aTrackNumber)
|
||||
: mParent(aParent)
|
||||
, mStream(new mp4_demuxer::ResourceStream(mParent->mResource))
|
||||
, mNeedReIndex(true)
|
||||
, mMonitor("MP4TrackDemuxer")
|
||||
{
|
||||
mInfo = mParent->mMetadata->GetTrackInfo(aType, aTrackNumber);
|
||||
@ -168,6 +177,23 @@ MP4TrackDemuxer::GetInfo() const
|
||||
return mInfo->Clone();
|
||||
}
|
||||
|
||||
void
|
||||
MP4TrackDemuxer::EnsureUpToDateIndex()
|
||||
{
|
||||
if (!mNeedReIndex) {
|
||||
return;
|
||||
}
|
||||
AutoPinned<MediaResource> resource(mParent->mResource);
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mIndex->UpdateMoofIndex(byteRanges);
|
||||
mNeedReIndex = false;
|
||||
}
|
||||
|
||||
nsRefPtr<MP4TrackDemuxer::SeekPromise>
|
||||
MP4TrackDemuxer::Seek(media::TimeUnit aTime)
|
||||
{
|
||||
@ -182,6 +208,7 @@ MP4TrackDemuxer::Seek(media::TimeUnit aTime)
|
||||
if (mQueuedSample) {
|
||||
seekTime = mQueuedSample->mTime;
|
||||
}
|
||||
SetNextKeyFrameTime();
|
||||
|
||||
return SeekPromise::CreateAndResolve(media::TimeUnit::FromMicroseconds(seekTime), __func__);
|
||||
}
|
||||
@ -214,6 +241,17 @@ MP4TrackDemuxer::GetSamples(int32_t aNumSamples)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4TrackDemuxer::SetNextKeyFrameTime()
|
||||
{
|
||||
mNextKeyframeTime.reset();
|
||||
mp4_demuxer::Microseconds frameTime = mIterator->GetNextKeyframeTime();
|
||||
if (frameTime != -1) {
|
||||
mNextKeyframeTime.emplace(
|
||||
media::TimeUnit::FromMicroseconds(frameTime));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4TrackDemuxer::Reset()
|
||||
{
|
||||
@ -221,6 +259,7 @@ MP4TrackDemuxer::Reset()
|
||||
// TODO, Seek to first frame available, which isn't always 0.
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mIterator->Seek(0);
|
||||
SetNextKeyFrameTime();
|
||||
}
|
||||
|
||||
void
|
||||
@ -240,12 +279,7 @@ MP4TrackDemuxer::UpdateSamples(nsTArray<nsRefPtr<MediaRawData>>& aSamples)
|
||||
}
|
||||
if (mNextKeyframeTime.isNothing() ||
|
||||
aSamples.LastElement()->mTime >= mNextKeyframeTime.value().ToMicroseconds()) {
|
||||
mNextKeyframeTime.reset();
|
||||
mp4_demuxer::Microseconds frameTime = mIterator->GetNextKeyframeTime();
|
||||
if (frameTime != -1) {
|
||||
mNextKeyframeTime.emplace(
|
||||
media::TimeUnit::FromMicroseconds(frameTime));
|
||||
}
|
||||
SetNextKeyFrameTime();
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,6 +312,7 @@ MP4TrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
|
||||
mQueuedSample = sample;
|
||||
}
|
||||
}
|
||||
SetNextKeyFrameTime();
|
||||
if (found) {
|
||||
return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
|
||||
} else {
|
||||
@ -290,12 +325,14 @@ int64_t
|
||||
MP4TrackDemuxer::GetEvictionOffset(media::TimeUnit aTime)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return int64_t(mIndex->GetEvictionOffset(aTime.ToMicroseconds()));
|
||||
uint64_t offset = mIndex->GetEvictionOffset(aTime.ToMicroseconds());
|
||||
return int64_t(offset == std::numeric_limits<uint64_t>::max() ? 0 : offset);
|
||||
}
|
||||
|
||||
media::TimeIntervals
|
||||
MP4TrackDemuxer::GetBuffered()
|
||||
{
|
||||
EnsureUpToDateIndex();
|
||||
AutoPinned<MediaResource> resource(mParent->mResource);
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
@ -306,16 +343,9 @@ MP4TrackDemuxer::GetBuffered()
|
||||
nsTArray<mp4_demuxer::Interval<int64_t>> timeRanges;
|
||||
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
int64_t endComposition =
|
||||
mIndex->GetEndCompositionIfBuffered(byteRanges);
|
||||
|
||||
mIndex->ConvertByteRangesToTimeRanges(byteRanges, &timeRanges);
|
||||
if (endComposition) {
|
||||
mp4_demuxer::Interval<int64_t>::SemiNormalAppend(
|
||||
timeRanges, mp4_demuxer::Interval<int64_t>(endComposition, endComposition));
|
||||
}
|
||||
// convert timeRanges.
|
||||
media::TimeIntervals ranges;
|
||||
media::TimeIntervals ranges = media::TimeIntervals();
|
||||
for (size_t i = 0; i < timeRanges.Length(); i++) {
|
||||
ranges +=
|
||||
media::TimeInterval(media::TimeUnit::FromMicroseconds(timeRanges[i].start),
|
||||
@ -327,14 +357,7 @@ MP4TrackDemuxer::GetBuffered()
|
||||
void
|
||||
MP4TrackDemuxer::NotifyDataArrived()
|
||||
{
|
||||
AutoPinned<MediaResource> resource(mParent->mResource);
|
||||
nsTArray<MediaByteRange> byteRanges;
|
||||
nsresult rv = resource->GetCachedRanges(byteRanges);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mIndex->UpdateMoofIndex(byteRanges);
|
||||
mNeedReIndex = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
|
||||
virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
|
||||
|
||||
virtual void NotifyDataRemoved() override;
|
||||
|
||||
private:
|
||||
friend class MP4TrackDemuxer;
|
||||
nsRefPtr<MediaResource> mResource;
|
||||
@ -83,6 +85,8 @@ private:
|
||||
friend class MP4Demuxer;
|
||||
void NotifyDataArrived();
|
||||
void UpdateSamples(nsTArray<nsRefPtr<MediaRawData>>& aSamples);
|
||||
void EnsureUpToDateIndex();
|
||||
void SetNextKeyFrameTime();
|
||||
nsRefPtr<MP4Demuxer> mParent;
|
||||
nsRefPtr<mp4_demuxer::Index> mIndex;
|
||||
UniquePtr<mp4_demuxer::SampleIterator> mIterator;
|
||||
@ -91,6 +95,7 @@ private:
|
||||
Maybe<media::TimeUnit> mNextKeyframeTime;
|
||||
// Queued samples extracted by the demuxer, but not yet returned.
|
||||
nsRefPtr<MediaRawData> mQueuedSample;
|
||||
bool mNeedReIndex;
|
||||
|
||||
// We do not actually need a monitor, however MoofParser will assert
|
||||
// if a monitor isn't held.
|
||||
|
@ -709,3 +709,12 @@ TEST(IntervalSet, FooIntervalSet)
|
||||
EXPECT_EQ(Foo<int>(), is[0].mStart);
|
||||
EXPECT_EQ(Foo<int>(4,5,6), is[0].mEnd);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, StaticAssert)
|
||||
{
|
||||
typedef media::IntervalSet<int> IntIntervals;
|
||||
media::Interval<int> i;
|
||||
|
||||
static_assert(mozilla::IsSame<nsTArray_CopyChooser<IntIntervals>::Type, nsTArray_CopyWithConstructors<IntIntervals>>::value, "Must use copy constructor");
|
||||
static_assert(mozilla::IsSame<nsTArray_CopyChooser<media::TimeIntervals>::Type, nsTArray_CopyWithConstructors<media::TimeIntervals>>::value, "Must use copy constructor");
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "WebMBufferedParser.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mp4_demuxer/MoofParser.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "MediaData.h"
|
||||
@ -324,7 +325,13 @@ public:
|
||||
|
||||
mp4_demuxer::Interval<mp4_demuxer::Microseconds> compositionRange =
|
||||
mParser->GetCompositionRange(byteRanges);
|
||||
mResource->EvictData(mParser->mOffset, mParser->mOffset);
|
||||
|
||||
ErrorResult rv;
|
||||
mResource->EvictData(mParser->mOffset, mParser->mOffset, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compositionRange.IsNull()) {
|
||||
return false;
|
||||
|
@ -89,14 +89,15 @@ ResourceQueue::AppendItem(MediaLargeByteBuffer* aData)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ResourceQueue::Evict(uint64_t aOffset, uint32_t aSizeToEvict)
|
||||
ResourceQueue::Evict(uint64_t aOffset, uint32_t aSizeToEvict,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SBR_DEBUG("Evict(aOffset=%llu, aSizeToEvict=%u)",
|
||||
aOffset, aSizeToEvict);
|
||||
return EvictBefore(std::min(aOffset, mOffset + (uint64_t)aSizeToEvict));
|
||||
return EvictBefore(std::min(aOffset, mOffset + (uint64_t)aSizeToEvict), aRv);
|
||||
}
|
||||
|
||||
uint32_t ResourceQueue::EvictBefore(uint64_t aOffset)
|
||||
uint32_t ResourceQueue::EvictBefore(uint64_t aOffset, ErrorResult& aRv)
|
||||
{
|
||||
SBR_DEBUG("EvictBefore(%llu)", aOffset);
|
||||
uint32_t evicted = 0;
|
||||
@ -111,8 +112,12 @@ uint32_t ResourceQueue::EvictBefore(uint64_t aOffset)
|
||||
mOffset += offset;
|
||||
evicted += offset;
|
||||
nsRefPtr<MediaLargeByteBuffer> data = new MediaLargeByteBuffer;
|
||||
data->AppendElements(item->mData->Elements() + offset,
|
||||
item->mData->Length() - offset);
|
||||
if (!data->AppendElements(item->mData->Elements() + offset,
|
||||
item->mData->Length() - offset)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
item->mData = data;
|
||||
break;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
// A SourceBufferResource has a queue containing the data that is appended
|
||||
// to it. The queue holds instances of ResourceItem which is an array of the
|
||||
// bytes. Appending data to the SourceBufferResource pushes this onto the
|
||||
@ -47,9 +49,10 @@ public:
|
||||
|
||||
// Tries to evict at least aSizeToEvict from the queue up until
|
||||
// aOffset. Returns amount evicted.
|
||||
uint32_t Evict(uint64_t aOffset, uint32_t aSizeToEvict);
|
||||
uint32_t Evict(uint64_t aOffset, uint32_t aSizeToEvict,
|
||||
ErrorResult& aRv);
|
||||
|
||||
uint32_t EvictBefore(uint64_t aOffset);
|
||||
uint32_t EvictBefore(uint64_t aOffset, ErrorResult& aRv);
|
||||
|
||||
uint32_t EvictAll();
|
||||
|
||||
|
@ -174,12 +174,13 @@ SourceBufferResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCo
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SourceBufferResource::EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold)
|
||||
SourceBufferResource::EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SBR_DEBUG("EvictData(aPlaybackOffset=%llu,"
|
||||
"aThreshold=%u)", aPlaybackOffset, aThreshold);
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
uint32_t result = mInputBuffer.Evict(aPlaybackOffset, aThreshold);
|
||||
uint32_t result = mInputBuffer.Evict(aPlaybackOffset, aThreshold, aRv);
|
||||
if (result > 0) {
|
||||
// Wake up any waiting threads in case a ReadInternal call
|
||||
// is now invalid.
|
||||
@ -189,13 +190,13 @@ SourceBufferResource::EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold)
|
||||
}
|
||||
|
||||
void
|
||||
SourceBufferResource::EvictBefore(uint64_t aOffset)
|
||||
SourceBufferResource::EvictBefore(uint64_t aOffset, ErrorResult& aRv)
|
||||
{
|
||||
SBR_DEBUG("EvictBefore(aOffset=%llu)", aOffset);
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
// If aOffset is past the current playback offset we don't evict.
|
||||
if (aOffset < mOffset) {
|
||||
mInputBuffer.EvictBefore(aOffset);
|
||||
mInputBuffer.EvictBefore(aOffset, aRv);
|
||||
}
|
||||
// Wake up any waiting threads in case a ReadInternal call
|
||||
// is now invalid.
|
||||
|
@ -112,10 +112,11 @@ public:
|
||||
}
|
||||
// Remove data from resource if it holds more than the threshold
|
||||
// number of bytes. Returns amount evicted.
|
||||
uint32_t EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold);
|
||||
uint32_t EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Remove data from resource before the given offset.
|
||||
void EvictBefore(uint64_t aOffset);
|
||||
void EvictBefore(uint64_t aOffset, ErrorResult& aRv);
|
||||
|
||||
// Remove all data from the resource
|
||||
uint32_t EvictAll();
|
||||
|
@ -241,7 +241,7 @@ TrackBuffer::AppendData(MediaLargeByteBuffer* aData, int64_t aTimestampOffset)
|
||||
|
||||
// Tell our reader that we have more data to ensure that playback starts if
|
||||
// required when data is appended.
|
||||
mParentDecoder->GetReader()->MaybeNotifyHaveData();
|
||||
NotifyTimeRangesChanged();
|
||||
|
||||
mInitializationPromise.Resolve(gotMedia, __func__);
|
||||
return p;
|
||||
@ -263,11 +263,20 @@ TrackBuffer::AppendDataToCurrentResource(MediaLargeByteBuffer* aData, uint32_t a
|
||||
mCurrentDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData->Elements()),
|
||||
aData->Length(), appendOffset);
|
||||
mParentDecoder->NotifyBytesDownloaded();
|
||||
mParentDecoder->NotifyTimeRangesChanged();
|
||||
NotifyTimeRangesChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffer::NotifyTimeRangesChanged()
|
||||
{
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(mParentDecoder->GetReader(),
|
||||
&MediaSourceReader::NotifyTimeRangesChanged);
|
||||
mParentDecoder->GetReader()->GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
class DecoderSorter
|
||||
{
|
||||
public:
|
||||
@ -337,16 +346,23 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
toEvict -= decoders[i]->GetResource()->EvictAll();
|
||||
} else {
|
||||
int64_t playbackOffset =
|
||||
decoders[i]->ConvertToByteOffset(time.ToMicroseconds());
|
||||
decoders[i]->ConvertToByteOffset(time.ToSeconds());
|
||||
MSE_DEBUG("evicting some bufferedEnd=%f "
|
||||
"aPlaybackTime=%f time=%f, playbackOffset=%lld size=%lld",
|
||||
buffered.GetEnd().ToSeconds(), aPlaybackTime, time,
|
||||
playbackOffset, decoders[i]->GetResource()->GetSize());
|
||||
if (playbackOffset > 0) {
|
||||
ErrorResult rv;
|
||||
toEvict -= decoders[i]->GetResource()->EvictData(playbackOffset,
|
||||
playbackOffset);
|
||||
playbackOffset,
|
||||
rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
decoders[i]->GetReader()->NotifyDataRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,6 +384,7 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds(),
|
||||
aPlaybackTime, decoders[i]->GetResource()->GetSize());
|
||||
toEvict -= decoders[i]->GetResource()->EvictAll();
|
||||
decoders[i]->GetReader()->NotifyDataRemoved();
|
||||
}
|
||||
|
||||
// Evict all data from future decoders, starting furthest away from
|
||||
@ -413,6 +430,7 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
buffered.GetStart().ToSeconds(), buffered.GetEnd().ToSeconds(),
|
||||
aPlaybackTime, decoders[i]->GetResource()->GetSize());
|
||||
toEvict -= decoders[i]->GetResource()->EvictAll();
|
||||
decoders[i]->GetReader()->NotifyDataRemoved();
|
||||
}
|
||||
|
||||
RemoveEmptyDecoders(decoders);
|
||||
@ -429,6 +447,10 @@ TrackBuffer::EvictData(double aPlaybackTime,
|
||||
}
|
||||
}
|
||||
|
||||
if (evicted) {
|
||||
NotifyTimeRangesChanged();
|
||||
}
|
||||
|
||||
return evicted;
|
||||
}
|
||||
|
||||
@ -490,9 +512,16 @@ TrackBuffer::EvictBefore(double aTime)
|
||||
if (endOffset > 0) {
|
||||
MSE_DEBUG("decoder=%u offset=%lld",
|
||||
i, endOffset);
|
||||
mInitializedDecoders[i]->GetResource()->EvictBefore(endOffset);
|
||||
ErrorResult rv;
|
||||
mInitializedDecoders[i]->GetResource()->EvictBefore(endOffset, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return;
|
||||
}
|
||||
mInitializedDecoders[i]->GetReader()->NotifyDataRemoved();
|
||||
}
|
||||
}
|
||||
NotifyTimeRangesChanged();
|
||||
}
|
||||
|
||||
media::TimeIntervals
|
||||
@ -788,7 +817,7 @@ TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
|
||||
|
||||
// Tell our reader that we have more data to ensure that playback starts if
|
||||
// required when data is appended.
|
||||
mParentDecoder->GetReader()->MaybeNotifyHaveData();
|
||||
NotifyTimeRangesChanged();
|
||||
|
||||
MSE_DEBUG("Reader %p activated",
|
||||
aDecoder->GetReader());
|
||||
@ -830,7 +859,7 @@ TrackBuffer::RegisterDecoder(SourceBufferDecoder* aDecoder)
|
||||
return false;
|
||||
}
|
||||
mInitializedDecoders.AppendElement(aDecoder);
|
||||
mParentDecoder->NotifyTimeRangesChanged();
|
||||
NotifyTimeRangesChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1086,9 +1115,15 @@ TrackBuffer::RangeRemoval(media::TimeUnit aStart,
|
||||
buffered.GetEnd().ToSeconds(), offset,
|
||||
decoders[i]->GetResource()->GetSize());
|
||||
if (offset > 0) {
|
||||
decoders[i]->GetResource()->EvictData(offset, offset);
|
||||
ErrorResult rv;
|
||||
decoders[i]->GetResource()->EvictData(offset, offset, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
decoders[i]->GetReader()->NotifyDataRemoved();
|
||||
}
|
||||
} else {
|
||||
// Only trimming existing buffers.
|
||||
@ -1099,11 +1134,13 @@ TrackBuffer::RangeRemoval(media::TimeUnit aStart,
|
||||
} else {
|
||||
decoders[i]->Trim(aStart.ToMicroseconds());
|
||||
}
|
||||
decoders[i]->GetReader()->NotifyDataRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
RemoveEmptyDecoders(decoders);
|
||||
|
||||
NotifyTimeRangesChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,8 @@ private:
|
||||
// data is appended to the current decoder's SourceBufferResource.
|
||||
bool AppendDataToCurrentResource(MediaLargeByteBuffer* aData,
|
||||
uint32_t aDuration /* microseconds */);
|
||||
// Queue on the parent's decoder task queue a call to NotifyTimeRangesChanged.
|
||||
void NotifyTimeRangesChanged();
|
||||
|
||||
// Queue execution of InitializeDecoder on mTaskQueue.
|
||||
bool QueueInitializeDecoder(SourceBufferDecoder* aDecoder);
|
||||
|
@ -74,7 +74,7 @@ SharedDecoderManager::SharedDecoderManager()
|
||||
, mActiveProxy(nullptr)
|
||||
, mActiveCallback(nullptr)
|
||||
, mWaitForInternalDrain(false)
|
||||
, mMonitor("SharedDecoderProxy")
|
||||
, mMonitor("SharedDecoderManager")
|
||||
, mDecoderReleasedResources(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread()); // taskqueue must be created on main thread.
|
||||
@ -163,16 +163,15 @@ void
|
||||
SharedDecoderManager::SetIdle(MediaDataDecoder* aProxy)
|
||||
{
|
||||
if (aProxy && mActiveProxy == aProxy) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mWaitForInternalDrain = true;
|
||||
nsresult rv;
|
||||
{
|
||||
// We don't want to hold the lock while calling Drain() has some
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mWaitForInternalDrain = true;
|
||||
// We don't want to hold the lock while calling Drain() as some
|
||||
// platform implementations call DrainComplete() immediately.
|
||||
MonitorAutoUnlock mon(mMonitor);
|
||||
rv = mActiveProxy->Drain();
|
||||
}
|
||||
nsresult rv = mActiveProxy->Drain();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
while (mWaitForInternalDrain) {
|
||||
mon.Wait();
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ private:
|
||||
SharedDecoderProxy* mActiveProxy;
|
||||
MediaDataDecoderCallback* mActiveCallback;
|
||||
nsAutoPtr<MediaDataDecoderCallback> mCallback;
|
||||
// access protected by mMonitor
|
||||
bool mWaitForInternalDrain;
|
||||
Monitor mMonitor;
|
||||
bool mDecoderReleasedResources;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "MediaInfo.h"
|
||||
|
||||
#include "FFmpegH264Decoder.h"
|
||||
#include "FFmpegLog.h"
|
||||
|
||||
#define GECKO_FRAME_TYPE 0x00093CC0
|
||||
|
||||
@ -49,6 +50,20 @@ FFmpegH264Decoder<LIBAV_VER>::Init()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int64_t
|
||||
FFmpegH264Decoder<LIBAV_VER>::GetPts(const AVPacket& packet)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_MAJOR == 53
|
||||
if (mFrame->pkt_pts == 0) {
|
||||
return mFrame->pkt_dts;
|
||||
} else {
|
||||
return mFrame->pkt_pts;
|
||||
}
|
||||
#else
|
||||
return mFrame->pkt_pts;
|
||||
#endif
|
||||
}
|
||||
|
||||
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
|
||||
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
|
||||
{
|
||||
@ -68,10 +83,19 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
|
||||
return DecodeResult::DECODE_ERROR;
|
||||
}
|
||||
|
||||
// Required with old version of FFmpeg/LibAV
|
||||
mFrame->reordered_opaque = AV_NOPTS_VALUE;
|
||||
|
||||
int decoded;
|
||||
int bytesConsumed =
|
||||
avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet);
|
||||
|
||||
FFMPEG_LOG("DoDecodeFrame:decode_video: rv=%d decoded=%d "
|
||||
"(Input: pts(%lld) dts(%lld) Output: pts(%lld) "
|
||||
"opaque(%lld) pkt_pts(%lld) pkt_dts(%lld))",
|
||||
bytesConsumed, decoded, packet.pts, packet.dts, mFrame->pts,
|
||||
mFrame->reordered_opaque, mFrame->pkt_pts, mFrame->pkt_dts);
|
||||
|
||||
if (bytesConsumed < 0) {
|
||||
NS_WARNING("FFmpeg video decoder error.");
|
||||
mCallback->Error();
|
||||
@ -80,6 +104,10 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
|
||||
|
||||
// If we've decoded a frame then we need to output it
|
||||
if (decoded) {
|
||||
int64_t pts = GetPts(packet);
|
||||
FFMPEG_LOG("Got one frame output with pts=%lld opaque=%lld",
|
||||
pts, mCodecContext->reordered_opaque);
|
||||
|
||||
VideoInfo info;
|
||||
info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight);
|
||||
|
||||
@ -105,7 +133,7 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
|
||||
nsRefPtr<VideoData> v = VideoData::Create(info,
|
||||
mImageContainer,
|
||||
aSample->mOffset,
|
||||
mFrame->pkt_pts,
|
||||
pts,
|
||||
aSample->mDuration,
|
||||
b,
|
||||
aSample->mKeyframe,
|
||||
|
@ -59,6 +59,7 @@ private:
|
||||
|
||||
static int AllocateBufferCb(AVCodecContext* aCodecContext, AVFrame* aFrame);
|
||||
static void ReleaseBufferCb(AVCodecContext* aCodecContext, AVFrame* aFrame);
|
||||
int64_t GetPts(const AVPacket& packet);
|
||||
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<ImageContainer> mImageContainer;
|
||||
|
@ -205,6 +205,7 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
|
||||
aOutData = nullptr;
|
||||
RefPtr<IMFSample> sample;
|
||||
HRESULT hr;
|
||||
int typeChangeCount = 0;
|
||||
while (true) {
|
||||
hr = mDecoder->Output(&sample);
|
||||
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
|
||||
@ -213,6 +214,11 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
|
||||
if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
|
||||
hr = UpdateOutputType();
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
// Catch infinite loops, but some decoders perform at least 2 stream
|
||||
// changes on consecutive calls, so be permissive.
|
||||
// 100 is arbitrarily > 2.
|
||||
NS_ENSURE_TRUE(typeChangeCount < 100, MF_E_TRANSFORM_STREAM_CHANGE);
|
||||
++typeChangeCount;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -482,6 +482,7 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
||||
RefPtr<IMFSample> sample;
|
||||
HRESULT hr;
|
||||
aOutData = nullptr;
|
||||
int typeChangeCount = 0;
|
||||
|
||||
// Loop until we decode a sample, or an unexpected error that we can't
|
||||
// handle occurs.
|
||||
@ -497,7 +498,12 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
||||
MOZ_ASSERT(!sample);
|
||||
hr = ConfigureVideoFrameGeometry();
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
// Catch infinite loops, but some decoders perform at least 2 stream
|
||||
// changes on consecutive calls, so be permissive.
|
||||
// 100 is arbitrarily > 2.
|
||||
NS_ENSURE_TRUE(typeChangeCount < 100, MF_E_TRANSFORM_STREAM_CHANGE);
|
||||
// Loop back and try decoding again...
|
||||
++typeChangeCount;
|
||||
continue;
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
|
BIN
dom/media/test/bipbop-lateaudio.mp4
Normal file
BIN
dom/media/test/bipbop-lateaudio.mp4
Normal file
Binary file not shown.
1
dom/media/test/bipbop-lateaudio.mp4^headers^
Normal file
1
dom/media/test/bipbop-lateaudio.mp4^headers^
Normal file
@ -0,0 +1 @@
|
||||
Cache-Control: no-store
|
@ -227,6 +227,9 @@ var gPlayTests = [
|
||||
{ name:"test-8-7.1.opus", type:"audio/ogg; codecs=opus", duration:13.478 },
|
||||
|
||||
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
|
||||
// Test playback of a MP4 file with a non-zero start time (and audio starting
|
||||
// a second later).
|
||||
{ name:"bipbop-lateaudio.mp4", type:"video/mp4", duration:2.401 },
|
||||
|
||||
{ name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
|
||||
{ name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
|
||||
|
@ -66,6 +66,8 @@ support-files =
|
||||
bipbop-cenc1-video1.m4s
|
||||
bipbop-cenc1-video2.m4s
|
||||
bipbop-cenc1-videoinit.mp4
|
||||
bipbop-lateaudio.mp4
|
||||
bipbop-lateaudio.mp4^headers^
|
||||
bogus.duh
|
||||
bogus.ogv
|
||||
bogus.ogv^headers^
|
||||
|
@ -32,6 +32,7 @@
|
||||
var audiotrack;
|
||||
return navigator.mediaDevices.getUserMedia({video:true, audio:true, fake:true})
|
||||
.then(newStream => {
|
||||
window.grip = newStream;
|
||||
newTrack = newStream.getVideoTracks()[0];
|
||||
audiotrack = newStream.getAudioTracks()[0];
|
||||
isnot(newTrack, sender.track, "replacing with a different track");
|
||||
|
@ -599,13 +599,17 @@ MobileMessageManager::DispatchTrustedDeletedEventToSelf(nsISupports* aDeletedInf
|
||||
uint32_t msgIdLength = info->GetData().deletedMessageIds().Length();
|
||||
if (msgIdLength) {
|
||||
Sequence<int32_t>& deletedMsgIds = init.mDeletedMessageIds.SetValue();
|
||||
deletedMsgIds.AppendElements(info->GetData().deletedMessageIds());
|
||||
if (!deletedMsgIds.AppendElements(info->GetData().deletedMessageIds())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t threadIdLength = info->GetData().deletedThreadIds().Length();
|
||||
if (threadIdLength) {
|
||||
Sequence<uint64_t>& deletedThreadIds = init.mDeletedThreadIds.SetValue();
|
||||
deletedThreadIds.AppendElements(info->GetData().deletedThreadIds());
|
||||
if (!deletedThreadIds.AppendElements(info->GetData().deletedThreadIds())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<MozMessageDeletedEvent> event =
|
||||
|
@ -92,7 +92,7 @@ interface CanvasRenderingContext2D {
|
||||
void fill(Path2D path, optional CanvasWindingRule winding = "nonzero");
|
||||
void stroke();
|
||||
void stroke(Path2D path);
|
||||
[Pref="canvas.focusring.enabled"] void drawFocusIfNeeded(Element element);
|
||||
[Pref="canvas.focusring.enabled", Throws] void drawFocusIfNeeded(Element element);
|
||||
// NOT IMPLEMENTED void drawSystemFocusRing(Path path, HTMLElement element);
|
||||
[Pref="canvas.customfocusring.enabled"] boolean drawCustomFocusRing(Element element);
|
||||
// NOT IMPLEMENTED boolean drawCustomFocusRing(Path path, HTMLElement element);
|
||||
@ -246,7 +246,7 @@ interface CanvasDrawingStyles {
|
||||
attribute double miterLimit; // (default 10)
|
||||
|
||||
// dashed lines
|
||||
[LenientFloat] void setLineDash(sequence<double> segments); // default empty
|
||||
[LenientFloat, Throws] void setLineDash(sequence<double> segments); // default empty
|
||||
sequence<double> getLineDash();
|
||||
[LenientFloat] attribute double lineDashOffset;
|
||||
|
||||
|
@ -43,7 +43,7 @@ interface MutationObserver {
|
||||
void disconnect();
|
||||
sequence<MutationRecord> takeRecords();
|
||||
|
||||
[ChromeOnly]
|
||||
[ChromeOnly, Throws]
|
||||
sequence<MutationObservingInfo?> getObservingInfo();
|
||||
[ChromeOnly]
|
||||
readonly attribute MutationCallback mutationCallback;
|
||||
|
@ -30,13 +30,13 @@ partial interface Performance {
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/performance-timeline/#sec-window.performance-attribute
|
||||
[Exposed=Window]
|
||||
[Exposed=(Window,Worker)]
|
||||
partial interface Performance {
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
PerformanceEntryList getEntries();
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
PerformanceEntryList getEntriesByType(DOMString entryType);
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
PerformanceEntryList getEntriesByName(DOMString name, optional DOMString
|
||||
entryType);
|
||||
};
|
||||
@ -44,11 +44,11 @@ partial interface Performance {
|
||||
// http://www.w3.org/TR/resource-timing/#extensions-performance-interface
|
||||
[Exposed=Window]
|
||||
partial interface Performance {
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
void clearResourceTimings();
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
void setResourceTimingBufferSize(unsigned long maxSize);
|
||||
[Pref="dom.enable_resource_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
attribute EventHandler onresourcetimingbufferfull;
|
||||
};
|
||||
|
||||
@ -60,14 +60,14 @@ partial interface Performance {
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/user-timing/
|
||||
[Exposed=Window]
|
||||
[Exposed=(Window,Worker)]
|
||||
partial interface Performance {
|
||||
[Pref="dom.enable_user_timing", Throws]
|
||||
[Func="nsPerformance::IsEnabled", Throws]
|
||||
void mark(DOMString markName);
|
||||
[Pref="dom.enable_user_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
void clearMarks(optional DOMString markName);
|
||||
[Pref="dom.enable_user_timing", Throws]
|
||||
[Func="nsPerformance::IsEnabled", Throws]
|
||||
void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);
|
||||
[Pref="dom.enable_user_timing"]
|
||||
[Func="nsPerformance::IsEnabled"]
|
||||
void clearMeasures(optional DOMString measureName);
|
||||
};
|
||||
|
@ -10,6 +10,7 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface PerformanceEntry
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
|
@ -7,6 +7,7 @@
|
||||
* http://www.w3.org/TR/user-timing/#performancemark
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface PerformanceMark : PerformanceEntry
|
||||
{
|
||||
};
|
||||
|
@ -7,6 +7,7 @@
|
||||
* http://www.w3.org/TR/user-timing/#performancemeasure
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface PerformanceMeasure : PerformanceEntry
|
||||
{
|
||||
};
|
||||
|
@ -329,9 +329,14 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
void framebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
|
||||
|
||||
[Throws]
|
||||
void invalidateFramebuffer(GLenum target, sequence<GLenum> attachments);
|
||||
|
||||
[Throws]
|
||||
void invalidateSubFramebuffer (GLenum target, sequence<GLenum> attachments,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
|
||||
void readBuffer(GLenum src);
|
||||
|
||||
/* Renderbuffer objects */
|
||||
|
@ -11,11 +11,6 @@
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Performance, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Performance, Release)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(Performance)
|
||||
|
||||
Performance::Performance(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
{
|
||||
@ -33,7 +28,7 @@ Performance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
return PerformanceBinding_workers::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
double
|
||||
DOMHighResTimeStamp
|
||||
Performance::Now() const
|
||||
{
|
||||
TimeDuration duration =
|
||||
@ -41,4 +36,45 @@ Performance::Now() const
|
||||
return duration.ToMilliseconds();
|
||||
}
|
||||
|
||||
// To be removed once bug 1124165 lands
|
||||
bool
|
||||
Performance::IsPerformanceTimingAttribute(const nsAString& aName)
|
||||
{
|
||||
// In workers we just support navigationStart.
|
||||
return aName.EqualsASCII("navigationStart");
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
Performance::GetPerformanceTimingFromString(const nsAString& aProperty)
|
||||
{
|
||||
if (!IsPerformanceTimingAttribute(aProperty)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aProperty.EqualsLiteral("navigationStart")) {
|
||||
return mWorkerPrivate->NowBaseTimeHighRes();
|
||||
}
|
||||
|
||||
MOZ_CRASH("IsPerformanceTimingAttribute and GetPerformanceTimingFromString are out of sync");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
Performance::DeltaFromNavigationStart(DOMHighResTimeStamp aTime)
|
||||
{
|
||||
if (aTime == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return aTime - mWorkerPrivate->NowBaseTimeHighRes();
|
||||
}
|
||||
|
||||
void
|
||||
Performance::DispatchBufferFullEvent()
|
||||
{
|
||||
// This method is needed just for InsertResourceEntry, but this method is not
|
||||
// exposed to workers.
|
||||
MOZ_CRASH("This should not be called.");
|
||||
}
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -12,17 +12,15 @@
|
||||
#include "Workers.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsPerformance.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class WorkerPrivate;
|
||||
|
||||
class Performance final : public nsWrapperCache
|
||||
class Performance final : public PerformanceBase
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Performance)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Performance)
|
||||
|
||||
explicit Performance(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
private:
|
||||
@ -31,18 +29,32 @@ private:
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
public:
|
||||
virtual JSObject*
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsISupports*
|
||||
GetParentObject() const
|
||||
// WebIDL (public APIs)
|
||||
DOMHighResTimeStamp Now() const override;
|
||||
|
||||
using PerformanceBase::Mark;
|
||||
using PerformanceBase::ClearMarks;
|
||||
using PerformanceBase::Measure;
|
||||
using PerformanceBase::ClearMeasures;
|
||||
|
||||
private:
|
||||
nsISupports* GetAsISupports() override
|
||||
{
|
||||
// There's only one global on a worker, so we don't need to specify.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// WebIDL (public APIs)
|
||||
double Now() const;
|
||||
void DispatchBufferFullEvent() override;
|
||||
|
||||
bool IsPerformanceTimingAttribute(const nsAString& aName) override;
|
||||
|
||||
DOMHighResTimeStamp
|
||||
GetPerformanceTimingFromString(const nsAString& aTimingName) override;
|
||||
|
||||
DOMHighResTimeStamp
|
||||
DeltaFromNavigationStart(DOMHighResTimeStamp aTime) override;
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIHttpHeaderVisitor.h"
|
||||
#include "nsIJARChannel.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsIUploadChannel2.h"
|
||||
@ -2594,60 +2595,70 @@ public:
|
||||
rv = uri->GetSpec(mSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||
NS_ENSURE_TRUE(httpChannel, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
rv = httpChannel->GetRequestMethod(mMethod);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t loadFlags;
|
||||
rv = channel->GetLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
|
||||
NS_ENSURE_TRUE(internalChannel, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
uint32_t mode;
|
||||
internalChannel->GetCorsMode(&mode);
|
||||
switch (mode) {
|
||||
case nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN:
|
||||
mRequestMode = RequestMode::Same_origin;
|
||||
break;
|
||||
case nsIHttpChannelInternal::CORS_MODE_NO_CORS:
|
||||
mRequestMode = RequestMode::No_cors;
|
||||
break;
|
||||
case nsIHttpChannelInternal::CORS_MODE_CORS:
|
||||
case nsIHttpChannelInternal::CORS_MODE_CORS_WITH_FORCED_PREFLIGHT:
|
||||
mRequestMode = RequestMode::Cors;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected CORS mode");
|
||||
}
|
||||
|
||||
if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
|
||||
mRequestCredentials = RequestCredentials::Omit;
|
||||
} else {
|
||||
bool includeCrossOrigin;
|
||||
internalChannel->GetCorsIncludeCredentials(&includeCrossOrigin);
|
||||
if (includeCrossOrigin) {
|
||||
mRequestCredentials = RequestCredentials::Include;
|
||||
}
|
||||
}
|
||||
|
||||
rv = httpChannel->VisitRequestHeaders(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mContentPolicyType = loadInfo->GetContentPolicyType();
|
||||
|
||||
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
|
||||
if (uploadChannel) {
|
||||
MOZ_ASSERT(!mUploadStream);
|
||||
rv = uploadChannel->CloneUploadStream(getter_AddRefs(mUploadStream));
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||
if (httpChannel) {
|
||||
rv = httpChannel->GetRequestMethod(mMethod);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
|
||||
NS_ENSURE_TRUE(internalChannel, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
uint32_t mode;
|
||||
internalChannel->GetCorsMode(&mode);
|
||||
switch (mode) {
|
||||
case nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN:
|
||||
mRequestMode = RequestMode::Same_origin;
|
||||
break;
|
||||
case nsIHttpChannelInternal::CORS_MODE_NO_CORS:
|
||||
mRequestMode = RequestMode::No_cors;
|
||||
break;
|
||||
case nsIHttpChannelInternal::CORS_MODE_CORS:
|
||||
case nsIHttpChannelInternal::CORS_MODE_CORS_WITH_FORCED_PREFLIGHT:
|
||||
mRequestMode = RequestMode::Cors;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected CORS mode");
|
||||
}
|
||||
|
||||
if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
|
||||
mRequestCredentials = RequestCredentials::Omit;
|
||||
} else {
|
||||
bool includeCrossOrigin;
|
||||
internalChannel->GetCorsIncludeCredentials(&includeCrossOrigin);
|
||||
if (includeCrossOrigin) {
|
||||
mRequestCredentials = RequestCredentials::Include;
|
||||
}
|
||||
}
|
||||
|
||||
rv = httpChannel->VisitRequestHeaders(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
|
||||
if (uploadChannel) {
|
||||
MOZ_ASSERT(!mUploadStream);
|
||||
rv = uploadChannel->CloneUploadStream(getter_AddRefs(mUploadStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
|
||||
// If it is not an HTTP channel it must be a JAR one.
|
||||
NS_ENSURE_TRUE(jarChannel, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
mMethod = "GET";
|
||||
|
||||
if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
|
||||
mRequestCredentials = RequestCredentials::Omit;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2700,7 +2700,8 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
||||
mParentStatus(Pending), mParentFrozen(false),
|
||||
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
|
||||
mWorkerType(aWorkerType),
|
||||
mCreationTimeStamp(TimeStamp::Now())
|
||||
mCreationTimeStamp(TimeStamp::Now()),
|
||||
mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC)
|
||||
{
|
||||
MOZ_ASSERT_IF(!IsDedicatedWorker(),
|
||||
!aSharedWorkerName.IsVoid() && NS_IsMainThread());
|
||||
@ -2722,6 +2723,7 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
||||
|
||||
MOZ_ASSERT(IsDedicatedWorker());
|
||||
mNowBaseTimeStamp = aParent->NowBaseTimeStamp();
|
||||
mNowBaseTimeHighRes = aParent->NowBaseTimeHighRes();
|
||||
}
|
||||
else {
|
||||
AssertIsOnMainThread();
|
||||
@ -2732,8 +2734,11 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
||||
mLoadInfo.mWindow->GetPerformance()) {
|
||||
mNowBaseTimeStamp = mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
|
||||
GetNavigationStartTimeStamp();
|
||||
mNowBaseTimeHighRes = mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
|
||||
GetNavigationStartHighRes();
|
||||
} else {
|
||||
mNowBaseTimeStamp = CreationTimeStamp();
|
||||
mNowBaseTimeHighRes = CreationTimeHighRes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,9 @@ private:
|
||||
bool mMainThreadObjectsForgotten;
|
||||
WorkerType mWorkerType;
|
||||
TimeStamp mCreationTimeStamp;
|
||||
DOMHighResTimeStamp mCreationTimeHighRes;
|
||||
TimeStamp mNowBaseTimeStamp;
|
||||
DOMHighResTimeStamp mNowBaseTimeHighRes;
|
||||
|
||||
protected:
|
||||
// The worker is owned by its thread, which is represented here. This is set
|
||||
@ -543,11 +545,21 @@ public:
|
||||
return mCreationTimeStamp;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp CreationTimeHighRes() const
|
||||
{
|
||||
return mCreationTimeHighRes;
|
||||
}
|
||||
|
||||
TimeStamp NowBaseTimeStamp() const
|
||||
{
|
||||
return mNowBaseTimeStamp;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp NowBaseTimeHighRes() const
|
||||
{
|
||||
return mNowBaseTimeHighRes;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
GetPrincipal() const
|
||||
{
|
||||
|
@ -101,6 +101,8 @@ support-files =
|
||||
bug1132395_sharedWorker.js
|
||||
bug1132924_worker.js
|
||||
empty.html
|
||||
worker_performance_user_timing.js
|
||||
sharedworker_performance_user_timing.js
|
||||
|
||||
[test_404.html]
|
||||
[test_atob.html]
|
||||
@ -203,3 +205,5 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
|
||||
[test_consoleAndBlobs.html]
|
||||
[test_bug1132395.html]
|
||||
[test_bug1132924.html]
|
||||
[test_performance_user_timing.html]
|
||||
[test_sharedWorker_performance_user_timing.html]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user