mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
c461a4a6c1
@ -55,7 +55,7 @@
|
||||
@RESPATH@/browser/@PREF_DIR@/firefox-l10n.js
|
||||
@RESPATH@/browser/searchplugins/*
|
||||
#ifdef XP_WIN32
|
||||
@RESPATH@/uninstall/helper.exe
|
||||
@BINPATH@/uninstall/helper.exe
|
||||
#endif
|
||||
#ifdef MOZ_UPDATER
|
||||
@RESPATH@/update.locale
|
||||
|
@ -2066,7 +2066,7 @@ nsDOMWindowUtils::GetFullZoom(float* aFullZoom)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aFullZoom = presContext->DeviceContext()->GetPixelScale();
|
||||
*aFullZoom = presContext->DeviceContext()->GetFullZoom();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -6370,7 +6370,7 @@ nsGlobalWindow::Confirm(const nsAString& aString, bool* aReturn)
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
nsGlobalWindow::Fetch(const RequestOrScalarValueString& aInput,
|
||||
nsGlobalWindow::Fetch(const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
return FetchRequest(this, aInput, aInit, aRv);
|
||||
|
@ -110,7 +110,7 @@ class Navigator;
|
||||
class OwningExternalOrWindowProxy;
|
||||
class Promise;
|
||||
struct RequestInit;
|
||||
class RequestOrScalarValueString;
|
||||
class RequestOrUSVString;
|
||||
class Selection;
|
||||
class SpeechSynthesis;
|
||||
class WakeLock;
|
||||
@ -857,7 +857,7 @@ public:
|
||||
void Alert(mozilla::ErrorResult& aError);
|
||||
void Alert(const nsAString& aMessage, mozilla::ErrorResult& aError);
|
||||
bool Confirm(const nsAString& aMessage, mozilla::ErrorResult& aError);
|
||||
already_AddRefed<mozilla::dom::Promise> Fetch(const mozilla::dom::RequestOrScalarValueString& aInput,
|
||||
already_AddRefed<mozilla::dom::Promise> Fetch(const mozilla::dom::RequestOrUSVString& aInput,
|
||||
const mozilla::dom::RequestInit& aInit,
|
||||
mozilla::ErrorResult& aRv);
|
||||
void Prompt(const nsAString& aMessage, const nsAString& aInitial,
|
||||
|
@ -2142,7 +2142,7 @@ NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
|
||||
|
||||
|
||||
template<typename T> static void
|
||||
NormalizeScalarValueStringInternal(JSContext* aCx, T& aString)
|
||||
NormalizeUSVStringInternal(JSContext* aCx, T& aString)
|
||||
{
|
||||
char16_t* start = aString.BeginWriting();
|
||||
// Must use const here because we can't pass char** to UTF16CharEnumerator as
|
||||
@ -2159,15 +2159,15 @@ NormalizeScalarValueStringInternal(JSContext* aCx, T& aString)
|
||||
}
|
||||
|
||||
void
|
||||
NormalizeScalarValueString(JSContext* aCx, nsAString& aString)
|
||||
NormalizeUSVString(JSContext* aCx, nsAString& aString)
|
||||
{
|
||||
NormalizeScalarValueStringInternal(aCx, aString);
|
||||
NormalizeUSVStringInternal(aCx, aString);
|
||||
}
|
||||
|
||||
void
|
||||
NormalizeScalarValueString(JSContext* aCx, binding_detail::FakeString& aString)
|
||||
NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString)
|
||||
{
|
||||
NormalizeScalarValueStringInternal(aCx, aString);
|
||||
NormalizeUSVStringInternal(aCx, aString);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1923,10 +1923,10 @@ ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
|
||||
}
|
||||
|
||||
void
|
||||
NormalizeScalarValueString(JSContext* aCx, nsAString& aString);
|
||||
NormalizeUSVString(JSContext* aCx, nsAString& aString);
|
||||
|
||||
void
|
||||
NormalizeScalarValueString(JSContext* aCx, binding_detail::FakeString& aString);
|
||||
NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString);
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
|
@ -4837,7 +4837,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
declArgs=declArgs,
|
||||
holderArgs=holderArgs)
|
||||
|
||||
if type.isDOMString() or type.isScalarValueString():
|
||||
if type.isDOMString() or type.isUSVString():
|
||||
assert not isEnforceRange and not isClamp
|
||||
|
||||
treatAs = {
|
||||
@ -4856,8 +4856,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
|
||||
def getConversionCode(varName):
|
||||
normalizeCode = ""
|
||||
if type.isScalarValueString():
|
||||
normalizeCode = "NormalizeScalarValueString(cx, %s);\n" % varName
|
||||
if type.isUSVString():
|
||||
normalizeCode = "NormalizeUSVString(cx, %s);\n" % varName
|
||||
|
||||
conversionCode = (
|
||||
"if (!ConvertJSValueToString(cx, ${val}, %s, %s, %s)) {\n"
|
||||
@ -5797,7 +5797,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
wrappingCode += wrapAndSetPtr(wrap, failed)
|
||||
return (wrappingCode, False)
|
||||
|
||||
if type.isDOMString() or type.isScalarValueString():
|
||||
if type.isDOMString() or type.isUSVString():
|
||||
if type.nullable():
|
||||
return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
|
||||
else:
|
||||
@ -6077,7 +6077,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
|
||||
if returnType.nullable():
|
||||
result = CGTemplatedType("Nullable", result)
|
||||
return result, None, None, None, None
|
||||
if returnType.isDOMString() or returnType.isScalarValueString():
|
||||
if returnType.isDOMString() or returnType.isUSVString():
|
||||
if isMember:
|
||||
return CGGeneric("nsString"), "ref", None, None, None
|
||||
return CGGeneric("DOMString"), "ref", None, None, None
|
||||
@ -8488,7 +8488,7 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
|
||||
typeName = CGGeneric(type.name)
|
||||
return CGWrapper(typeName, post=" const &")
|
||||
|
||||
if type.isDOMString() or type.isScalarValueString():
|
||||
if type.isDOMString() or type.isUSVString():
|
||||
return CGGeneric("const nsAString&")
|
||||
|
||||
if type.isByteString():
|
||||
@ -12467,7 +12467,7 @@ class CGNativeMember(ClassMethod):
|
||||
return (result.define(),
|
||||
"%s(%s)" % (result.define(), defaultReturnArg),
|
||||
"return ${declName};\n")
|
||||
if type.isDOMString() or type.isScalarValueString():
|
||||
if type.isDOMString() or type.isUSVString():
|
||||
if isMember:
|
||||
# No need for a third element in the isMember case
|
||||
return "nsString", None, None
|
||||
@ -12587,7 +12587,7 @@ class CGNativeMember(ClassMethod):
|
||||
def getArgs(self, returnType, argList):
|
||||
args = [self.getArg(arg) for arg in argList]
|
||||
# Now the outparams
|
||||
if returnType.isDOMString() or returnType.isScalarValueString():
|
||||
if returnType.isDOMString() or returnType.isUSVString():
|
||||
args.append(Argument("nsString&", "aRetVal"))
|
||||
elif returnType.isByteString():
|
||||
args.append(Argument("nsCString&", "aRetVal"))
|
||||
@ -12714,7 +12714,7 @@ class CGNativeMember(ClassMethod):
|
||||
# Unroll for the name, in case we're nullable.
|
||||
return type.unroll().name, True, True
|
||||
|
||||
if type.isDOMString() or type.isScalarValueString():
|
||||
if type.isDOMString() or type.isUSVString():
|
||||
if isMember:
|
||||
declType = "nsString"
|
||||
else:
|
||||
@ -14587,7 +14587,7 @@ class CGEventGetter(CGNativeMember):
|
||||
memberName = CGDictionary.makeMemberName(self.member.identifier.name)
|
||||
if (type.isPrimitive() and type.tag() in builtinNames) or type.isEnum() or type.isGeckoInterface():
|
||||
return "return " + memberName + ";\n"
|
||||
if type.isDOMString() or type.isByteString() or type.isScalarValueString():
|
||||
if type.isDOMString() or type.isByteString() or type.isUSVString():
|
||||
return "aRetVal = " + memberName + ";\n"
|
||||
if type.isSpiderMonkeyInterface() or type.isObject():
|
||||
return fill(
|
||||
@ -14980,7 +14980,7 @@ class CGEventClass(CGBindingImplClass):
|
||||
nativeType = CGGeneric(type.unroll().inner.identifier.name)
|
||||
if type.nullable():
|
||||
nativeType = CGTemplatedType("Nullable", nativeType)
|
||||
elif type.isDOMString() or type.isScalarValueString():
|
||||
elif type.isDOMString() or type.isUSVString():
|
||||
nativeType = CGGeneric("nsString")
|
||||
elif type.isByteString():
|
||||
nativeType = CGGeneric("nsCString")
|
||||
|
@ -1572,7 +1572,7 @@ class IDLType(IDLObject):
|
||||
'any',
|
||||
'domstring',
|
||||
'bytestring',
|
||||
'scalarvaluestring',
|
||||
'usvstring',
|
||||
'object',
|
||||
'date',
|
||||
'void',
|
||||
@ -1625,7 +1625,7 @@ class IDLType(IDLObject):
|
||||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
@ -1811,8 +1811,8 @@ class IDLNullableType(IDLType):
|
||||
def isDOMString(self):
|
||||
return self.inner.isDOMString()
|
||||
|
||||
def isScalarValueString(self):
|
||||
return self.inner.isScalarValueString()
|
||||
def isUSVString(self):
|
||||
return self.inner.isUSVString()
|
||||
|
||||
def isFloat(self):
|
||||
return self.inner.isFloat()
|
||||
@ -1939,7 +1939,7 @@ class IDLSequenceType(IDLType):
|
||||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
@ -2213,7 +2213,7 @@ class IDLArrayType(IDLType):
|
||||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
@ -2311,8 +2311,8 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
|
||||
def isDOMString(self):
|
||||
return self.inner.isDOMString()
|
||||
|
||||
def isScalarValueString(self):
|
||||
return self.inner.isScalarValueString()
|
||||
def isUSVString(self):
|
||||
return self.inner.isUSVString()
|
||||
|
||||
def isVoid(self):
|
||||
return self.inner.isVoid()
|
||||
@ -2412,7 +2412,7 @@ class IDLWrapperType(IDLType):
|
||||
def isDOMString(self):
|
||||
return False
|
||||
|
||||
def isScalarValueString(self):
|
||||
def isUSVString(self):
|
||||
return False
|
||||
|
||||
def isVoid(self):
|
||||
@ -2566,7 +2566,7 @@ class IDLBuiltinType(IDLType):
|
||||
'any',
|
||||
'domstring',
|
||||
'bytestring',
|
||||
'scalarvaluestring',
|
||||
'usvstring',
|
||||
'object',
|
||||
'date',
|
||||
'void',
|
||||
@ -2601,7 +2601,7 @@ class IDLBuiltinType(IDLType):
|
||||
Types.any: IDLType.Tags.any,
|
||||
Types.domstring: IDLType.Tags.domstring,
|
||||
Types.bytestring: IDLType.Tags.bytestring,
|
||||
Types.scalarvaluestring: IDLType.Tags.scalarvaluestring,
|
||||
Types.usvstring: IDLType.Tags.usvstring,
|
||||
Types.object: IDLType.Tags.object,
|
||||
Types.date: IDLType.Tags.date,
|
||||
Types.void: IDLType.Tags.void,
|
||||
@ -2635,7 +2635,7 @@ class IDLBuiltinType(IDLType):
|
||||
def isString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.domstring or \
|
||||
self._typeTag == IDLBuiltinType.Types.bytestring or \
|
||||
self._typeTag == IDLBuiltinType.Types.scalarvaluestring
|
||||
self._typeTag == IDLBuiltinType.Types.usvstring
|
||||
|
||||
def isByteString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.bytestring
|
||||
@ -2643,8 +2643,8 @@ class IDLBuiltinType(IDLType):
|
||||
def isDOMString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.domstring
|
||||
|
||||
def isScalarValueString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.scalarvaluestring
|
||||
def isUSVString(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.usvstring
|
||||
|
||||
def isInteger(self):
|
||||
return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
|
||||
@ -2798,9 +2798,9 @@ BuiltinTypes = {
|
||||
IDLBuiltinType.Types.bytestring:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString",
|
||||
IDLBuiltinType.Types.bytestring),
|
||||
IDLBuiltinType.Types.scalarvaluestring:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ScalarValueString",
|
||||
IDLBuiltinType.Types.scalarvaluestring),
|
||||
IDLBuiltinType.Types.usvstring:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "USVString",
|
||||
IDLBuiltinType.Types.usvstring),
|
||||
IDLBuiltinType.Types.object:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object",
|
||||
IDLBuiltinType.Types.object),
|
||||
@ -2935,10 +2935,10 @@ class IDLValue(IDLObject):
|
||||
raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted"
|
||||
% self.value, [location]);
|
||||
return self
|
||||
elif self.type.isString() and type.isScalarValueString():
|
||||
# Allow ScalarValueStrings to use default value just like
|
||||
elif self.type.isString() and type.isUSVString():
|
||||
# Allow USVStrings to use default value just like
|
||||
# DOMString. No coercion is required in this case as Codegen.py
|
||||
# treats ScalarValueString just like DOMString, but with an
|
||||
# treats USVString just like DOMString, but with an
|
||||
# extra normalization step.
|
||||
assert self.type.isDOMString()
|
||||
return self
|
||||
@ -4168,7 +4168,7 @@ class Tokenizer(object):
|
||||
"Date": "DATE",
|
||||
"DOMString": "DOMSTRING",
|
||||
"ByteString": "BYTESTRING",
|
||||
"ScalarValueString": "SCALARVALUESTRING",
|
||||
"USVString": "USVSTRING",
|
||||
"any": "ANY",
|
||||
"boolean": "BOOLEAN",
|
||||
"byte": "BYTE",
|
||||
@ -5132,7 +5132,7 @@ class Parser(Tokenizer):
|
||||
| DATE
|
||||
| DOMSTRING
|
||||
| BYTESTRING
|
||||
| SCALARVALUESTRING
|
||||
| USVSTRING
|
||||
| ANY
|
||||
| ATTRIBUTE
|
||||
| BOOLEAN
|
||||
@ -5405,11 +5405,11 @@ class Parser(Tokenizer):
|
||||
"""
|
||||
p[0] = IDLBuiltinType.Types.bytestring
|
||||
|
||||
def p_PrimitiveOrStringTypeScalarValueString(self, p):
|
||||
def p_PrimitiveOrStringTypeUSVString(self, p):
|
||||
"""
|
||||
PrimitiveOrStringType : SCALARVALUESTRING
|
||||
PrimitiveOrStringType : USVSTRING
|
||||
"""
|
||||
p[0] = IDLBuiltinType.Types.scalarvaluestring
|
||||
p[0] = IDLBuiltinType.Types.usvstring
|
||||
|
||||
def p_UnsignedIntegerTypeUnsigned(self, p):
|
||||
"""
|
||||
|
@ -160,7 +160,7 @@ def WebIDLTest(parser, harness):
|
||||
"optional Dict2", "sequence<long>", "sequence<short>",
|
||||
"MozMap<object>", "MozMap<Dict>", "MozMap<long>",
|
||||
"long[]", "short[]", "Date", "Date?", "any",
|
||||
"ScalarValueString" ]
|
||||
"USVString" ]
|
||||
# When we can parse Date and RegExp, we need to add them here.
|
||||
|
||||
# Try to categorize things a bit to keep list lengths down
|
||||
@ -171,7 +171,7 @@ def WebIDLTest(parser, harness):
|
||||
primitives = numerics + booleans
|
||||
nonNumerics = allBut(argTypes, numerics)
|
||||
nonBooleans = allBut(argTypes, booleans)
|
||||
strings = [ "DOMString", "ByteString", "Enum", "Enum2", "ScalarValueString" ]
|
||||
strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ]
|
||||
nonStrings = allBut(argTypes, strings)
|
||||
nonObjects = primitives + strings
|
||||
objects = allBut(argTypes, nonObjects )
|
||||
@ -206,7 +206,7 @@ def WebIDLTest(parser, harness):
|
||||
setDistinguishable("boolean?", allBut(nonBooleans, nullables))
|
||||
setDistinguishable("DOMString", nonStrings)
|
||||
setDistinguishable("ByteString", nonStrings)
|
||||
setDistinguishable("ScalarValueString", nonStrings)
|
||||
setDistinguishable("USVString", nonStrings)
|
||||
setDistinguishable("Enum", nonStrings)
|
||||
setDistinguishable("Enum2", nonStrings)
|
||||
setDistinguishable("Interface", notRelatedInterfaces)
|
||||
|
@ -63,7 +63,7 @@ def WebIDLTest(parser, harness):
|
||||
"octet",
|
||||
"DOMString",
|
||||
"ByteString",
|
||||
"ScalarValueString",
|
||||
"USVString",
|
||||
#"sequence<float>",
|
||||
"object",
|
||||
"ArrayBuffer",
|
||||
|
@ -4,8 +4,8 @@ import WebIDL
|
||||
|
||||
def WebIDLTest(parser, harness):
|
||||
parser.parse("""
|
||||
interface TestScalarValueString {
|
||||
attribute ScalarValueString svs;
|
||||
interface TestUSVString {
|
||||
attribute USVString svs;
|
||||
};
|
||||
""")
|
||||
|
||||
@ -15,9 +15,9 @@ def WebIDLTest(parser, harness):
|
||||
harness.ok(isinstance(results[0], WebIDL.IDLInterface),
|
||||
"Should be an IDLInterface")
|
||||
iface = results[0]
|
||||
harness.check(iface.identifier.QName(), "::TestScalarValueString",
|
||||
harness.check(iface.identifier.QName(), "::TestUSVString",
|
||||
"Interface has the right QName")
|
||||
harness.check(iface.identifier.name, "TestScalarValueString",
|
||||
harness.check(iface.identifier.name, "TestUSVString",
|
||||
"Interface has the right name")
|
||||
harness.check(iface.parent, None, "Interface has no parent")
|
||||
|
||||
@ -26,11 +26,11 @@ def WebIDLTest(parser, harness):
|
||||
|
||||
attr = members[0]
|
||||
harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute")
|
||||
harness.check(attr.identifier.QName(), "::TestScalarValueString::svs",
|
||||
harness.check(attr.identifier.QName(), "::TestUSVString::svs",
|
||||
"Attr has correct QName")
|
||||
harness.check(attr.identifier.name, "svs", "Attr has correct name")
|
||||
harness.check(str(attr.type), "ScalarValueString",
|
||||
harness.check(str(attr.type), "USVString",
|
||||
"Attr type is the correct name")
|
||||
harness.ok(attr.type.isScalarValueString(), "Should be ScalarValueString type")
|
||||
harness.ok(attr.type.isUSVString(), "Should be USVString type")
|
||||
harness.ok(attr.type.isString(), "Should be String collective type")
|
||||
harness.ok(not attr.type.isDOMString(), "Should be not be DOMString type")
|
@ -480,15 +480,15 @@ public:
|
||||
void PassOptionalNullableByteString(const Optional<nsCString>&);
|
||||
void PassVariadicByteString(const Sequence<nsCString>&);
|
||||
|
||||
// ScalarValueString types
|
||||
void PassSVS(const nsAString&);
|
||||
void PassNullableSVS(const nsAString&);
|
||||
void PassOptionalSVS(const Optional<nsAString>&);
|
||||
void PassOptionalSVSWithDefaultValue(const nsAString&);
|
||||
void PassOptionalNullableSVS(const Optional<nsAString>&);
|
||||
void PassOptionalNullableSVSWithDefaultValue(const nsAString&);
|
||||
void PassVariadicSVS(const Sequence<nsString>&);
|
||||
void ReceiveSVS(DOMString&);
|
||||
// USVString types
|
||||
void PassUSVS(const nsAString&);
|
||||
void PassNullableUSVS(const nsAString&);
|
||||
void PassOptionalUSVS(const Optional<nsAString>&);
|
||||
void PassOptionalUSVSWithDefaultValue(const nsAString&);
|
||||
void PassOptionalNullableUSVS(const Optional<nsAString>&);
|
||||
void PassOptionalNullableUSVSWithDefaultValue(const nsAString&);
|
||||
void PassVariadicUSVS(const Sequence<nsString>&);
|
||||
void ReceiveUSVS(DOMString&);
|
||||
|
||||
// Enumerated types
|
||||
void PassEnum(TestEnum);
|
||||
@ -613,7 +613,7 @@ public:
|
||||
void PassUnionWithMozMap(const StringMozMapOrString&);
|
||||
void PassUnionWithMozMapAndSequence(const StringMozMapOrStringSequence&);
|
||||
void PassUnionWithSequenceAndMozMap(const StringSequenceOrStringMozMap&);
|
||||
void PassUnionWithSVS(const ScalarValueStringOrLong&);
|
||||
void PassUnionWithUSVS(const USVStringOrLong&);
|
||||
#endif
|
||||
void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&);
|
||||
void PassOptionalUnion(JSContext*, const Optional<ObjectOrLong>&);
|
||||
|
@ -460,15 +460,15 @@ interface TestInterface {
|
||||
void passOptionalNullableByteString(optional ByteString? arg);
|
||||
void passVariadicByteString(ByteString... arg);
|
||||
|
||||
// ScalarValueString types
|
||||
void passSVS(ScalarValueString arg);
|
||||
void passNullableSVS(ScalarValueString? arg);
|
||||
void passOptionalSVS(optional ScalarValueString arg);
|
||||
void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
|
||||
void passOptionalNullableSVS(optional ScalarValueString? arg);
|
||||
void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
|
||||
void passVariadicSVS(ScalarValueString... arg);
|
||||
ScalarValueString receiveSVS();
|
||||
// USVString types
|
||||
void passUSVS(USVString arg);
|
||||
void passNullableUSVS(USVString? arg);
|
||||
void passOptionalUSVS(optional USVString arg);
|
||||
void passOptionalUSVSWithDefaultValue(optional USVString arg = "abc");
|
||||
void passOptionalNullableUSVS(optional USVString? arg);
|
||||
void passOptionalNullableUSVSWithDefaultValue(optional USVString? arg = null);
|
||||
void passVariadicUSVS(USVString... arg);
|
||||
USVString receiveUSVS();
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(TestEnum arg);
|
||||
@ -578,7 +578,7 @@ interface TestInterface {
|
||||
void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
|
||||
void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
|
||||
void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
|
||||
void passUnionWithSVS((ScalarValueString or long) arg);
|
||||
void passUnionWithUSVS((USVString or long) arg);
|
||||
#endif
|
||||
void passUnionWithNullable((object? or long) arg);
|
||||
void passNullableUnion((object or long)? arg);
|
||||
|
@ -327,15 +327,15 @@ interface TestExampleInterface {
|
||||
void passVariadicByteString(ByteString... arg);
|
||||
void passUnionByteString((ByteString or long) arg);
|
||||
|
||||
// ScalarValueString types
|
||||
void passSVS(ScalarValueString arg);
|
||||
void passNullableSVS(ScalarValueString? arg);
|
||||
void passOptionalSVS(optional ScalarValueString arg);
|
||||
void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
|
||||
void passOptionalNullableSVS(optional ScalarValueString? arg);
|
||||
void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
|
||||
void passVariadicSVS(ScalarValueString... arg);
|
||||
ScalarValueString receiveSVS();
|
||||
// USVString types
|
||||
void passSVS(USVString arg);
|
||||
void passNullableSVS(USVString? arg);
|
||||
void passOptionalSVS(optional USVString arg);
|
||||
void passOptionalSVSWithDefaultValue(optional USVString arg = "abc");
|
||||
void passOptionalNullableSVS(optional USVString? arg);
|
||||
void passOptionalNullableSVSWithDefaultValue(optional USVString? arg = null);
|
||||
void passVariadicSVS(USVString... arg);
|
||||
USVString receiveSVS();
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(TestEnum arg);
|
||||
@ -443,7 +443,7 @@ interface TestExampleInterface {
|
||||
void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
|
||||
void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
|
||||
void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
|
||||
void passUnionWithSVS((ScalarValueString or long) arg);
|
||||
void passUnionWithSVS((USVString or long) arg);
|
||||
#endif
|
||||
void passUnionWithNullable((object? or long) arg);
|
||||
void passNullableUnion((object or long)? arg);
|
||||
|
@ -339,15 +339,15 @@ interface TestJSImplInterface {
|
||||
void passVariadicByteString(ByteString... arg);
|
||||
void PassUnionByteString((ByteString or long) arg);
|
||||
|
||||
// ScalarValueString types
|
||||
void passSVS(ScalarValueString arg);
|
||||
void passNullableSVS(ScalarValueString? arg);
|
||||
void passOptionalSVS(optional ScalarValueString arg);
|
||||
void passOptionalSVSWithDefaultValue(optional ScalarValueString arg = "abc");
|
||||
void passOptionalNullableSVS(optional ScalarValueString? arg);
|
||||
void passOptionalNullableSVSWithDefaultValue(optional ScalarValueString? arg = null);
|
||||
void passVariadicSVS(ScalarValueString... arg);
|
||||
ScalarValueString receiveSVS();
|
||||
// USVString types
|
||||
void passSVS(USVString arg);
|
||||
void passNullableSVS(USVString? arg);
|
||||
void passOptionalSVS(optional USVString arg);
|
||||
void passOptionalSVSWithDefaultValue(optional USVString arg = "abc");
|
||||
void passOptionalNullableSVS(optional USVString? arg);
|
||||
void passOptionalNullableSVSWithDefaultValue(optional USVString? arg = null);
|
||||
void passVariadicSVS(USVString... arg);
|
||||
USVString receiveSVS();
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(MyTestEnum arg);
|
||||
@ -456,7 +456,7 @@ interface TestJSImplInterface {
|
||||
void passUnionWithMozMap((MozMap<DOMString> or DOMString) arg);
|
||||
void passUnionWithMozMapAndSequence((MozMap<DOMString> or sequence<DOMString>) arg);
|
||||
void passUnionWithSequenceAndMozMap((sequence<DOMString> or MozMap<DOMString>) arg);
|
||||
void passUnionWithSVS((ScalarValueString or long) arg);
|
||||
void passUnionWithSVS((USVString or long) arg);
|
||||
#endif
|
||||
void passUnionWithNullable((object? or long) arg);
|
||||
void passNullableUnion((object or long)? arg);
|
||||
|
@ -44,7 +44,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926547
|
||||
[test_queryInterface.html]
|
||||
[test_returnUnion.html]
|
||||
skip-if = debug == false
|
||||
[test_scalarvaluestring.html]
|
||||
[test_usvstring.html]
|
||||
skip-if = debug == false
|
||||
[test_sequence_wrapping.html]
|
||||
[test_setWithNamedGetterNoNamedSetter.html]
|
||||
|
@ -3,7 +3,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test ScalarValueString</title>
|
||||
<title>Test USVString</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
@ -886,7 +886,8 @@ Event::GetScreenCoords(nsPresContext* aPresContext,
|
||||
|
||||
LayoutDeviceIntPoint offset = aPoint +
|
||||
LayoutDeviceIntPoint::FromUntyped(guiEvent->widget->WidgetToScreenOffset());
|
||||
nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
|
||||
nscoord factor =
|
||||
aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
|
||||
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
|
||||
nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
|
||||
}
|
||||
|
@ -32,6 +32,12 @@
|
||||
#include "mozilla/TouchEvents.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
#include "GeckoTaskTracer.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
using namespace mozilla::tasktracer;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
@ -407,6 +413,27 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
NS_ENSURE_TRUE(aEvent->message || !aDOMEvent || aTargets,
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
{
|
||||
if (aDOMEvent) {
|
||||
nsAutoString eventType;
|
||||
aDOMEvent->GetType(eventType);
|
||||
|
||||
nsCOMPtr<Element> element = do_QueryInterface(aTarget);
|
||||
nsAutoString elementId;
|
||||
nsAutoString elementTagName;
|
||||
if (element) {
|
||||
element->GetId(elementId);
|
||||
element->GetTagName(elementTagName);
|
||||
}
|
||||
AddLabel("Event [%s] dispatched at target [id:%s tag:%s]",
|
||||
NS_ConvertUTF16toUTF8(eventType).get(),
|
||||
NS_ConvertUTF16toUTF8(elementId).get(),
|
||||
NS_ConvertUTF16toUTF8(elementTagName).get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
|
||||
|
||||
bool retargeted = false;
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
LayoutDeviceIntPoint offset = aEvent->refPoint +
|
||||
LayoutDeviceIntPoint::FromUntyped(event->widget->WidgetToScreenOffset());
|
||||
nscoord factor =
|
||||
aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
|
||||
aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
|
||||
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
|
||||
nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public:
|
||||
};
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrScalarValueString& aInput,
|
||||
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> p = Promise::Create(aGlobal, aRv);
|
||||
@ -316,7 +316,7 @@ ExtractFromBlob(const File& aFile, nsIInputStream** aStream,
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromScalarValueString(const nsString& aStr,
|
||||
ExtractFromUSVString(const nsString& aStr,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
@ -365,7 +365,7 @@ ExtractFromURLSearchParams(const URLSearchParams& aParams,
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
@ -380,10 +380,10 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalar
|
||||
} else if (aBodyInit.IsBlob()) {
|
||||
const File& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType);
|
||||
} else if (aBodyInit.IsScalarValueString()) {
|
||||
} else if (aBodyInit.IsUSVString()) {
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsScalarValueString());
|
||||
return ExtractFromScalarValueString(str, aStream, aContentType);
|
||||
str.Assign(aBodyInit.GetAsUSVString());
|
||||
return ExtractFromUSVString(str, aStream, aContentType);
|
||||
} else if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType);
|
||||
@ -394,7 +394,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalar
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
@ -409,10 +409,10 @@ ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueS
|
||||
} else if (aBodyInit.IsBlob()) {
|
||||
const File& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType);
|
||||
} else if (aBodyInit.IsScalarValueString()) {
|
||||
} else if (aBodyInit.IsUSVString()) {
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsScalarValueString());
|
||||
return ExtractFromScalarValueString(str, aStream, aContentType);
|
||||
str.Assign(aBodyInit.GetAsUSVString());
|
||||
return ExtractFromUSVString(str, aStream, aContentType);
|
||||
} else if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType);
|
||||
|
@ -18,18 +18,18 @@ class nsIGlobalObject;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams;
|
||||
class ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
|
||||
class InternalRequest;
|
||||
class OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams;
|
||||
class OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams;
|
||||
class Promise;
|
||||
class RequestOrScalarValueString;
|
||||
class RequestOrUSVString;
|
||||
|
||||
namespace workers {
|
||||
class WorkerPrivate;
|
||||
} // namespace workers
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrScalarValueString& aInput,
|
||||
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
@ -41,7 +41,7 @@ GetRequestReferrer(nsIGlobalObject* aGlobal, const InternalRequest* aRequest, ns
|
||||
* Stores content type in out param aContentType.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType);
|
||||
|
||||
@ -49,7 +49,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalar
|
||||
* Non-owning version.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType);
|
||||
|
||||
|
@ -49,7 +49,7 @@ Request::GetInternalRequest()
|
||||
|
||||
/*static*/ already_AddRefed<Request>
|
||||
Request::Constructor(const GlobalObject& aGlobal,
|
||||
const RequestOrScalarValueString& aInput,
|
||||
const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<InternalRequest> request;
|
||||
@ -76,9 +76,9 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
|
||||
RequestMode fallbackMode = RequestMode::EndGuard_;
|
||||
RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
|
||||
if (aInput.IsScalarValueString()) {
|
||||
if (aInput.IsUSVString()) {
|
||||
nsString input;
|
||||
input.Assign(aInput.GetAsScalarValueString());
|
||||
input.Assign(aInput.GetAsUSVString());
|
||||
|
||||
nsString requestURL;
|
||||
if (NS_IsMainThread()) {
|
||||
@ -191,7 +191,7 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
if (aInit.mBody.WasPassed()) {
|
||||
const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
|
||||
const OwningArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsCString contentType;
|
||||
aRv = ExtractByteStreamFromBody(bodyInit,
|
||||
|
@ -23,7 +23,7 @@ namespace dom {
|
||||
class Headers;
|
||||
class InternalHeaders;
|
||||
class Promise;
|
||||
class RequestOrScalarValueString;
|
||||
class RequestOrUSVString;
|
||||
|
||||
class Request MOZ_FINAL : public nsISupports
|
||||
, public nsWrapperCache
|
||||
@ -89,7 +89,7 @@ public:
|
||||
GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); }
|
||||
|
||||
static already_AddRefed<Request>
|
||||
Constructor(const GlobalObject& aGlobal, const RequestOrScalarValueString& aInput,
|
||||
Constructor(const GlobalObject& aGlobal, const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& rv);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const
|
||||
|
@ -56,14 +56,14 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
{
|
||||
ErrorResult result;
|
||||
ResponseInit init;
|
||||
Optional<ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams> body;
|
||||
Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams> body;
|
||||
nsRefPtr<Response> r = Response::Constructor(aGlobal, body, init, result);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
/*static*/ already_AddRefed<Response>
|
||||
Response::Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams>& aBody,
|
||||
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
|
||||
const ResponseInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
if (aInit.mStatus < 200 || aInit.mStatus > 599) {
|
||||
|
@ -19,7 +19,7 @@ class nsPIDOMWindow;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams;
|
||||
class ArrayBufferOrArrayBufferViewOrUSVStringOrURLSearchParams;
|
||||
class Headers;
|
||||
class InternalHeaders;
|
||||
class Promise;
|
||||
@ -87,7 +87,7 @@ public:
|
||||
|
||||
static already_AddRefed<Response>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams>& aBody,
|
||||
const Optional<ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrURLSearchParams>& aBody,
|
||||
const ResponseInit& aInit, ErrorResult& rv);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const
|
||||
|
@ -278,7 +278,8 @@ public:
|
||||
enum NotDecodedReason {
|
||||
END_OF_STREAM,
|
||||
DECODE_ERROR,
|
||||
WAITING_FOR_DATA
|
||||
WAITING_FOR_DATA,
|
||||
CANCELED
|
||||
};
|
||||
|
||||
// Receives the result of a RequestAudioData() call.
|
||||
|
@ -632,6 +632,11 @@ bool
|
||||
MediaDecoderStateMachine::NeedToDecodeAudio()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
SAMPLE_LOG("NeedToDecodeAudio() isDec=%d decToTar=%d minPrl=%d seek=%d enufAud=%d",
|
||||
IsAudioDecoding(), mDecodeToSeekTarget, mMinimizePreroll,
|
||||
mState == DECODER_STATE_SEEKING,
|
||||
HaveEnoughDecodedAudio(mAmpleAudioThresholdUsecs * mPlaybackRate));
|
||||
|
||||
return IsAudioDecoding() &&
|
||||
((mState == DECODER_STATE_SEEKING && mDecodeToSeekTarget) ||
|
||||
(!mMinimizePreroll &&
|
||||
@ -833,6 +838,11 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
return;
|
||||
}
|
||||
|
||||
if (aReason == RequestSampleCallback::CANCELED) {
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
// This is an EOS. Finish off the queue, and then handle things based on our
|
||||
// state.
|
||||
MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM);
|
||||
@ -1722,6 +1732,11 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
||||
!needToDecodeVideo &&
|
||||
!IsPlaying();
|
||||
|
||||
SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d dispAudio=%d needVideo=%d dispVid=%d needIdle=%d",
|
||||
needToDecodeAudio, mAudioRequestPending,
|
||||
needToDecodeVideo, mVideoRequestPending,
|
||||
needIdle);
|
||||
|
||||
if (needToDecodeAudio) {
|
||||
EnsureAudioDecodeTaskQueued();
|
||||
}
|
||||
@ -1729,10 +1744,6 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
||||
EnsureVideoDecodeTaskQueued();
|
||||
}
|
||||
|
||||
SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d dispAudio=%d needVideo=%d dispVid=%d needIdle=%d",
|
||||
needToDecodeAudio, mAudioRequestPending,
|
||||
needToDecodeVideo, mVideoRequestPending,
|
||||
needIdle);
|
||||
|
||||
if (needIdle) {
|
||||
RefPtr<nsIRunnable> event = NS_NewRunnableMethod(
|
||||
@ -2251,9 +2262,10 @@ void MediaDecoderStateMachine::DecodeSeek()
|
||||
return;
|
||||
}
|
||||
|
||||
mDecodeToSeekTarget = false;
|
||||
|
||||
if (!currentTimeChanged) {
|
||||
DECODER_LOG("Seek !currentTimeChanged...");
|
||||
mDecodeToSeekTarget = false;
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -2387,6 +2399,13 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
// Try to decode another frame to detect if we're at the end...
|
||||
DECODER_LOG("Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime);
|
||||
|
||||
mCurrentSeekTarget = SeekTarget();
|
||||
|
||||
// Reset quick buffering status. This ensures that if we began the
|
||||
// seek while quick-buffering, we won't bypass quick buffering mode
|
||||
// if we need to buffer after the seek.
|
||||
mQuickBuffering = false;
|
||||
|
||||
// Prevent changes in playback position before 'seeked' is fired for we
|
||||
// expect currentTime equals seek target in 'seeked' callback.
|
||||
mScheduler->FreezeScheduling();
|
||||
@ -2395,11 +2414,6 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
// Reset quick buffering status. This ensures that if we began the
|
||||
// seek while quick-buffering, we won't bypass quick buffering mode
|
||||
// if we need to buffer after the seek.
|
||||
mQuickBuffering = false;
|
||||
|
||||
ScheduleStateMachine();
|
||||
mScheduler->ThawScheduling();
|
||||
}
|
||||
|
@ -1302,8 +1302,7 @@ PeerConnectionObserver.prototype = {
|
||||
onStateChange: function(state) {
|
||||
switch (state) {
|
||||
case "SignalingState":
|
||||
this._dompc.callCB(this._dompc.onsignalingstatechange,
|
||||
this._dompc.signalingState);
|
||||
this.dispatchEvent(new this._win.Event("signalingstatechange"));
|
||||
break;
|
||||
|
||||
case "IceConnectionState":
|
||||
|
@ -33,8 +33,10 @@ PRLogModuleInfo* GetDemuxerLog() {
|
||||
return log;
|
||||
}
|
||||
#define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
#define VLOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
|
||||
#else
|
||||
#define LOG(...)
|
||||
#define VLOG(...)
|
||||
#endif
|
||||
|
||||
using namespace mp4_demuxer;
|
||||
@ -134,14 +136,28 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
|
||||
|
||||
MP4Reader::~MP4Reader()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_COUNT_DTOR(MP4Reader);
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
class DestroyPDMTask : public nsRunnable {
|
||||
public:
|
||||
DestroyPDMTask(nsAutoPtr<PlatformDecoderModule>& aPDM)
|
||||
: mPDM(aPDM)
|
||||
{}
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mPDM = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsAutoPtr<PlatformDecoderModule> mPDM;
|
||||
};
|
||||
|
||||
void
|
||||
MP4Reader::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
|
||||
if (mAudio.mDecoder) {
|
||||
Flush(kAudio);
|
||||
mAudio.mDecoder->Shutdown();
|
||||
@ -164,8 +180,10 @@ MP4Reader::Shutdown()
|
||||
mQueuedVideoSample = nullptr;
|
||||
|
||||
if (mPlatform) {
|
||||
mPlatform->Shutdown();
|
||||
mPlatform = nullptr;
|
||||
// PDMs are supposed to be destroyed on the main thread...
|
||||
nsRefPtr<DestroyPDMTask> task(new DestroyPDMTask(mPlatform));
|
||||
MOZ_ASSERT(!mPlatform);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,12 +224,10 @@ MP4Reader::Init(MediaDecoderReader* aCloneDonor)
|
||||
|
||||
InitLayersBackendType();
|
||||
|
||||
mAudio.mTaskQueue = new MediaTaskQueue(
|
||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("MP4 Audio Decode")));
|
||||
mAudio.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
NS_ENSURE_TRUE(mAudio.mTaskQueue, NS_ERROR_FAILURE);
|
||||
|
||||
mVideo.mTaskQueue = new MediaTaskQueue(
|
||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("MP4 Video Decode")));
|
||||
mVideo.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
NS_ENSURE_TRUE(mVideo.mTaskQueue, NS_ERROR_FAILURE);
|
||||
|
||||
static bool sSetupPrefCache = false;
|
||||
@ -483,6 +499,176 @@ MP4Reader::GetDecoderData(TrackType aTrack)
|
||||
return (aTrack == kAudio) ? mAudio : mVideo;
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
|
||||
int64_t aTimeThreshold)
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
VLOG("RequestVideoData skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
uint32_t parsed = 0, decoded = 0;
|
||||
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
|
||||
|
||||
MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
|
||||
|
||||
if (aSkipToNextKeyframe) {
|
||||
if (!SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed) ||
|
||||
NS_FAILED(mVideo.mDecoder->Flush())) {
|
||||
NS_WARNING("Failed to skip/flush video when skipping-to-next-keyframe.");
|
||||
}
|
||||
}
|
||||
|
||||
auto& decoder = GetDecoderData(kVideo);
|
||||
MonitorAutoLock lock(decoder.mMonitor);
|
||||
decoder.mOutputRequested = true;
|
||||
ScheduleUpdate(kVideo);
|
||||
|
||||
// Report the number of "decoded" frames as the difference in the
|
||||
// mNumSamplesOutput field since the last time we were called.
|
||||
uint64_t delta = mVideo.mNumSamplesOutput - mLastReportedNumDecodedFrames;
|
||||
decoded = static_cast<uint32_t>(delta);
|
||||
mLastReportedNumDecodedFrames = mVideo.mNumSamplesOutput;
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::RequestAudioData()
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
VLOG("RequestAudioData");
|
||||
auto& decoder = GetDecoderData(kAudio);
|
||||
MonitorAutoLock lock(decoder.mMonitor);
|
||||
decoder.mOutputRequested = true;
|
||||
ScheduleUpdate(kAudio);
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::ScheduleUpdate(TrackType aTrack)
|
||||
{
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mMonitor.AssertCurrentThreadOwns();
|
||||
if (decoder.mUpdateScheduled) {
|
||||
return;
|
||||
}
|
||||
VLOG("SchedulingUpdate(%s)", TrackTypeToStr(aTrack));
|
||||
decoder.mUpdateScheduled = true;
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<TrackType>(this, &MP4Reader::Update, aTrack));
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::NeedInput(DecoderData& aDecoder)
|
||||
{
|
||||
aDecoder.mMonitor.AssertCurrentThreadOwns();
|
||||
// We try to keep a few more compressed samples input than decoded samples
|
||||
// have been output, provided the state machine has requested we send it a
|
||||
// decoded sample. To account for H.264 streams which may require a longer
|
||||
// run of input than we input, decoders fire an "input exhausted" callback,
|
||||
// which overrides our "few more samples" threshold.
|
||||
return
|
||||
!aDecoder.mError &&
|
||||
!aDecoder.mEOS &&
|
||||
aDecoder.mOutputRequested &&
|
||||
aDecoder.mOutput.IsEmpty() &&
|
||||
(aDecoder.mInputExhausted ||
|
||||
aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::Update(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
|
||||
bool needInput = false;
|
||||
bool needOutput = false;
|
||||
bool eos = false;
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
nsRefPtr<MediaData> output;
|
||||
{
|
||||
MonitorAutoLock lock(decoder.mMonitor);
|
||||
decoder.mUpdateScheduled = false;
|
||||
if (NeedInput(decoder)) {
|
||||
needInput = true;
|
||||
decoder.mInputExhausted = false;
|
||||
decoder.mNumSamplesInput++;
|
||||
}
|
||||
needOutput = decoder.mOutputRequested;
|
||||
if (needOutput && !decoder.mOutput.IsEmpty()) {
|
||||
output = decoder.mOutput[0];
|
||||
decoder.mOutput.RemoveElementAt(0);
|
||||
}
|
||||
eos = decoder.mEOS;
|
||||
}
|
||||
VLOG("Update(%s) ni=%d no=%d iex=%d or=%d fl=%d",
|
||||
TrackTypeToStr(aTrack),
|
||||
needInput,
|
||||
needOutput,
|
||||
decoder.mInputExhausted,
|
||||
decoder.mOutputRequested,
|
||||
decoder.mIsFlushing);
|
||||
|
||||
if (needInput) {
|
||||
MP4Sample* sample = PopSample(aTrack);
|
||||
if (sample) {
|
||||
decoder.mDecoder->Input(sample);
|
||||
} else {
|
||||
{
|
||||
MonitorAutoLock lock(decoder.mMonitor);
|
||||
MOZ_ASSERT(!decoder.mEOS);
|
||||
eos = decoder.mEOS = true;
|
||||
}
|
||||
decoder.mDecoder->Drain();
|
||||
}
|
||||
}
|
||||
if (needOutput) {
|
||||
if (output) {
|
||||
ReturnOutput(output, aTrack);
|
||||
} else if (eos) {
|
||||
ReturnEOS(aTrack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::ReturnOutput(MediaData* aData, TrackType aTrack)
|
||||
{
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
{
|
||||
MonitorAutoLock lock(decoder.mMonitor);
|
||||
MOZ_ASSERT(decoder.mOutputRequested);
|
||||
decoder.mOutputRequested = false;
|
||||
if (decoder.mDiscontinuity) {
|
||||
decoder.mDiscontinuity = false;
|
||||
aData->mDiscontinuity = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTrack == kAudio) {
|
||||
AudioData* audioData = static_cast<AudioData*>(aData);
|
||||
|
||||
if (audioData->mChannels != mInfo.mAudio.mChannels ||
|
||||
audioData->mRate != mInfo.mAudio.mRate) {
|
||||
LOG("MP4Reader::ReturnOutput change of sampling rate:%d->%d",
|
||||
mInfo.mAudio.mRate, audioData->mRate);
|
||||
mInfo.mAudio.mRate = audioData->mRate;
|
||||
mInfo.mAudio.mChannels = audioData->mChannels;
|
||||
}
|
||||
|
||||
GetCallback()->OnAudioDecoded(audioData);
|
||||
} else if (aTrack == kVideo) {
|
||||
GetCallback()->OnVideoDecoded(static_cast<VideoData*>(aData));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::ReturnEOS(TrackType aTrack)
|
||||
{
|
||||
GetCallback()->OnNotDecoded(aTrack == kAudio ? MediaData::AUDIO_DATA : MediaData::VIDEO_DATA,
|
||||
RequestSampleCallback::END_OF_STREAM);
|
||||
}
|
||||
|
||||
MP4Sample*
|
||||
MP4Reader::PopSample(TrackType aTrack)
|
||||
{
|
||||
@ -501,108 +687,12 @@ MP4Reader::PopSample(TrackType aTrack)
|
||||
}
|
||||
}
|
||||
|
||||
// How async decoding works:
|
||||
//
|
||||
// When MP4Reader::Decode() is called:
|
||||
// * Lock the DecoderData. We assume the state machine wants
|
||||
// output from the decoder (in future, we'll assume decoder wants input
|
||||
// when the output MediaQueue isn't "full").
|
||||
// * Cache the value of mNumSamplesOutput, as prevFramesOutput.
|
||||
// * While we've not output data (mNumSamplesOutput != prevNumFramesOutput)
|
||||
// and while we still require input, we demux and input data in the reader.
|
||||
// We assume we require input if
|
||||
// ((mNumSamplesInput - mNumSamplesOutput) < sDecodeAheadMargin) or
|
||||
// mInputExhausted is true. Before we send input, we reset mInputExhausted
|
||||
// and increment mNumFrameInput, and drop the lock on DecoderData.
|
||||
// * Once we no longer require input, we wait on the DecoderData
|
||||
// lock for output, or for the input exhausted callback. If we receive the
|
||||
// input exhausted callback, we go back and input more data.
|
||||
// * When our output callback is called, we take the DecoderData lock and
|
||||
// increment mNumSamplesOutput. We notify the DecoderData lock. This will
|
||||
// awaken the Decode thread, and unblock it, and it will return.
|
||||
bool
|
||||
MP4Reader::Decode(TrackType aTrack)
|
||||
{
|
||||
DecoderData& data = GetDecoderData(aTrack);
|
||||
MOZ_ASSERT(data.mDecoder);
|
||||
|
||||
data.mMonitor.Lock();
|
||||
uint64_t prevNumFramesOutput = data.mNumSamplesOutput;
|
||||
while (prevNumFramesOutput == data.mNumSamplesOutput) {
|
||||
data.mMonitor.AssertCurrentThreadOwns();
|
||||
if (data.mError) {
|
||||
// Decode error!
|
||||
data.mMonitor.Unlock();
|
||||
return false;
|
||||
}
|
||||
// Send input to the decoder, if we need to. We assume the decoder
|
||||
// needs input if it's told us it's out of input, or we're beneath the
|
||||
// "low water mark" for the amount of input we've sent it vs the amount
|
||||
// out output we've received. We always try to keep the decoder busy if
|
||||
// possible, so we try to maintain at least a few input samples ahead,
|
||||
// if we need output.
|
||||
while (prevNumFramesOutput == data.mNumSamplesOutput &&
|
||||
(data.mInputExhausted ||
|
||||
(data.mNumSamplesInput - data.mNumSamplesOutput) < data.mDecodeAhead) &&
|
||||
!data.mEOS) {
|
||||
data.mMonitor.AssertCurrentThreadOwns();
|
||||
data.mMonitor.Unlock();
|
||||
nsAutoPtr<MP4Sample> compressed(PopSample(aTrack));
|
||||
if (!compressed) {
|
||||
// EOS, or error. Send the decoder a signal to drain.
|
||||
LOG("MP4Reader: EOS or error - no samples available");
|
||||
LOG("Draining %s", TrackTypeToStr(aTrack));
|
||||
data.mMonitor.Lock();
|
||||
MOZ_ASSERT(!data.mEOS);
|
||||
data.mEOS = true;
|
||||
MOZ_ASSERT(!data.mDrainComplete);
|
||||
data.mDrainComplete = false;
|
||||
data.mMonitor.Unlock();
|
||||
data.mDecoder->Drain();
|
||||
} else {
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("PopSample %s time=%lld dur=%lld", TrackTypeToStr(aTrack),
|
||||
compressed->composition_timestamp, compressed->duration);
|
||||
#endif
|
||||
data.mMonitor.Lock();
|
||||
data.mDrainComplete = false;
|
||||
data.mInputExhausted = false;
|
||||
data.mNumSamplesInput++;
|
||||
data.mMonitor.Unlock();
|
||||
|
||||
if (NS_FAILED(data.mDecoder->Input(compressed))) {
|
||||
return false;
|
||||
}
|
||||
// If Input() failed, we let the auto pointer delete |compressed|.
|
||||
// Otherwise, we assume the decoder will delete it when it's finished
|
||||
// with it.
|
||||
compressed.forget();
|
||||
}
|
||||
data.mMonitor.Lock();
|
||||
}
|
||||
data.mMonitor.AssertCurrentThreadOwns();
|
||||
while (!data.mError &&
|
||||
prevNumFramesOutput == data.mNumSamplesOutput &&
|
||||
(!data.mInputExhausted || data.mEOS) &&
|
||||
!data.mDrainComplete) {
|
||||
data.mMonitor.Wait();
|
||||
}
|
||||
if (data.mError ||
|
||||
(data.mEOS && data.mDrainComplete)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
data.mMonitor.AssertCurrentThreadOwns();
|
||||
bool rv = !(data.mDrainComplete || data.mError);
|
||||
data.mMonitor.Unlock();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MP4Reader::ResetDecode()
|
||||
{
|
||||
Flush(kAudio);
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
Flush(kVideo);
|
||||
Flush(kAudio);
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
}
|
||||
|
||||
@ -610,7 +700,7 @@ void
|
||||
MP4Reader::Output(TrackType aTrack, MediaData* aSample)
|
||||
{
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("Decoded %s sample time=%lld dur=%lld",
|
||||
VLOG("Decoded %s sample time=%lld dur=%lld",
|
||||
TrackTypeToStr(aTrack), aSample->mTime, aSample->mDuration);
|
||||
#endif
|
||||
|
||||
@ -620,40 +710,20 @@ MP4Reader::Output(TrackType aTrack, MediaData* aSample)
|
||||
return;
|
||||
}
|
||||
|
||||
DecoderData& data = GetDecoderData(aTrack);
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
// Don't accept output while we're flushing.
|
||||
MonitorAutoLock mon(data.mMonitor);
|
||||
if (data.mIsFlushing) {
|
||||
MonitorAutoLock mon(decoder.mMonitor);
|
||||
if (decoder.mIsFlushing) {
|
||||
LOG("MP4Reader produced output while flushing, discarding.");
|
||||
mon.NotifyAll();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aTrack) {
|
||||
case kAudio: {
|
||||
MOZ_ASSERT(aSample->mType == MediaData::AUDIO_DATA);
|
||||
AudioData* audioData = static_cast<AudioData*>(aSample);
|
||||
AudioQueue().Push(audioData);
|
||||
if (audioData->mChannels != mInfo.mAudio.mChannels ||
|
||||
audioData->mRate != mInfo.mAudio.mRate) {
|
||||
LOG("MP4Reader::Output change of sampling rate:%d->%d",
|
||||
mInfo.mAudio.mRate, audioData->mRate);
|
||||
mInfo.mAudio.mRate = audioData->mRate;
|
||||
mInfo.mAudio.mChannels = audioData->mChannels;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kVideo: {
|
||||
MOZ_ASSERT(aSample->mType == MediaData::VIDEO_DATA);
|
||||
VideoQueue().Push(static_cast<VideoData*>(aSample));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
decoder.mOutput.AppendElement(aSample);
|
||||
decoder.mNumSamplesOutput++;
|
||||
if (NeedInput(decoder) || decoder.mOutputRequested) {
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
data.mNumSamplesOutput++;
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
void
|
||||
@ -671,28 +741,26 @@ MP4Reader::InputExhausted(TrackType aTrack)
|
||||
DecoderData& data = GetDecoderData(aTrack);
|
||||
MonitorAutoLock mon(data.mMonitor);
|
||||
data.mInputExhausted = true;
|
||||
mon.NotifyAll();
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::Error(TrackType aTrack)
|
||||
{
|
||||
DecoderData& data = GetDecoderData(aTrack);
|
||||
MonitorAutoLock mon(data.mMonitor);
|
||||
data.mError = true;
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::DecodeAudioData()
|
||||
{
|
||||
MOZ_ASSERT(HasAudio() && mPlatform && mAudio.mDecoder);
|
||||
return Decode(kAudio);
|
||||
{
|
||||
MonitorAutoLock mon(data.mMonitor);
|
||||
data.mError = true;
|
||||
}
|
||||
GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA,
|
||||
RequestSampleCallback::DECODE_ERROR);
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::Flush(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
VLOG("Flush(%s) BEGIN", TrackTypeToStr(aTrack));
|
||||
DecoderData& data = GetDecoderData(aTrack);
|
||||
if (!data.mDecoder) {
|
||||
return;
|
||||
@ -710,12 +778,28 @@ MP4Reader::Flush(TrackType aTrack)
|
||||
{
|
||||
MonitorAutoLock mon(data.mMonitor);
|
||||
data.mIsFlushing = false;
|
||||
data.mOutput.Clear();
|
||||
data.mNumSamplesInput = 0;
|
||||
data.mNumSamplesOutput = 0;
|
||||
data.mInputExhausted = false;
|
||||
if (data.mOutputRequested) {
|
||||
GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA,
|
||||
RequestSampleCallback::CANCELED);
|
||||
}
|
||||
data.mOutputRequested = false;
|
||||
data.mDiscontinuity = true;
|
||||
}
|
||||
if (aTrack == kVideo) {
|
||||
mQueuedVideoSample = nullptr;
|
||||
}
|
||||
VLOG("Flush(%s) END", TrackTypeToStr(aTrack));
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed)
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
|
||||
MOZ_ASSERT(mVideo.mDecoder);
|
||||
|
||||
Flush(kVideo);
|
||||
@ -725,6 +809,12 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed
|
||||
nsAutoPtr<MP4Sample> compressed(PopSample(kVideo));
|
||||
if (!compressed) {
|
||||
// EOS, or error. Let the state machine know.
|
||||
GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA,
|
||||
RequestSampleCallback::END_OF_STREAM);
|
||||
{
|
||||
MonitorAutoLock mon(mVideo.mMonitor);
|
||||
mVideo.mEOS = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
parsed++;
|
||||
@ -739,47 +829,16 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold)
|
||||
{
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
uint32_t parsed = 0, decoded = 0;
|
||||
AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
|
||||
|
||||
MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
|
||||
|
||||
if (aKeyframeSkip) {
|
||||
bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed);
|
||||
if (!ok) {
|
||||
NS_WARNING("Failed to skip demux up to next keyframe");
|
||||
return false;
|
||||
}
|
||||
aKeyframeSkip = false;
|
||||
nsresult rv = mVideo.mDecoder->Flush();
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
|
||||
bool rv = Decode(kVideo);
|
||||
{
|
||||
// Report the number of "decoded" frames as the difference in the
|
||||
// mNumSamplesOutput field since the last time we were called.
|
||||
MonitorAutoLock mon(mVideo.mMonitor);
|
||||
uint64_t delta = mVideo.mNumSamplesOutput - mLastReportedNumDecodedFrames;
|
||||
decoded = static_cast<uint32_t>(delta);
|
||||
mLastReportedNumDecodedFrames = mVideo.mNumSamplesOutput;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::Seek(int64_t aTime,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
int64_t aCurrentTime)
|
||||
{
|
||||
LOG("MP4Reader::Seek(%lld)", aTime);
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) {
|
||||
VLOG("Seek() END (Unseekable)");
|
||||
GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -793,7 +852,7 @@ MP4Reader::Seek(int64_t aTime,
|
||||
mDemuxer->SeekAudio(
|
||||
mQueuedVideoSample ? mQueuedVideoSample->composition_timestamp : aTime);
|
||||
}
|
||||
|
||||
LOG("MP4Reader::Seek(%lld) exit", aTime);
|
||||
GetCallback()->OnSeekCompleted(NS_OK);
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@ class MP4Stream;
|
||||
|
||||
class MP4Reader : public MediaDecoderReader
|
||||
{
|
||||
typedef mp4_demuxer::TrackType TrackType;
|
||||
|
||||
public:
|
||||
explicit MP4Reader(AbstractMediaDecoder* aDecoder);
|
||||
|
||||
@ -35,10 +37,11 @@ public:
|
||||
|
||||
virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool DecodeAudioData() MOZ_OVERRIDE;
|
||||
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
virtual void RequestVideoData(bool aSkipToNextKeyframe,
|
||||
int64_t aTimeThreshold) MOZ_OVERRIDE;
|
||||
|
||||
virtual void RequestAudioData() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool HasAudio() MOZ_OVERRIDE;
|
||||
virtual bool HasVideo() MOZ_OVERRIDE;
|
||||
|
||||
@ -75,6 +78,17 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void ReturnEOS(TrackType aTrack);
|
||||
void ReturnOutput(MediaData* aData, TrackType aTrack);
|
||||
|
||||
// Sends input to decoder for aTrack, and output to the state machine,
|
||||
// if necessary.
|
||||
void Update(TrackType aTrack);
|
||||
|
||||
// Enqueues a task to call Update(aTrack) on the decoder task queue.
|
||||
// Lock for corresponding track must be held.
|
||||
void ScheduleUpdate(TrackType aTrack);
|
||||
|
||||
void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData);
|
||||
|
||||
// Initializes mLayersBackendType if possible.
|
||||
@ -86,10 +100,11 @@ private:
|
||||
|
||||
bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
|
||||
|
||||
// DecoderCallback proxies the MediaDataDecoderCallback calls to these
|
||||
// functions.
|
||||
void Output(mp4_demuxer::TrackType aType, MediaData* aSample);
|
||||
void InputExhausted(mp4_demuxer::TrackType aTrack);
|
||||
void Error(mp4_demuxer::TrackType aTrack);
|
||||
bool Decode(mp4_demuxer::TrackType aTrack);
|
||||
void Flush(mp4_demuxer::TrackType aTrack);
|
||||
void DrainComplete(mp4_demuxer::TrackType aTrack);
|
||||
void UpdateIndex();
|
||||
@ -144,7 +159,10 @@ private:
|
||||
, mError(false)
|
||||
, mIsFlushing(false)
|
||||
, mDrainComplete(false)
|
||||
, mOutputRequested(false)
|
||||
, mUpdateScheduled(false)
|
||||
, mEOS(false)
|
||||
, mDiscontinuity(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -155,6 +173,10 @@ private:
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
// Callback that receives output and error notifications from the decoder.
|
||||
nsAutoPtr<DecoderCallback> mCallback;
|
||||
// Decoded samples returned my mDecoder awaiting being returned to
|
||||
// state machine upon request.
|
||||
nsTArray<nsRefPtr<MediaData> > mOutput;
|
||||
|
||||
// Monitor that protects all non-threadsafe state; the primitives
|
||||
// that follow.
|
||||
Monitor mMonitor;
|
||||
@ -167,7 +189,10 @@ private:
|
||||
bool mError;
|
||||
bool mIsFlushing;
|
||||
bool mDrainComplete;
|
||||
bool mOutputRequested;
|
||||
bool mUpdateScheduled;
|
||||
bool mEOS;
|
||||
bool mDiscontinuity;
|
||||
};
|
||||
DecoderData mAudio;
|
||||
DecoderData mVideo;
|
||||
@ -175,6 +200,10 @@ private:
|
||||
// decoder.
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> mQueuedVideoSample;
|
||||
|
||||
// Returns true when the decoder for this track needs input.
|
||||
// aDecoder.mMonitor must be locked.
|
||||
bool NeedInput(DecoderData& aDecoder);
|
||||
|
||||
// The last number of decoded output frames that we've reported to
|
||||
// MediaDecoder::NotifyDecoded(). We diff the number of output video
|
||||
// frames every time that DecodeVideoData() is called, and report the
|
||||
|
@ -164,8 +164,9 @@ public:
|
||||
// media data that the decoder accepts as valid input and produces as
|
||||
// output is determined when the MediaDataDecoder is created.
|
||||
//
|
||||
// All functions must be threadsafe, and be able to be called on an
|
||||
// arbitrary thread.
|
||||
// All functions are only called on the decode task queue. Don't block
|
||||
// inside these functions, unless it's explicitly noted that you should
|
||||
// (like in Flush() and Drain()).
|
||||
//
|
||||
// Decoding is done asynchronously. Any async work can be done on the
|
||||
// MediaTaskQueue passed into the PlatformDecoderModules's Create*Decoder()
|
||||
|
@ -114,12 +114,13 @@ public:
|
||||
AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
|
||||
PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
|
||||
|
||||
mCallback->Output(new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
|
||||
aDuration,
|
||||
numFrames,
|
||||
audio,
|
||||
numChannels,
|
||||
sampleRate));
|
||||
nsRefPtr<AudioData> data = new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
|
||||
aDuration,
|
||||
numFrames,
|
||||
audio,
|
||||
numChannels,
|
||||
sampleRate);
|
||||
mCallback->Output(data);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
@ -267,13 +267,13 @@ AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
|
||||
nsAutoArrayPtr<AudioDataValue>
|
||||
data(new AudioDataValue[outputData.Length()]);
|
||||
PodCopy(data.get(), &outputData[0], outputData.Length());
|
||||
AudioData* audio = new AudioData(aSample->byte_offset,
|
||||
aSample->composition_timestamp,
|
||||
duration.value(),
|
||||
numFrames,
|
||||
data.forget(),
|
||||
channels,
|
||||
rate);
|
||||
nsRefPtr<AudioData> audio = new AudioData(aSample->byte_offset,
|
||||
aSample->composition_timestamp,
|
||||
duration.value(),
|
||||
numFrames,
|
||||
data.forget(),
|
||||
channels,
|
||||
rate);
|
||||
mCallback->Output(audio);
|
||||
}
|
||||
|
||||
|
@ -128,13 +128,13 @@ FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
|
||||
return;
|
||||
}
|
||||
|
||||
AudioData* data = new AudioData(samplePosition,
|
||||
pts,
|
||||
duration.value(),
|
||||
mFrame->nb_samples,
|
||||
audio.forget(),
|
||||
numChannels,
|
||||
samplingRate);
|
||||
nsRefPtr<AudioData> data = new AudioData(samplePosition,
|
||||
pts,
|
||||
duration.value(),
|
||||
mFrame->nb_samples,
|
||||
audio.forget(),
|
||||
numChannels,
|
||||
samplingRate);
|
||||
mCallback->Output(data);
|
||||
pts += duration.value();
|
||||
}
|
||||
|
@ -162,12 +162,13 @@ GonkMediaDataDecoder::IsWaitingMediaResources() {
|
||||
|
||||
bool
|
||||
GonkMediaDataDecoder::IsDormantNeeded() {
|
||||
return mDecoder->IsDormantNeeded();
|
||||
|
||||
return mDecoder.get() ? true : false;
|
||||
}
|
||||
|
||||
void
|
||||
GonkMediaDataDecoder::ReleaseMediaResources() {
|
||||
mDecoder->ReleaseMediaResources();
|
||||
mManager->ReleaseMediaResources();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -34,6 +34,7 @@ public:
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) = 0;
|
||||
|
||||
virtual void ReleaseMediaResources() {};
|
||||
};
|
||||
|
||||
// Samples are decoded using the GonkDecoder (MediaCodec)
|
||||
|
@ -455,6 +455,7 @@ GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
{
|
||||
// Our decode may have acquired the hardware resource that it needs
|
||||
// to start. Notify the state machine to resume loading metadata.
|
||||
ALOG("CodecReserved!");
|
||||
mReaderCallback->NotifyResourcesStatusChanged();
|
||||
break;
|
||||
}
|
||||
@ -467,7 +468,7 @@ GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
|
||||
case kNotifyPostReleaseBuffer:
|
||||
{
|
||||
ReleaseAllPendingVideoBuffersLocked();
|
||||
ReleaseAllPendingVideoBuffers();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -562,7 +563,7 @@ void GonkVideoDecoderManager::PostReleaseVideoBuffer(
|
||||
|
||||
}
|
||||
|
||||
void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffersLocked()
|
||||
void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffers()
|
||||
{
|
||||
Vector<android::MediaBuffer*> releasingVideoBuffers;
|
||||
{
|
||||
@ -584,4 +585,9 @@ void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffersLocked()
|
||||
releasingVideoBuffers.clear();
|
||||
}
|
||||
|
||||
void GonkVideoDecoderManager::ReleaseMediaResources() {
|
||||
ALOG("ReleseMediaResources");
|
||||
ReleaseAllPendingVideoBuffers();
|
||||
mDecoder->ReleaseMediaResources();
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
@ -50,7 +50,10 @@ public:
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
|
||||
|
||||
virtual void ReleaseMediaResources();
|
||||
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
private:
|
||||
struct FrameInfo
|
||||
{
|
||||
@ -112,7 +115,7 @@ private:
|
||||
void codecCanceled();
|
||||
void onMessageReceived(const sp<AMessage> &aMessage);
|
||||
|
||||
void ReleaseAllPendingVideoBuffersLocked();
|
||||
void ReleaseAllPendingVideoBuffers();
|
||||
void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer);
|
||||
|
||||
uint32_t mVideoWidth;
|
||||
|
@ -285,6 +285,45 @@ public:
|
||||
string mRecordId;
|
||||
};
|
||||
|
||||
static void
|
||||
RecvGMPRecordIterator(GMPRecordIterator* aRecordIterator,
|
||||
void* aUserArg,
|
||||
GMPErr aStatus)
|
||||
{
|
||||
FakeDecryptor* decryptor = reinterpret_cast<FakeDecryptor*>(aUserArg);
|
||||
decryptor->ProcessRecordNames(aRecordIterator, aStatus);
|
||||
}
|
||||
|
||||
void
|
||||
FakeDecryptor::ProcessRecordNames(GMPRecordIterator* aRecordIterator,
|
||||
GMPErr aStatus)
|
||||
{
|
||||
if (sInstance != this) {
|
||||
FakeDecryptor::Message("Error aUserArg was not passed through GetRecordIterator");
|
||||
return;
|
||||
}
|
||||
if (GMP_FAILED(aStatus)) {
|
||||
FakeDecryptor::Message("Error GetRecordIterator failed");
|
||||
return;
|
||||
}
|
||||
std::string response("record-names ");
|
||||
bool first = true;
|
||||
const char* name = nullptr;
|
||||
uint32_t len = 0;
|
||||
while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) {
|
||||
std::string s(name, name+len);
|
||||
if (!first) {
|
||||
response += ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
response += s;
|
||||
aRecordIterator->NextRecord();
|
||||
}
|
||||
aRecordIterator->Close();
|
||||
FakeDecryptor::Message(response);
|
||||
}
|
||||
|
||||
enum ShutdownMode {
|
||||
ShutdownNormal,
|
||||
ShutdownTimeout,
|
||||
@ -335,6 +374,8 @@ FakeDecryptor::UpdateSession(uint32_t aPromiseId,
|
||||
mHost->GetPluginVoucher(&rawVoucher, &length);
|
||||
std::string voucher((const char*)rawVoucher, (const char*)(rawVoucher + length));
|
||||
Message("retrieved plugin-voucher: " + voucher);
|
||||
} else if (task == "retrieve-record-names") {
|
||||
GMPEnumRecordNames(&RecvGMPRecordIterator, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,9 @@ public:
|
||||
|
||||
static void Message(const std::string& aMessage);
|
||||
|
||||
void ProcessRecordNames(GMPRecordIterator* aRecordIterator,
|
||||
GMPErr aStatus);
|
||||
|
||||
private:
|
||||
|
||||
virtual ~FakeDecryptor() {}
|
||||
|
@ -193,3 +193,10 @@ GMPOpenRecord(const std::string& aRecordName,
|
||||
}
|
||||
return client->Init(record, aContinuation);
|
||||
}
|
||||
|
||||
GMPErr
|
||||
GMPEnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
|
||||
void* aUserArg)
|
||||
{
|
||||
return g_platform_api->getrecordenumerator(aRecvIteratorFunc, aUserArg);
|
||||
}
|
||||
|
@ -52,6 +52,10 @@ public:
|
||||
|
||||
GMPErr
|
||||
GMPOpenRecord(const std::string& aRecordName,
|
||||
OpenContinuation* aContinuation);
|
||||
OpenContinuation* aContinuation);
|
||||
|
||||
GMPErr
|
||||
GMPEnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
|
||||
void* aUserArg);
|
||||
|
||||
#endif // TEST_GMP_STORAGE_H__
|
||||
|
@ -158,8 +158,10 @@ CreateRecord(const char* aRecordName,
|
||||
GMPRecord** aOutRecord,
|
||||
GMPRecordClient* aClient)
|
||||
{
|
||||
MOZ_ASSERT(IsOnChildMainThread());
|
||||
|
||||
if (sMainLoop != MessageLoop::current()) {
|
||||
NS_WARNING("GMP called CreateRecord() on non-main thread!");
|
||||
MOZ_ASSERT(false, "GMP called CreateRecord() on non-main thread!");
|
||||
return GMPGenericErr;
|
||||
}
|
||||
if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE) {
|
||||
@ -194,6 +196,25 @@ GetClock(GMPTimestamp* aOutTime)
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
GMPErr
|
||||
CreateRecordIterator(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
|
||||
void* aUserArg)
|
||||
{
|
||||
if (sMainLoop != MessageLoop::current()) {
|
||||
MOZ_ASSERT(false, "GMP called CreateRecord() on non-main thread!");
|
||||
return GMPGenericErr;
|
||||
}
|
||||
if (!aRecvIteratorFunc) {
|
||||
return GMPInvalidArgErr;
|
||||
}
|
||||
GMPStorageChild* storage = sChild->GetGMPStorage();
|
||||
if (!storage) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
MOZ_ASSERT(storage);
|
||||
return storage->EnumerateRecords(aRecvIteratorFunc, aUserArg);
|
||||
}
|
||||
|
||||
void
|
||||
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
|
||||
{
|
||||
@ -212,6 +233,7 @@ InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
|
||||
aPlatformAPI.createrecord = &CreateRecord;
|
||||
aPlatformAPI.settimer = &SetTimerOnMainThread;
|
||||
aPlatformAPI.getcurrenttime = &GetClock;
|
||||
aPlatformAPI.getrecordenumerator = &CreateRecordIterator;
|
||||
}
|
||||
|
||||
GMPThreadImpl::GMPThreadImpl()
|
||||
|
@ -268,6 +268,82 @@ GMPStorageChild::RecvWriteComplete(const nsCString& aRecordName,
|
||||
return true;
|
||||
}
|
||||
|
||||
GMPErr
|
||||
GMPStorageChild::EnumerateRecords(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
|
||||
void* aUserArg)
|
||||
{
|
||||
if (mPlugin->GMPMessageLoop() != MessageLoop::current()) {
|
||||
MOZ_ASSERT(false, "GMP used GMPStorage on non-main thread.");
|
||||
return GMPGenericErr;
|
||||
}
|
||||
if (mShutdown) {
|
||||
NS_WARNING("GMPStorage used after it's been shutdown!");
|
||||
return GMPClosedErr;
|
||||
}
|
||||
if (!SendGetRecordNames()) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
MOZ_ASSERT(aRecvIteratorFunc);
|
||||
mPendingRecordIterators.push(RecordIteratorContext(aRecvIteratorFunc, aUserArg));
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
class GMPRecordIteratorImpl : public GMPRecordIterator {
|
||||
public:
|
||||
GMPRecordIteratorImpl(const InfallibleTArray<nsCString>& aRecordNames)
|
||||
: mRecordNames(aRecordNames)
|
||||
, mIndex(0)
|
||||
{
|
||||
mRecordNames.Sort();
|
||||
}
|
||||
|
||||
virtual GMPErr GetName(const char** aOutName, uint32_t* aOutNameLength) MOZ_OVERRIDE {
|
||||
if (!aOutName || !aOutNameLength) {
|
||||
return GMPInvalidArgErr;
|
||||
}
|
||||
if (mIndex == mRecordNames.Length()) {
|
||||
return GMPEndOfEnumeration;
|
||||
}
|
||||
*aOutName = mRecordNames[mIndex].get();
|
||||
*aOutNameLength = mRecordNames[mIndex].Length();
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual GMPErr NextRecord() MOZ_OVERRIDE {
|
||||
if (mIndex < mRecordNames.Length()) {
|
||||
mIndex++;
|
||||
}
|
||||
return (mIndex < mRecordNames.Length()) ? GMPNoErr
|
||||
: GMPEndOfEnumeration;
|
||||
}
|
||||
|
||||
virtual void Close() MOZ_OVERRIDE {
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<nsCString> mRecordNames;
|
||||
size_t mIndex;
|
||||
};
|
||||
|
||||
bool
|
||||
GMPStorageChild::RecvRecordNames(const InfallibleTArray<nsCString>& aRecordNames,
|
||||
const GMPErr& aStatus)
|
||||
{
|
||||
if (mShutdown || mPendingRecordIterators.empty()) {
|
||||
return true;
|
||||
}
|
||||
RecordIteratorContext ctx = mPendingRecordIterators.front();
|
||||
mPendingRecordIterators.pop();
|
||||
|
||||
if (GMP_FAILED(aStatus)) {
|
||||
ctx.mFunc(nullptr, ctx.mUserArg, aStatus);
|
||||
} else {
|
||||
ctx.mFunc(new GMPRecordIteratorImpl(aRecordNames), ctx.mUserArg, GMPNoErr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPStorageChild::RecvShutdown()
|
||||
{
|
||||
@ -275,6 +351,9 @@ GMPStorageChild::RecvShutdown()
|
||||
// parent. We don't delete any objects here, as that may invalidate
|
||||
// GMPRecord pointers held by the GMP.
|
||||
mShutdown = true;
|
||||
while (!mPendingRecordIterators.empty()) {
|
||||
mPendingRecordIterators.pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "gmp-storage.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "gmp-platform.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
@ -70,6 +73,9 @@ public:
|
||||
|
||||
GMPErr Close(GMPRecordImpl* aRecord);
|
||||
|
||||
GMPErr EnumerateRecords(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
|
||||
void* aUserArg);
|
||||
|
||||
protected:
|
||||
~GMPStorageChild() {}
|
||||
|
||||
@ -81,11 +87,25 @@ protected:
|
||||
const InfallibleTArray<uint8_t>& aBytes) MOZ_OVERRIDE;
|
||||
virtual bool RecvWriteComplete(const nsCString& aRecordName,
|
||||
const GMPErr& aStatus) MOZ_OVERRIDE;
|
||||
virtual bool RecvRecordNames(const InfallibleTArray<nsCString>& aRecordNames,
|
||||
const GMPErr& aStatus) MOZ_OVERRIDE;
|
||||
virtual bool RecvShutdown() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsRefPtrHashtable<nsCStringHashKey, GMPRecordImpl> mRecords;
|
||||
GMPChild* mPlugin;
|
||||
|
||||
struct RecordIteratorContext {
|
||||
explicit RecordIteratorContext(RecvGMPRecordIteratorPtr aFunc,
|
||||
void* aUserArg)
|
||||
: mFunc(aFunc)
|
||||
, mUserArg(aUserArg)
|
||||
{}
|
||||
RecvGMPRecordIteratorPtr mFunc;
|
||||
void* mUserArg;
|
||||
};
|
||||
|
||||
std::queue<RecordIteratorContext> mPendingRecordIterators;
|
||||
bool mShutdown;
|
||||
};
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -104,9 +106,17 @@ OpenStorageFile(const nsCString& aRecordName,
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoString recordNameHash;
|
||||
recordNameHash.AppendInt(HashString(aRecordName.get()));
|
||||
f->Append(recordNameHash);
|
||||
nsAutoCString recordNameBase64;
|
||||
rv = Base64Encode(aRecordName, recordNameBase64);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Base64 can encode to a '/' character, which will mess with file paths,
|
||||
// so we need to replace that here with something that won't mess with paths.
|
||||
recordNameBase64.ReplaceChar('/', '-');
|
||||
|
||||
f->AppendNative(recordNameBase64);
|
||||
|
||||
auto mode = PR_RDWR | PR_CREATE_FILE;
|
||||
if (aMode == Truncate) {
|
||||
@ -193,6 +203,54 @@ public:
|
||||
return (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr;
|
||||
}
|
||||
|
||||
virtual GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) MOZ_OVERRIDE
|
||||
{
|
||||
nsCOMPtr<nsIFile> storageDir;
|
||||
nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mNodeId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
rv = storageDir->GetDirectoryEntries(getter_AddRefs(iter));
|
||||
if (NS_FAILED(rv)) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
bool hasMore;
|
||||
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
rv = iter->GetNext(getter_AddRefs(supports));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoCString leafName;
|
||||
rv = dirEntry->GetNativeLeafName(leafName);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The record's file name is the Base64 encode of the record name,
|
||||
// with '/' characters replaced with '-' characters. Base64 decode
|
||||
// to extract the file name.
|
||||
leafName.ReplaceChar('-', '/');
|
||||
nsAutoCString recordName;
|
||||
rv = Base64Decode(leafName, recordName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aOutRecordNames.AppendElement(recordName);
|
||||
}
|
||||
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
|
||||
{
|
||||
PRFileDesc* fd = mFiles.Get(aRecordName);
|
||||
@ -255,6 +313,12 @@ public:
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) MOZ_OVERRIDE
|
||||
{
|
||||
mRecords.EnumerateRead(EnumRecordNames, &aOutRecordNames);
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
|
||||
{
|
||||
Record* record = nullptr;
|
||||
@ -277,6 +341,16 @@ private:
|
||||
bool mIsOpen;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
EnumRecordNames(const nsACString& aKey,
|
||||
Record* aRecord,
|
||||
void* aUserArg)
|
||||
{
|
||||
nsTArray<nsCString>* names = reinterpret_cast<nsTArray<nsCString>*>(aUserArg);
|
||||
names->AppendElement(aKey);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsClassHashtable<nsCStringHashKey, Record> mRecords;
|
||||
};
|
||||
|
||||
@ -389,6 +463,22 @@ GMPStorageParent::RecvWrite(const nsCString& aRecordName,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPStorageParent::RecvGetRecordNames()
|
||||
{
|
||||
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
|
||||
|
||||
if (mShutdown) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> recordNames;
|
||||
GMPErr status = mStorage->GetRecordNames(recordNames);
|
||||
unused << SendRecordNames(recordNames, status);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPStorageParent::RecvClose(const nsCString& aRecordName)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@ public:
|
||||
nsTArray<uint8_t>& aOutBytes) = 0;
|
||||
virtual GMPErr Write(const nsCString& aRecordName,
|
||||
const nsTArray<uint8_t>& aBytes) = 0;
|
||||
virtual GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) = 0;
|
||||
virtual void Close(const nsCString& aRecordName) = 0;
|
||||
};
|
||||
|
||||
@ -42,6 +43,7 @@ protected:
|
||||
virtual bool RecvRead(const nsCString& aRecordName) MOZ_OVERRIDE;
|
||||
virtual bool RecvWrite(const nsCString& aRecordName,
|
||||
const InfallibleTArray<uint8_t>& aBytes) MOZ_OVERRIDE;
|
||||
virtual bool RecvGetRecordNames() MOZ_OVERRIDE;
|
||||
virtual bool RecvClose(const nsCString& aRecordName) MOZ_OVERRIDE;
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -19,6 +19,7 @@ child:
|
||||
OpenComplete(nsCString aRecordName, GMPErr aStatus);
|
||||
ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes);
|
||||
WriteComplete(nsCString aRecordName, GMPErr aStatus);
|
||||
RecordNames(nsCString[] aRecordNames, GMPErr aStatus);
|
||||
Shutdown();
|
||||
|
||||
parent:
|
||||
@ -26,6 +27,7 @@ parent:
|
||||
Read(nsCString aRecordName);
|
||||
Write(nsCString aRecordName, uint8_t[] aBytes);
|
||||
Close(nsCString aRecordName);
|
||||
GetRecordNames();
|
||||
__delete__();
|
||||
|
||||
};
|
||||
|
@ -37,7 +37,7 @@ struct GMPAudioCodec
|
||||
// AAC AudioSpecificConfig.
|
||||
// These are null/0 if not externally negotiated
|
||||
const uint8_t* mExtraData;
|
||||
size_t mExtraDataLen;
|
||||
uint32_t mExtraDataLen;
|
||||
};
|
||||
|
||||
#endif // GMP_AUDIO_CODEC_h_
|
||||
|
@ -45,6 +45,8 @@ typedef enum {
|
||||
GMPEncodeErr = 8,
|
||||
GMPNoKeyErr = 9,
|
||||
GMPCryptoErr = 10,
|
||||
GMPEndOfEnumeration = 11,
|
||||
GMPInvalidArgErr = 12,
|
||||
GMPLastErr // Placeholder, must be last. This enum's values must remain consecutive!
|
||||
} GMPErr;
|
||||
|
||||
|
@ -82,6 +82,22 @@ typedef GMPErr (*GMPCreateRecordPtr)(const char* aRecordName,
|
||||
typedef GMPErr (*GMPSetTimerOnMainThreadPtr)(GMPTask* aTask, int64_t aTimeoutMS);
|
||||
typedef GMPErr (*GMPGetCurrentTimePtr)(GMPTimestamp* aOutTime);
|
||||
|
||||
typedef void (*RecvGMPRecordIteratorPtr)(GMPRecordIterator* aRecordIterator,
|
||||
void* aUserArg,
|
||||
GMPErr aStatus);
|
||||
|
||||
// Creates a GMPCreateRecordIterator to enumerate the records in storage.
|
||||
// When the iterator is ready, the function at aRecvIteratorFunc
|
||||
// is called with the GMPRecordIterator as an argument. If the operation
|
||||
// fails, RecvGMPRecordIteratorPtr is called with a failure aStatus code.
|
||||
// The list that the iterator is covering is fixed when
|
||||
// GMPCreateRecordIterator is called, it is *not* updated when changes are
|
||||
// made to storage.
|
||||
// Iterator begins pointing at first record.
|
||||
// aUserArg is passed to the aRecvIteratorFunc upon completion.
|
||||
typedef GMPErr (*GMPCreateRecordIteratorPtr)(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
|
||||
void* aUserArg);
|
||||
|
||||
struct GMPPlatformAPI {
|
||||
// Increment the version when things change. Can only add to the struct,
|
||||
// do not change what already exists. Pointers to functions may be NULL
|
||||
@ -96,6 +112,7 @@ struct GMPPlatformAPI {
|
||||
GMPCreateRecordPtr createrecord;
|
||||
GMPSetTimerOnMainThreadPtr settimer;
|
||||
GMPGetCurrentTimePtr getcurrenttime;
|
||||
GMPCreateRecordIteratorPtr getrecordenumerator;
|
||||
};
|
||||
|
||||
#endif // GMP_PLATFORM_h_
|
||||
|
@ -110,4 +110,31 @@ class GMPRecordClient {
|
||||
virtual ~GMPRecordClient() {}
|
||||
};
|
||||
|
||||
// Iterates over the records that are available. Note: this list maintains
|
||||
// a snapshot of the records that were present when the iterator was created.
|
||||
// Create by calling the GMPCreateRecordIteratorPtr function on the
|
||||
// GMPPlatformAPI struct.
|
||||
// Iteration is in alphabetical order.
|
||||
class GMPRecordIterator {
|
||||
public:
|
||||
// Retrieve the name for the current record.
|
||||
// Returns GMPNoErr if successful, or GMPEndOfEnumeration if iteration has
|
||||
// reached the end.
|
||||
virtual GMPErr GetName(const char ** aOutName, uint32_t * aOutNameLength) = 0;
|
||||
|
||||
// Advance iteration to the next record.
|
||||
// Returns GMPNoErr if successful, or GMPEndOfEnumeration if iteration has
|
||||
// reached the end.
|
||||
virtual GMPErr NextRecord() = 0;
|
||||
|
||||
// Signals to the GMP host that the GMP is finished with the
|
||||
// GMPRecordIterator. GMPs must call this to release memory held by
|
||||
// the GMPRecordIterator. Do not access the GMPRecordIterator pointer
|
||||
// after calling this!
|
||||
// Memory retrieved by GetName is *not* valid after calling Close()!
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual ~GMPRecordIterator() {}
|
||||
};
|
||||
|
||||
#endif // GMP_STORAGE_h_
|
||||
|
@ -580,6 +580,67 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Update(NS_LITERAL_CSTRING("retrieve-plugin-voucher"));
|
||||
}
|
||||
|
||||
void TestGetRecordNamesInMemoryStorage() {
|
||||
TestGetRecordNames(true);
|
||||
}
|
||||
|
||||
nsCString mRecordNames;
|
||||
|
||||
void AppendIntPadded(nsACString& aString, uint32_t aInt) {
|
||||
if (aInt > 0 && aInt < 10) {
|
||||
aString.AppendLiteral("0");
|
||||
}
|
||||
aString.AppendInt(aInt);
|
||||
}
|
||||
|
||||
void TestGetRecordNames(bool aPrivateBrowsing) {
|
||||
CreateDecryptor(NS_LITERAL_STRING("foo.com"),
|
||||
NS_LITERAL_STRING("bar.com"),
|
||||
aPrivateBrowsing);
|
||||
|
||||
// Create a number of records of different names.
|
||||
const uint32_t num = 100;
|
||||
for (uint32_t i = 0; i < num; i++) {
|
||||
nsAutoCString response;
|
||||
response.AppendLiteral("stored data");
|
||||
AppendIntPadded(response, i);
|
||||
response.AppendLiteral(" test-data");
|
||||
AppendIntPadded(response, i);
|
||||
|
||||
if (i != 0) {
|
||||
mRecordNames.AppendLiteral(",");
|
||||
}
|
||||
mRecordNames.AppendLiteral("data");
|
||||
AppendIntPadded(mRecordNames, i);
|
||||
|
||||
nsAutoCString update;
|
||||
update.AppendLiteral("store data");
|
||||
AppendIntPadded(update, i);
|
||||
update.AppendLiteral(" test-data");
|
||||
AppendIntPadded(update, i);
|
||||
|
||||
nsIRunnable* continuation = nullptr;
|
||||
if (i + 1 == num) {
|
||||
continuation =
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::TestGetRecordNames_QueryNames);
|
||||
}
|
||||
Expect(response, continuation);
|
||||
Update(update);
|
||||
}
|
||||
}
|
||||
|
||||
void TestGetRecordNames_QueryNames() {
|
||||
nsCString response("record-names ");
|
||||
response.Append(mRecordNames);
|
||||
Expect(response,
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
Update(NS_LITERAL_CSTRING("retrieve-record-names"));
|
||||
}
|
||||
|
||||
void GetRecordNamesPersistentStorage() {
|
||||
TestGetRecordNames(false);
|
||||
}
|
||||
|
||||
void Expect(const nsCString& aMessage, nsIRunnable* aContinuation) {
|
||||
mExpected.AppendElement(ExpectedMessage(aMessage, aContinuation));
|
||||
}
|
||||
@ -751,3 +812,13 @@ TEST(GeckoMediaPlugins, GMPOutputProtection) {
|
||||
runner->DoTest(&GMPStorageTest::TestOutputProtection);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPStorageGetRecordNamesInMemoryStorage) {
|
||||
nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
|
||||
runner->DoTest(&GMPStorageTest::TestGetRecordNamesInMemoryStorage);
|
||||
}
|
||||
|
||||
TEST(GeckoMediaPlugins, GMPStorageGetRecordNamesPersistentStorage) {
|
||||
nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
|
||||
runner->DoTest(&GMPStorageTest::GetRecordNamesPersistentStorage);
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ public:
|
||||
decoder->SetResource(resource);
|
||||
|
||||
reader->Init(nullptr);
|
||||
reader->SetTaskQueue(
|
||||
new MediaTaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("TestMP4Reader"))));
|
||||
{
|
||||
// This needs to be done before invoking GetBuffered. This is normally
|
||||
// done by MediaDecoderStateMachine.
|
||||
@ -55,6 +57,10 @@ public:
|
||||
private:
|
||||
virtual ~TestBinding()
|
||||
{
|
||||
reader->GetTaskQueue()->Dispatch(NS_NewRunnableMethod(reader,
|
||||
&MP4Reader::Shutdown));
|
||||
reader->GetTaskQueue()->Shutdown();
|
||||
|
||||
decoder = nullptr;
|
||||
resource = nullptr;
|
||||
reader = nullptr;
|
||||
|
@ -110,10 +110,6 @@ MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
|
||||
MediaCodecProxy::~MediaCodecProxy()
|
||||
{
|
||||
releaseCodec();
|
||||
|
||||
// Complete all pending Binder ipc transactions
|
||||
IPCThreadState::self()->flushCommands();
|
||||
|
||||
cancelResource();
|
||||
}
|
||||
|
||||
@ -181,6 +177,7 @@ MediaCodecProxy::releaseCodec()
|
||||
|
||||
// Release MediaCodec
|
||||
if (mCodec != nullptr) {
|
||||
status_t err = mCodec->stop();
|
||||
mCodec->release();
|
||||
mCodec = nullptr;
|
||||
}
|
||||
@ -190,6 +187,10 @@ MediaCodecProxy::releaseCodec()
|
||||
// this value come from stagefright's AwesomePlayer.
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
// Complete all pending Binder ipc transactions
|
||||
IPCThreadState::self()->flushCommands();
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
@ -597,6 +598,8 @@ status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
|
||||
|
||||
bool MediaCodecProxy::IsWaitingResources()
|
||||
{
|
||||
// Write Lock for mCodec
|
||||
RWLock::AutoWLock awl(mCodecLock);
|
||||
return mCodec == nullptr;
|
||||
}
|
||||
|
||||
@ -607,11 +610,8 @@ bool MediaCodecProxy::IsDormantNeeded()
|
||||
|
||||
void MediaCodecProxy::ReleaseMediaResources()
|
||||
{
|
||||
if (mCodec.get()) {
|
||||
mCodec->stop();
|
||||
mCodec->release();
|
||||
mCodec.clear();
|
||||
}
|
||||
releaseCodec();
|
||||
cancelResource();
|
||||
}
|
||||
|
||||
void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {
|
||||
|
@ -613,16 +613,16 @@ PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
|
||||
}
|
||||
}
|
||||
|
||||
function signalingstatechangeLocalClose(state) {
|
||||
info("'onsignalingstatechange' event '" + state + "' received");
|
||||
is(state, "closed", "onsignalingstatechange event is closed");
|
||||
function signalingstatechangeLocalClose(e) {
|
||||
info("'signalingstatechange' event received");
|
||||
is(e.target.signalingState, "closed", "signalingState is closed");
|
||||
self.waitingForLocal = false;
|
||||
verifyClosed();
|
||||
}
|
||||
|
||||
function signalingstatechangeRemoteClose(state) {
|
||||
info("'onsignalingstatechange' event '" + state + "' received");
|
||||
is(state, "closed", "onsignalingstatechange event is closed");
|
||||
function signalingstatechangeRemoteClose(e) {
|
||||
info("'signalingstatechange' event received");
|
||||
is(e.target.signalingState, "closed", "signalingState is closed");
|
||||
self.waitingForRemote = false;
|
||||
verifyClosed();
|
||||
}
|
||||
@ -744,9 +744,10 @@ function PCT_setLocalDescription(peer, desc, stateExpected, onSuccess) {
|
||||
}
|
||||
}
|
||||
|
||||
peer.onsignalingstatechange = function (state) {
|
||||
info(peer + ": 'onsignalingstatechange' event '" + state + "' received");
|
||||
if(stateExpected === state && eventFired == false) {
|
||||
peer.onsignalingstatechange = function (e) {
|
||||
info(peer + ": 'signalingstatechange' event received");
|
||||
var state = e.target.signalingState;
|
||||
if(stateExpected === state && !eventFired) {
|
||||
eventFired = true;
|
||||
peer.setLocalDescStableEventDate = new Date();
|
||||
check_next_test();
|
||||
@ -812,9 +813,10 @@ function PCT_setRemoteDescription(peer, desc, stateExpected, onSuccess) {
|
||||
}
|
||||
}
|
||||
|
||||
peer.onsignalingstatechange = function (state) {
|
||||
info(peer + ": 'onsignalingstatechange' event '" + state + "' received");
|
||||
if(stateExpected === state && eventFired == false) {
|
||||
peer.onsignalingstatechange = function(e) {
|
||||
info(peer + ": 'signalingstatechange' event received");
|
||||
var state = e.target.signalingState;
|
||||
if(stateExpected === state && !eventFired) {
|
||||
eventFired = true;
|
||||
peer.setRemoteDescStableEventDate = new Date();
|
||||
check_next_test();
|
||||
@ -1618,7 +1620,6 @@ function PeerConnectionWrapper(label, configuration, h264) {
|
||||
* failure will be raised if an event of this type is caught.
|
||||
*
|
||||
* @param {Object} aEvent
|
||||
* Event data which includes the newly created data channel
|
||||
*/
|
||||
this._pc.onsignalingstatechange = function (anEvent) {
|
||||
info(self + ": 'onsignalingstatechange' event fired");
|
||||
@ -1930,7 +1931,7 @@ PeerConnectionWrapper.prototype = {
|
||||
logSignalingState: function PCW_logSignalingState() {
|
||||
var self = this;
|
||||
|
||||
function _logSignalingState(state) {
|
||||
function _logSignalingState(e) {
|
||||
var newstate = self._pc.signalingState;
|
||||
var oldstate = self.signalingStateLog[self.signalingStateLog.length - 1]
|
||||
if (Object.keys(signalingStateTransitions).indexOf(oldstate) != -1) {
|
||||
@ -1956,7 +1957,7 @@ PeerConnectionWrapper.prototype = {
|
||||
var self = this;
|
||||
|
||||
self._remote_ice_candidates.push(candidate);
|
||||
if (self.signalingstate === 'closed') {
|
||||
if (self.signalingState === 'closed') {
|
||||
info("Received ICE candidate for closed PeerConnection - discarding");
|
||||
return;
|
||||
}
|
||||
|
@ -24,8 +24,9 @@
|
||||
var exception = null;
|
||||
|
||||
// handle the event which the close() triggers
|
||||
test.pcLocal.onsignalingstatechange = function (state) {
|
||||
is(state, "closed", "Received expected onsignalingstatechange event 'closed'");
|
||||
test.pcLocal.onsignalingstatechange = function (e) {
|
||||
is(e.target.signalingState, "closed",
|
||||
"Received expected onsignalingstatechange event on 'closed'");
|
||||
}
|
||||
|
||||
test.pcLocal.close();
|
||||
@ -39,8 +40,9 @@
|
||||
exception = null;
|
||||
|
||||
// handle the event which the close() triggers
|
||||
test.pcRemote.onsignalingstatechange = function (state) {
|
||||
is(state, "closed", "Received expected onsignalingstatechange event 'closed'");
|
||||
test.pcRemote.onsignalingstatechange = function (e) {
|
||||
is(e.target.signalingState, "closed",
|
||||
"Received expected onsignalingstatechange event on 'closed'");
|
||||
}
|
||||
|
||||
test.pcRemote.close();
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
runNetworkTest(function () {
|
||||
var pc = new mozRTCPeerConnection();
|
||||
var signalStateChanged = false;
|
||||
var exception = null;
|
||||
var eTimeout = null;
|
||||
|
||||
@ -25,12 +24,15 @@
|
||||
is(pc.iceConnectionState, "new", "Initial iceConnectionState is 'new'");
|
||||
is(pc.iceGatheringState, "new", "Initial iceGatheringState is 'new'");
|
||||
|
||||
pc.onsignalingstatechange = function(aEvent) {
|
||||
var finish;
|
||||
var finished = new Promise(function(resolve) {
|
||||
finish = resolve;
|
||||
});
|
||||
|
||||
pc.onsignalingstatechange = function(e) {
|
||||
clearTimeout(eTimeout);
|
||||
signalStateChanged = true;
|
||||
is(aEvent, "closed", "onsignalingstatechange event is 'closed'");
|
||||
is(pc.signalingState, "closed", "Event callback signalingState is 'closed'");
|
||||
is(pc.iceConnectionState, "closed", "Event callback iceConnectionState is 'closed'");
|
||||
is(pc.signalingState, "closed", "signalingState is 'closed'");
|
||||
is(pc.iceConnectionState, "closed", "iceConnectionState is 'closed'");
|
||||
|
||||
try {
|
||||
pc.close();
|
||||
@ -82,23 +84,13 @@
|
||||
pc.setIdentityProvider("Invalid Provider")},
|
||||
"setIdentityProvider() on closed PC raised expected exception");
|
||||
|
||||
// in case we are ending the test from within here
|
||||
if(pc !== null) {
|
||||
pc = null;
|
||||
networkTestFinished();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
// This is only a shortcut to prevent a mochitest timeout in case the
|
||||
// event does not fire
|
||||
// This prevents a mochitest timeout in case the event does not fire
|
||||
eTimeout = setTimeout(function() {
|
||||
ok(signalStateChanged, "Failed to receive expected onsignalingstatechange event in 60s");
|
||||
|
||||
// in case we are ending the test in this timeout
|
||||
if (pc !== null) {
|
||||
pc = null;
|
||||
networkTestFinished();
|
||||
}
|
||||
ok(false, "Failed to receive expected onsignalingstatechange event in 60s");
|
||||
finish();
|
||||
}, 60000);
|
||||
|
||||
try {
|
||||
@ -107,20 +99,10 @@
|
||||
exception = e;
|
||||
}
|
||||
is(exception, null, "closing the connection raises no exception");
|
||||
if (pc !== null) {
|
||||
is(pc.signalingState, "closed", "Final signalingState is 'closed'");
|
||||
is(pc.iceConnectionState, "closed", "Final iceConnectionState is 'closed'");
|
||||
}
|
||||
|
||||
if (signalStateChanged) {
|
||||
clearTimeout(eTimeout);
|
||||
// in case we are ending the test outside the even handler
|
||||
if (pc !== null) {
|
||||
pc = null;
|
||||
networkTestFinished();
|
||||
}
|
||||
}
|
||||
is(pc.signalingState, "closed", "Final signalingState is 'closed'");
|
||||
is(pc.iceConnectionState, "closed", "Final iceConnectionState is 'closed'");
|
||||
|
||||
finished.then(networkTestFinished);
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -247,9 +247,7 @@ DelayBuffer::UpdateUpmixChannels(int aNewReadChunk, uint32_t aChannelCount,
|
||||
"Smoothing is making feedback delay too small.");
|
||||
|
||||
mLastReadChunk = aNewReadChunk;
|
||||
// Missing assignment operator is bug 976927
|
||||
mUpmixChannels.ReplaceElementsAt(0, mUpmixChannels.Length(),
|
||||
mChunks[aNewReadChunk].mChannelData);
|
||||
mUpmixChannels = mChunks[aNewReadChunk].mChannelData;
|
||||
MOZ_ASSERT(mUpmixChannels.Length() <= aChannelCount);
|
||||
if (mUpmixChannels.Length() < aChannelCount) {
|
||||
if (aChannelInterpretation == ChannelInterpretation::Speakers) {
|
||||
|
@ -2820,7 +2820,7 @@ nsPluginInstanceOwner::GetContentsScaleFactor(double *result)
|
||||
nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(mContent->OwnerDoc());
|
||||
if (presShell) {
|
||||
scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
|
||||
presShell->GetPresContext()->DeviceContext()->UnscaledAppUnitsPerDevPixel();
|
||||
presShell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
|
||||
}
|
||||
#endif
|
||||
*result = scaleFactor;
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
typedef object JSON;
|
||||
// FIXME(nsm): Bug 739173: FormData is not available in workers.
|
||||
// typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or ScalarValueString or URLSearchParams) BodyInit;
|
||||
typedef (ArrayBuffer or ArrayBufferView or Blob or ScalarValueString or URLSearchParams) BodyInit;
|
||||
// typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or USVString or URLSearchParams) BodyInit;
|
||||
typedef (ArrayBuffer or ArrayBufferView or Blob or USVString or URLSearchParams) BodyInit;
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface Body {
|
||||
@ -24,7 +24,7 @@ interface Body {
|
||||
[Throws]
|
||||
Promise<JSON> json();
|
||||
[Throws]
|
||||
Promise<ScalarValueString> text();
|
||||
Promise<USVString> text();
|
||||
};
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
|
@ -7,12 +7,12 @@
|
||||
interface nsIFile;
|
||||
|
||||
[Constructor(sequence<(ArrayBuffer or ArrayBufferView or Blob or DOMString)> fileBits,
|
||||
ScalarValueString fileName, optional FilePropertyBag options),
|
||||
USVString fileName, optional FilePropertyBag options),
|
||||
|
||||
// These constructors are just for chrome callers:
|
||||
Constructor(Blob fileBits, optional ChromeFilePropertyBag options),
|
||||
Constructor(nsIFile fileBits, optional ChromeFilePropertyBag options),
|
||||
Constructor(ScalarValueString fileBits, optional ChromeFilePropertyBag options),
|
||||
Constructor(USVString fileBits, optional ChromeFilePropertyBag options),
|
||||
|
||||
Exposed=(Window,Worker)]
|
||||
interface File : Blob {
|
||||
|
@ -7,14 +7,14 @@
|
||||
* https://fetch.spec.whatwg.org/#request-class
|
||||
*/
|
||||
|
||||
typedef (Request or ScalarValueString) RequestInfo;
|
||||
typedef (Request or USVString) RequestInfo;
|
||||
|
||||
[Constructor(RequestInfo input, optional RequestInit init),
|
||||
Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::Headers::PrefEnabled"]
|
||||
interface Request {
|
||||
readonly attribute ByteString method;
|
||||
readonly attribute ScalarValueString url;
|
||||
readonly attribute USVString url;
|
||||
readonly attribute Headers headers;
|
||||
|
||||
readonly attribute DOMString referrer;
|
||||
|
@ -12,11 +12,11 @@
|
||||
Func="mozilla::dom::Headers::PrefEnabled"]
|
||||
interface Response {
|
||||
static Response error();
|
||||
static Response redirect(ScalarValueString url, optional unsigned short status = 302);
|
||||
static Response redirect(USVString url, optional unsigned short status = 302);
|
||||
|
||||
readonly attribute ResponseType type;
|
||||
|
||||
readonly attribute ScalarValueString url;
|
||||
readonly attribute USVString url;
|
||||
readonly attribute unsigned short status;
|
||||
readonly attribute ByteString statusText;
|
||||
readonly attribute Headers headers;
|
||||
|
@ -20,11 +20,11 @@ interface ServiceWorkerContainer : EventTarget {
|
||||
readonly attribute Promise<ServiceWorkerRegistration> ready;
|
||||
|
||||
[Throws]
|
||||
Promise<ServiceWorkerRegistration> register(ScalarValueString scriptURL,
|
||||
Promise<ServiceWorkerRegistration> register(USVString scriptURL,
|
||||
optional RegistrationOptionList options);
|
||||
|
||||
[Throws]
|
||||
Promise<ServiceWorkerRegistration> getRegistration(optional ScalarValueString documentURL = "");
|
||||
Promise<ServiceWorkerRegistration> getRegistration(optional USVString documentURL = "");
|
||||
|
||||
[Throws]
|
||||
Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
|
||||
@ -47,5 +47,5 @@ partial interface ServiceWorkerContainer {
|
||||
};
|
||||
|
||||
dictionary RegistrationOptionList {
|
||||
ScalarValueString scope = "/";
|
||||
USVString scope = "/";
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ interface ServiceWorkerRegistration : EventTarget {
|
||||
[Unforgeable] readonly attribute ServiceWorker? waiting;
|
||||
[Unforgeable] readonly attribute ServiceWorker? active;
|
||||
|
||||
readonly attribute ScalarValueString scope;
|
||||
readonly attribute USVString scope;
|
||||
|
||||
[Throws]
|
||||
Promise<boolean> unregister();
|
||||
|
@ -31,7 +31,7 @@ interface TestInterfaceJS {
|
||||
// For testing bug 968335.
|
||||
DOMString getCallerPrincipal();
|
||||
|
||||
DOMString convertSVS(ScalarValueString svs);
|
||||
DOMString convertSVS(USVString svs);
|
||||
|
||||
(TestInterfaceJS or long) pingPongUnion((TestInterfaceJS or long) something);
|
||||
(DOMString or TestInterfaceJS?) pingPongUnionContainingNull((TestInterfaceJS? or DOMString) something);
|
||||
|
@ -13,16 +13,16 @@
|
||||
* http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
|
||||
*/
|
||||
|
||||
[Constructor(optional ScalarValueString init = ""),
|
||||
[Constructor(optional USVString init = ""),
|
||||
Constructor(URLSearchParams init),
|
||||
Exposed=(Window,Worker)]
|
||||
interface URLSearchParams {
|
||||
void append(ScalarValueString name, ScalarValueString value);
|
||||
void delete(ScalarValueString name);
|
||||
ScalarValueString? get(ScalarValueString name);
|
||||
sequence<ScalarValueString> getAll(ScalarValueString name);
|
||||
boolean has(ScalarValueString name);
|
||||
void set(ScalarValueString name, ScalarValueString value);
|
||||
// iterable<ScalarValueString, ScalarValueString>; - Bug 1085284
|
||||
void append(USVString name, USVString value);
|
||||
void delete(USVString name);
|
||||
USVString? get(USVString name);
|
||||
sequence<USVString> getAll(USVString name);
|
||||
boolean has(USVString name);
|
||||
void set(USVString name, USVString value);
|
||||
// iterable<USVString, USVString>; - Bug 1085284
|
||||
stringifier;
|
||||
};
|
||||
|
@ -17,31 +17,31 @@
|
||||
Exposed=(Window, Worker)]
|
||||
interface URLUtils {
|
||||
// Bug 824857: no support for stringifier attributes yet.
|
||||
// stringifier attribute ScalarValueString href;
|
||||
// stringifier attribute USVString href;
|
||||
[Throws, CrossOriginWritable=Location]
|
||||
attribute ScalarValueString href;
|
||||
attribute USVString href;
|
||||
[Throws]
|
||||
readonly attribute ScalarValueString origin;
|
||||
readonly attribute USVString origin;
|
||||
|
||||
[Throws]
|
||||
attribute ScalarValueString protocol;
|
||||
attribute USVString protocol;
|
||||
[Throws]
|
||||
attribute ScalarValueString username;
|
||||
attribute USVString username;
|
||||
[Throws]
|
||||
attribute ScalarValueString password;
|
||||
attribute USVString password;
|
||||
[Throws]
|
||||
attribute ScalarValueString host;
|
||||
attribute USVString host;
|
||||
[Throws]
|
||||
attribute ScalarValueString hostname;
|
||||
attribute USVString hostname;
|
||||
[Throws]
|
||||
attribute ScalarValueString port;
|
||||
attribute USVString port;
|
||||
[Throws]
|
||||
attribute ScalarValueString pathname;
|
||||
attribute USVString pathname;
|
||||
[Throws]
|
||||
attribute ScalarValueString search;
|
||||
attribute USVString search;
|
||||
|
||||
[Throws]
|
||||
attribute ScalarValueString hash;
|
||||
attribute USVString hash;
|
||||
|
||||
// Bug 824857 should remove this.
|
||||
[Throws]
|
||||
|
@ -17,14 +17,14 @@
|
||||
Exposed=(Window, Worker)]
|
||||
interface URLUtilsReadOnly {
|
||||
stringifier;
|
||||
readonly attribute ScalarValueString href;
|
||||
readonly attribute USVString href;
|
||||
|
||||
readonly attribute ScalarValueString protocol;
|
||||
readonly attribute ScalarValueString host;
|
||||
readonly attribute ScalarValueString hostname;
|
||||
readonly attribute ScalarValueString port;
|
||||
readonly attribute ScalarValueString pathname;
|
||||
readonly attribute ScalarValueString search;
|
||||
readonly attribute ScalarValueString hash;
|
||||
readonly attribute ScalarValueString origin;
|
||||
readonly attribute USVString protocol;
|
||||
readonly attribute USVString host;
|
||||
readonly attribute USVString hostname;
|
||||
readonly attribute USVString port;
|
||||
readonly attribute USVString pathname;
|
||||
readonly attribute USVString search;
|
||||
readonly attribute USVString hash;
|
||||
readonly attribute USVString origin;
|
||||
};
|
||||
|
@ -304,7 +304,7 @@ WorkerGlobalScope::GetPerformance()
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WorkerGlobalScope::Fetch(const RequestOrScalarValueString& aInput,
|
||||
WorkerGlobalScope::Fetch(const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
return FetchRequest(this, aInput, aInit, aRv);
|
||||
|
@ -17,7 +17,7 @@ namespace dom {
|
||||
class Console;
|
||||
class Function;
|
||||
class Promise;
|
||||
class RequestOrScalarValueString;
|
||||
class RequestOrUSVString;
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@ -126,7 +126,7 @@ public:
|
||||
Performance* GetPerformance();
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Fetch(const RequestOrScalarValueString& aInput, const RequestInit& aInit, ErrorResult& aRv);
|
||||
Fetch(const RequestOrUSVString& aInput, const RequestInit& aInit, ErrorResult& aRv);
|
||||
};
|
||||
|
||||
class DedicatedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
|
||||
|
@ -738,13 +738,13 @@ ShadowLayerForwarder::DeallocShmem(ipc::Shmem& aShmem)
|
||||
bool
|
||||
ShadowLayerForwarder::IPCOpen() const
|
||||
{
|
||||
return mShadowManager->IPCOpen();
|
||||
return HasShadowManager() && mShadowManager->IPCOpen();
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowLayerForwarder::IsSameProcess() const
|
||||
{
|
||||
if (!mShadowManager->IPCOpen()) {
|
||||
if (!HasShadowManager() || !mShadowManager->IPCOpen()) {
|
||||
return false;
|
||||
}
|
||||
return mShadowManager->OtherProcess() == kInvalidProcessHandle;
|
||||
|
@ -244,9 +244,9 @@ nsFontCache::Flush()
|
||||
|
||||
nsDeviceContext::nsDeviceContext()
|
||||
: mWidth(0), mHeight(0), mDepth(0),
|
||||
mAppUnitsPerDevPixel(-1), mAppUnitsPerDevNotScaledPixel(-1),
|
||||
mAppUnitsPerDevPixel(-1), mAppUnitsPerDevPixelAtUnitFullZoom(-1),
|
||||
mAppUnitsPerPhysicalInch(-1),
|
||||
mPixelScale(1.0f), mPrintingScale(1.0f),
|
||||
mFullZoom(1.0f), mPrintingScale(1.0f),
|
||||
mFontCache(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "nsDeviceContext created off main thread");
|
||||
@ -333,7 +333,7 @@ nsDeviceContext::SetDPI()
|
||||
break;
|
||||
}
|
||||
|
||||
mAppUnitsPerDevNotScaledPixel =
|
||||
mAppUnitsPerDevPixelAtUnitFullZoom =
|
||||
NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
|
||||
} else {
|
||||
// A value of -1 means use the maximum of 96 and the system DPI.
|
||||
@ -358,14 +358,14 @@ nsDeviceContext::SetDPI()
|
||||
: CSSToLayoutDeviceScale(1.0);
|
||||
double devPixelsPerCSSPixel = scale.scale;
|
||||
|
||||
mAppUnitsPerDevNotScaledPixel =
|
||||
mAppUnitsPerDevPixelAtUnitFullZoom =
|
||||
std::max(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel));
|
||||
}
|
||||
|
||||
NS_ASSERTION(dpi != -1.0, "no dpi set");
|
||||
|
||||
mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevNotScaledPixel);
|
||||
UpdateScaledAppUnits();
|
||||
mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevPixelAtUnitFullZoom);
|
||||
UpdateAppUnitsForFullZoom();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -722,33 +722,33 @@ nsDeviceContext::CalcPrintingSize()
|
||||
}
|
||||
|
||||
bool nsDeviceContext::CheckDPIChange() {
|
||||
int32_t oldDevPixels = mAppUnitsPerDevNotScaledPixel;
|
||||
int32_t oldDevPixels = mAppUnitsPerDevPixelAtUnitFullZoom;
|
||||
int32_t oldInches = mAppUnitsPerPhysicalInch;
|
||||
|
||||
SetDPI();
|
||||
|
||||
return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
|
||||
return oldDevPixels != mAppUnitsPerDevPixelAtUnitFullZoom ||
|
||||
oldInches != mAppUnitsPerPhysicalInch;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDeviceContext::SetPixelScale(float aScale)
|
||||
nsDeviceContext::SetFullZoom(float aScale)
|
||||
{
|
||||
if (aScale <= 0) {
|
||||
NS_NOTREACHED("Invalid pixel scale value");
|
||||
NS_NOTREACHED("Invalid full zoom value");
|
||||
return false;
|
||||
}
|
||||
int32_t oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
|
||||
mPixelScale = aScale;
|
||||
UpdateScaledAppUnits();
|
||||
mFullZoom = aScale;
|
||||
UpdateAppUnitsForFullZoom();
|
||||
return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
|
||||
}
|
||||
|
||||
void
|
||||
nsDeviceContext::UpdateScaledAppUnits()
|
||||
nsDeviceContext::UpdateAppUnitsForFullZoom()
|
||||
{
|
||||
mAppUnitsPerDevPixel =
|
||||
std::max(1, NSToIntRound(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale));
|
||||
// adjust mPixelScale to reflect appunit rounding
|
||||
mPixelScale = float(mAppUnitsPerDevNotScaledPixel) / mAppUnitsPerDevPixel;
|
||||
std::max(1, NSToIntRound(float(mAppUnitsPerDevPixelAtUnitFullZoom) / mFullZoom));
|
||||
// adjust mFullZoom to reflect appunit rounding
|
||||
mFullZoom = float(mAppUnitsPerDevPixelAtUnitFullZoom) / mAppUnitsPerDevPixel;
|
||||
}
|
||||
|
@ -103,11 +103,11 @@ public:
|
||||
static int32_t AppUnitsPerCSSInch() { return mozilla::AppUnitsPerCSSInch(); }
|
||||
|
||||
/**
|
||||
* Get the unscaled ratio of app units to dev pixels; useful if something
|
||||
* needs to be converted from to unscaled pixels
|
||||
* Get the ratio of app units to dev pixels that would be used at unit
|
||||
* (100%) full zoom.
|
||||
*/
|
||||
int32_t UnscaledAppUnitsPerDevPixel() const
|
||||
{ return mAppUnitsPerDevNotScaledPixel; }
|
||||
int32_t AppUnitsPerDevPixelAtUnitFullZoom() const
|
||||
{ return mAppUnitsPerDevPixelAtUnitFullZoom; }
|
||||
|
||||
/**
|
||||
* Get the nsFontMetrics that describe the properties of
|
||||
@ -234,16 +234,16 @@ public:
|
||||
bool CheckDPIChange();
|
||||
|
||||
/**
|
||||
* Set the pixel scaling factor: all lengths are multiplied by this factor
|
||||
* Set the full zoom factor: all lengths are multiplied by this factor
|
||||
* when we convert them to device pixels. Returns whether the ratio of
|
||||
* app units to dev pixels changed because of the scale factor.
|
||||
* app units to dev pixels changed because of the zoom factor.
|
||||
*/
|
||||
bool SetPixelScale(float aScale);
|
||||
bool SetFullZoom(float aScale);
|
||||
|
||||
/**
|
||||
* Returns the pixel scaling factor (page zoom factor) applied.
|
||||
* Returns the page full zoom factor applied.
|
||||
*/
|
||||
float GetPixelScale() const { return mPixelScale; }
|
||||
float GetFullZoom() const { return mFullZoom; }
|
||||
|
||||
/**
|
||||
* True if this device context was created for printing.
|
||||
@ -259,15 +259,15 @@ private:
|
||||
void ComputeFullAreaUsingScreen(nsRect *outRect);
|
||||
void FindScreen(nsIScreen **outScreen);
|
||||
void CalcPrintingSize();
|
||||
void UpdateScaledAppUnits();
|
||||
void UpdateAppUnitsForFullZoom();
|
||||
|
||||
nscoord mWidth;
|
||||
nscoord mHeight;
|
||||
uint32_t mDepth;
|
||||
int32_t mAppUnitsPerDevPixel;
|
||||
int32_t mAppUnitsPerDevNotScaledPixel;
|
||||
int32_t mAppUnitsPerDevPixelAtUnitFullZoom;
|
||||
int32_t mAppUnitsPerPhysicalInch;
|
||||
float mPixelScale;
|
||||
float mFullZoom;
|
||||
float mPrintingScale;
|
||||
|
||||
nsFontCache* mFontCache;
|
||||
|
@ -581,6 +581,50 @@ function ArrayFill(value, start = 0, end = undefined) {
|
||||
return O;
|
||||
}
|
||||
|
||||
// Proposed for ES7:
|
||||
// https://github.com/domenic/Array.prototype.includes/blob/master/spec.md
|
||||
function ArrayIncludes(searchElement, fromIndex = 0) {
|
||||
// Steps 1-2.
|
||||
var O = ToObject(this);
|
||||
|
||||
// Steps 3-4.
|
||||
var len = ToLength(O.length);
|
||||
|
||||
// Step 5.
|
||||
if (len === 0)
|
||||
return false;
|
||||
|
||||
// Steps 6-7.
|
||||
var n = ToInteger(fromIndex);
|
||||
|
||||
// Step 8.
|
||||
var k;
|
||||
if (n >= 0) {
|
||||
k = n;
|
||||
}
|
||||
// Step 9.
|
||||
else {
|
||||
// Step a.
|
||||
k = len + n;
|
||||
// Step b.
|
||||
if (k < 0)
|
||||
k = 0;
|
||||
}
|
||||
|
||||
// Step 10.
|
||||
while (k < len) {
|
||||
// Steps a-c.
|
||||
if (SameValueZero(searchElement, O[k]))
|
||||
return true;
|
||||
|
||||
// Step d.
|
||||
k++;
|
||||
}
|
||||
|
||||
// Step 11.
|
||||
return false;
|
||||
}
|
||||
|
||||
#define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
|
||||
#define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
|
||||
#define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
|
||||
|
@ -103,6 +103,11 @@ function ToLength(v) {
|
||||
return std_Math_min(v, 0x1fffffffffffff);
|
||||
}
|
||||
|
||||
// Spec: ECMAScript Draft, 6th edition Oct 14, 2014, 7.2.4.
|
||||
function SameValueZero(x, y) {
|
||||
return x === y || (x !== x && y !== y);
|
||||
}
|
||||
|
||||
/********** Testing code **********/
|
||||
|
||||
#ifdef ENABLE_PARALLEL_JS
|
||||
|
@ -10250,12 +10250,10 @@ CodeGenerator::visitDebugger(LDebugger *ins)
|
||||
Register cx = ToRegister(ins->getTemp(0));
|
||||
Register temp = ToRegister(ins->getTemp(1));
|
||||
|
||||
// The check for cx->compartment()->isDebuggee() could be inlined, but the
|
||||
// performance of |debugger;| does not matter.
|
||||
masm.loadJSContext(cx);
|
||||
masm.setupUnalignedABICall(1, temp);
|
||||
masm.passABIArg(cx);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, IsCompartmentDebuggee));
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, GlobalHasLiveOnDebuggerStatement));
|
||||
|
||||
Label bail;
|
||||
masm.branchIfTrueBool(ReturnReg, &bail);
|
||||
|
@ -418,12 +418,10 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx
|
||||
jsbytecode *pc = frame.pc();
|
||||
|
||||
if (cx->compartment()->isDebuggee()) {
|
||||
// We need to bail when debug mode is active to observe the Debugger's
|
||||
// exception unwinding handler if either a Debugger is observing all
|
||||
// execution in the compartment, or it has a live onExceptionUnwind
|
||||
// hook, or it has observed this frame (e.g., for onPop).
|
||||
bool shouldBail = cx->compartment()->debugObservesAllExecution() ||
|
||||
Debugger::hasLiveOnExceptionUnwind(cx->global());
|
||||
// We need to bail when we are the debuggee of a Debugger with a live
|
||||
// onExceptionUnwind hook, or if a Debugger has observed this frame
|
||||
// (e.g., for onPop).
|
||||
bool shouldBail = Debugger::hasLiveHook(cx->global(), Debugger::OnExceptionUnwind);
|
||||
if (!shouldBail) {
|
||||
JitActivation *act = cx->mainThread().activation()->asJit();
|
||||
RematerializedFrame *rematFrame =
|
||||
|
@ -1046,9 +1046,10 @@ OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *m
|
||||
}
|
||||
|
||||
bool
|
||||
IsCompartmentDebuggee(JSContext *cx)
|
||||
GlobalHasLiveOnDebuggerStatement(JSContext *cx)
|
||||
{
|
||||
return cx->compartment()->isDebuggee();
|
||||
return cx->compartment()->isDebuggee() &&
|
||||
Debugger::hasLiveHook(cx->global(), Debugger::OnDebuggerStatement);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -726,7 +726,7 @@ JSObject *InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleO
|
||||
|
||||
bool HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn);
|
||||
bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn);
|
||||
bool IsCompartmentDebuggee(JSContext *cx);
|
||||
bool GlobalHasLiveOnDebuggerStatement(JSContext *cx);
|
||||
|
||||
bool EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val,
|
||||
Handle<StaticWithObject *> templ);
|
||||
|
@ -3227,6 +3227,10 @@ static const JSFunctionSpec array_methods[] = {
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0,0),
|
||||
JS_SELF_HOSTED_FN("entries", "ArrayEntries", 0,0),
|
||||
JS_SELF_HOSTED_FN("keys", "ArrayKeys", 0,0),
|
||||
|
||||
/* ES7 additions */
|
||||
JS_SELF_HOSTED_FN("includes", "ArrayIncludes", 2,0),
|
||||
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -18,6 +18,7 @@ TEST_FILES = \
|
||||
ecma_3_1/ \
|
||||
ecma_5/ \
|
||||
ecma_6/ \
|
||||
ecma_7/ \
|
||||
Intl/ \
|
||||
js1_1/ \
|
||||
js1_2/ \
|
||||
|
0
js/src/tests/ecma_7/Array/browser.js
Normal file
0
js/src/tests/ecma_7/Array/browser.js
Normal file
59
js/src/tests/ecma_7/Array/includes.js
Normal file
59
js/src/tests/ecma_7/Array/includes.js
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var BUGNUMBER = 1069063;
|
||||
var summary = "Implement Array.prototype.includes";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
assertEq(typeof [].includes, "function");
|
||||
assertEq([].includes.length, 1);
|
||||
|
||||
assertTrue([1, 2, 3].includes(2));
|
||||
assertTrue([1,,2].includes(2));
|
||||
assertTrue([1, 2, 3].includes(2, 1));
|
||||
assertTrue([1, 2, 3].includes(2, -2));
|
||||
assertTrue([1, 2, 3].includes(2, -100));
|
||||
assertTrue([Object, Function, Array].includes(Function));
|
||||
assertTrue([-0].includes(0));
|
||||
assertTrue([NaN].includes(NaN));
|
||||
assertTrue([,].includes());
|
||||
assertTrue(staticIncludes("123", "2"));
|
||||
assertTrue(staticIncludes({length: 3, 1: 2}, 2));
|
||||
assertTrue(staticIncludes({length: 3, 1: 2, get 3(){throw ""}}, 2));
|
||||
assertTrue(staticIncludes({length: 3, get 1() {return 2}}, 2));
|
||||
assertTrue(staticIncludes({__proto__: {1: 2}, length: 3}, 2));
|
||||
assertTrue(staticIncludes(new Proxy([1], {get(){return 2}}), 2));
|
||||
|
||||
assertFalse([1, 2, 3].includes("2"));
|
||||
assertFalse([1, 2, 3].includes(2, 2));
|
||||
assertFalse([1, 2, 3].includes(2, -1));
|
||||
assertFalse([undefined].includes(NaN));
|
||||
assertFalse([{}].includes({}));
|
||||
assertFalse(staticIncludes({length: 3, 1: 2}, 2, 2));
|
||||
assertFalse(staticIncludes({length: 3, get 0(){delete this[1]}, 1: 2}, 2));
|
||||
assertFalse(staticIncludes({length: -100, 0: 1}, 1));
|
||||
|
||||
assertThrowsInstanceOf(() => staticIncludes(), TypeError);
|
||||
assertThrowsInstanceOf(() => staticIncludes(null), TypeError);
|
||||
assertThrowsInstanceOf(() => staticIncludes({get length(){throw TypeError()}}), TypeError);
|
||||
assertThrowsInstanceOf(() => staticIncludes({length: 3, get 1() {throw TypeError()}}, 2), TypeError);
|
||||
assertThrowsInstanceOf(() => staticIncludes({__proto__: {get 1() {throw TypeError()}}, length: 3}, 2), TypeError);
|
||||
assertThrowsInstanceOf(() => staticIncludes(new Proxy([1], {get(){throw TypeError()}})), TypeError);
|
||||
|
||||
function assertTrue(v) {
|
||||
assertEq(v, true);
|
||||
}
|
||||
|
||||
function assertFalse(v) {
|
||||
assertEq(v, false);
|
||||
}
|
||||
|
||||
function staticIncludes(o, v, f) {
|
||||
return [].includes.call(o, v, f);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
0
js/src/tests/ecma_7/Array/shell.js
Normal file
0
js/src/tests/ecma_7/Array/shell.js
Normal file
0
js/src/tests/ecma_7/browser.js
Normal file
0
js/src/tests/ecma_7/browser.js
Normal file
205
js/src/tests/ecma_7/shell.js
Normal file
205
js/src/tests/ecma_7/shell.js
Normal file
@ -0,0 +1,205 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
if (typeof assertThrowsInstanceOf === 'undefined') {
|
||||
var assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) {
|
||||
var fullmsg;
|
||||
try {
|
||||
f();
|
||||
} catch (exc) {
|
||||
if (exc instanceof ctor)
|
||||
return;
|
||||
fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc;
|
||||
}
|
||||
if (fullmsg === undefined)
|
||||
fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown";
|
||||
if (msg !== undefined)
|
||||
fullmsg += " - " + msg;
|
||||
throw new Error(fullmsg);
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof assertThrowsValue === 'undefined') {
|
||||
var assertThrowsValue = function assertThrowsValue(f, val, msg) {
|
||||
var fullmsg;
|
||||
try {
|
||||
f();
|
||||
} catch (exc) {
|
||||
if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val))
|
||||
return;
|
||||
fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
|
||||
}
|
||||
if (fullmsg === undefined)
|
||||
fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown";
|
||||
if (msg !== undefined)
|
||||
fullmsg += " - " + msg;
|
||||
throw new Error(fullmsg);
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof assertDeepEq === 'undefined') {
|
||||
var assertDeepEq = (function(){
|
||||
var call = Function.prototype.call,
|
||||
Array_isArray = Array.isArray,
|
||||
Map_ = Map,
|
||||
Error_ = Error,
|
||||
Map_has = call.bind(Map.prototype.has),
|
||||
Map_get = call.bind(Map.prototype.get),
|
||||
Map_set = call.bind(Map.prototype.set),
|
||||
Object_toString = call.bind(Object.prototype.toString),
|
||||
Function_toString = call.bind(Function.prototype.toString),
|
||||
Object_getPrototypeOf = Object.getPrototypeOf,
|
||||
Object_hasOwnProperty = call.bind(Object.prototype.hasOwnProperty),
|
||||
Object_getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor,
|
||||
Object_isExtensible = Object.isExtensible,
|
||||
Object_getOwnPropertyNames = Object.getOwnPropertyNames,
|
||||
uneval_ = uneval;
|
||||
|
||||
// Return true iff ES6 Type(v) isn't Object.
|
||||
// Note that `typeof document.all === "undefined"`.
|
||||
function isPrimitive(v) {
|
||||
return (v === null ||
|
||||
v === undefined ||
|
||||
typeof v === "boolean" ||
|
||||
typeof v === "number" ||
|
||||
typeof v === "string" ||
|
||||
typeof v === "symbol");
|
||||
}
|
||||
|
||||
function assertSameValue(a, b, msg) {
|
||||
try {
|
||||
assertEq(a, b);
|
||||
} catch (exc) {
|
||||
throw Error_(exc.message + (msg ? " " + msg : ""));
|
||||
}
|
||||
}
|
||||
|
||||
function assertSameClass(a, b, msg) {
|
||||
var ac = Object_toString(a), bc = Object_toString(b);
|
||||
assertSameValue(ac, bc, msg);
|
||||
switch (ac) {
|
||||
case "[object Function]":
|
||||
assertSameValue(Function_toString(a), Function_toString(b), msg);
|
||||
}
|
||||
}
|
||||
|
||||
function at(prevmsg, segment) {
|
||||
return prevmsg ? prevmsg + segment : "at _" + segment;
|
||||
}
|
||||
|
||||
// Assert that the arguments a and b are thoroughly structurally equivalent.
|
||||
//
|
||||
// For the sake of speed, we cut a corner:
|
||||
// var x = {}, y = {}, ax = [x];
|
||||
// assertDeepEq([ax, x], [ax, y]); // passes (?!)
|
||||
//
|
||||
// Technically this should fail, since the two object graphs are different.
|
||||
// (The graph of [ax, y] contains one more object than the graph of [ax, x].)
|
||||
//
|
||||
// To get technically correct behavior, pass {strictEquivalence: true}.
|
||||
// This is slower because we have to walk the entire graph, and Object.prototype
|
||||
// is big.
|
||||
//
|
||||
return function assertDeepEq(a, b, options) {
|
||||
var strictEquivalence = options ? options.strictEquivalence : false;
|
||||
|
||||
function assertSameProto(a, b, msg) {
|
||||
check(Object_getPrototypeOf(a), Object_getPrototypeOf(b), at(msg, ".__proto__"));
|
||||
}
|
||||
|
||||
function failPropList(na, nb, msg) {
|
||||
throw Error_("got own properties " + uneval_(na) + ", expected " + uneval_(nb) +
|
||||
(msg ? " " + msg : ""));
|
||||
}
|
||||
|
||||
function assertSameProps(a, b, msg) {
|
||||
var na = Object_getOwnPropertyNames(a),
|
||||
nb = Object_getOwnPropertyNames(b);
|
||||
if (na.length !== nb.length)
|
||||
failPropList(na, nb, msg);
|
||||
|
||||
// Ignore differences in whether Array elements are stored densely.
|
||||
if (Array_isArray(a)) {
|
||||
na.sort();
|
||||
nb.sort();
|
||||
}
|
||||
|
||||
for (var i = 0; i < na.length; i++) {
|
||||
var name = na[i];
|
||||
if (name !== nb[i])
|
||||
failPropList(na, nb, msg);
|
||||
var da = Object_getOwnPropertyDescriptor(a, name),
|
||||
db = Object_getOwnPropertyDescriptor(b, name);
|
||||
var pmsg = at(msg, /^[_$A-Za-z0-9]+$/.test(name)
|
||||
? /0|[1-9][0-9]*/.test(name) ? "[" + name + "]" : "." + name
|
||||
: "[" + uneval_(name) + "]");
|
||||
assertSameValue(da.configurable, db.configurable, at(pmsg, ".[[Configurable]]"));
|
||||
assertSameValue(da.enumerable, db.enumerable, at(pmsg, ".[[Enumerable]]"));
|
||||
if (Object_hasOwnProperty(da, "value")) {
|
||||
if (!Object_hasOwnProperty(db, "value"))
|
||||
throw Error_("got data property, expected accessor property" + pmsg);
|
||||
check(da.value, db.value, pmsg);
|
||||
} else {
|
||||
if (Object_hasOwnProperty(db, "value"))
|
||||
throw Error_("got accessor property, expected data property" + pmsg);
|
||||
check(da.get, db.get, at(pmsg, ".[[Get]]"));
|
||||
check(da.set, db.set, at(pmsg, ".[[Set]]"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var ab = Map_();
|
||||
var bpath = Map_();
|
||||
|
||||
function check(a, b, path) {
|
||||
if (typeof a === "symbol") {
|
||||
// Symbols are primitives, but they have identity.
|
||||
// Symbol("x") !== Symbol("x") but
|
||||
// assertDeepEq(Symbol("x"), Symbol("x")) should pass.
|
||||
if (typeof b !== "symbol") {
|
||||
throw Error_("got " + uneval_(a) + ", expected " + uneval_(b) + " " + path);
|
||||
} else if (uneval_(a) !== uneval_(b)) {
|
||||
// We lamely use uneval_ to distinguish well-known symbols
|
||||
// from user-created symbols. The standard doesn't offer
|
||||
// a convenient way to do it.
|
||||
throw Error_("got " + uneval_(a) + ", expected " + uneval_(b) + " " + path);
|
||||
} else if (Map_has(ab, a)) {
|
||||
assertSameValue(Map_get(ab, a), b, path);
|
||||
} else if (Map_has(bpath, b)) {
|
||||
var bPrevPath = Map_get(bpath, b) || "_";
|
||||
throw Error_("got distinct symbols " + at(path, "") + " and " +
|
||||
at(bPrevPath, "") + ", expected the same symbol both places");
|
||||
} else {
|
||||
Map_set(ab, a, b);
|
||||
Map_set(bpath, b, path);
|
||||
}
|
||||
} else if (isPrimitive(a)) {
|
||||
assertSameValue(a, b, path);
|
||||
} else if (isPrimitive(b)) {
|
||||
throw Error_("got " + Object_toString(a) + ", expected " + uneval_(b) + " " + path);
|
||||
} else if (Map_has(ab, a)) {
|
||||
assertSameValue(Map_get(ab, a), b, path);
|
||||
} else if (Map_has(bpath, b)) {
|
||||
var bPrevPath = Map_get(bpath, b) || "_";
|
||||
throw Error_("got distinct objects " + at(path, "") + " and " + at(bPrevPath, "") +
|
||||
", expected the same object both places");
|
||||
} else {
|
||||
Map_set(ab, a, b);
|
||||
Map_set(bpath, b, path);
|
||||
if (a !== b || strictEquivalence) {
|
||||
assertSameClass(a, b, path);
|
||||
assertSameProto(a, b, path);
|
||||
assertSameProps(a, b, path);
|
||||
assertSameValue(Object_isExtensible(a),
|
||||
Object_isExtensible(b),
|
||||
at(path, ".[[Extensible]]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check(a, b, "");
|
||||
};
|
||||
})();
|
||||
}
|
@ -468,12 +468,12 @@ Debugger::getScriptFrameWithIter(JSContext *cx, AbstractFramePtr frame,
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Debugger::hasLiveOnExceptionUnwind(GlobalObject *global)
|
||||
Debugger::hasLiveHook(GlobalObject *global, Hook which)
|
||||
{
|
||||
if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
|
||||
for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
|
||||
Debugger *dbg = *p;
|
||||
if (dbg->enabled && dbg->getHook(OnExceptionUnwind))
|
||||
if (dbg->enabled && dbg->getHook(which))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -581,7 +581,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
||||
static bool handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to);
|
||||
static bool handleIonBailout(JSContext *cx, jit::RematerializedFrame *from, jit::BaselineFrame *to);
|
||||
static void propagateForcedReturn(JSContext *cx, AbstractFramePtr frame, HandleValue rval);
|
||||
static bool hasLiveOnExceptionUnwind(GlobalObject *global);
|
||||
static bool hasLiveHook(GlobalObject *global, Hook which);
|
||||
|
||||
/************************************* Functions for use by Debugger.cpp. */
|
||||
|
||||
|
@ -169,7 +169,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
||||
["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
|
||||
"pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
|
||||
"forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
|
||||
"findIndex", "copyWithin", "fill", kIteratorSymbol, "entries", "keys", "constructor"];
|
||||
"findIndex", "copyWithin", "fill", "includes", kIteratorSymbol, "entries", "keys", "constructor"];
|
||||
if (isNightlyBuild) {
|
||||
let pjsMethods = ['mapPar', 'reducePar', 'scanPar', 'scatterPar', 'filterPar'];
|
||||
gPrototypeProperties['Array'] = gPrototypeProperties['Array'].concat(pjsMethods);
|
||||
|
@ -533,6 +533,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
mCurrentTableItem(nullptr),
|
||||
mCurrentFrame(aReferenceFrame),
|
||||
mCurrentReferenceFrame(aReferenceFrame),
|
||||
mCurrentAnimatedGeometryRoot(aReferenceFrame),
|
||||
mWillChangeBudgetCalculated(false),
|
||||
mDirtyRect(-1,-1,-1,-1),
|
||||
mGlassDisplayItem(nullptr),
|
||||
@ -1088,6 +1089,104 @@ nsDisplayListBuilder::FindReferenceFrameFor(const nsIFrame *aFrame,
|
||||
return mReferenceFrame;
|
||||
}
|
||||
|
||||
// Sticky frames are active if their nearest scrollable frame is also active.
|
||||
static bool
|
||||
IsStickyFrameActive(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY);
|
||||
|
||||
// Find the nearest scrollframe.
|
||||
nsIFrame* cursor = aFrame;
|
||||
nsIFrame* parent = aParent;
|
||||
while (parent->GetType() != nsGkAtoms::scrollFrame) {
|
||||
cursor = parent;
|
||||
if ((parent = nsLayoutUtils::GetCrossDocParentFrame(cursor)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
||||
return sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == cursor;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent)
|
||||
{
|
||||
if (nsLayoutUtils::IsPopup(aFrame))
|
||||
return true;
|
||||
if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(aFrame))
|
||||
return true;
|
||||
if (!aFrame->GetParent() &&
|
||||
nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext())) {
|
||||
// Viewport frames in a display port need to be animated geometry roots
|
||||
// for background-attachment:fixed elements.
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
|
||||
if (!parent)
|
||||
return true;
|
||||
|
||||
nsIAtom* parentType = parent->GetType();
|
||||
// Treat the slider thumb as being as an active scrolled root when it wants
|
||||
// its own layer so that it can move without repainting.
|
||||
if (parentType == nsGkAtoms::sliderFrame && nsLayoutUtils::IsScrollbarThumbLayerized(aFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
|
||||
IsStickyFrameActive(this, aFrame, parent))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentType == nsGkAtoms::scrollFrame) {
|
||||
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
||||
if (sf->IsScrollingActive(this) && sf->GetScrolledFrame() == aFrame) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixed-pos frames are parented by the viewport frame, which has no parent.
|
||||
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aParent) {
|
||||
*aParent = parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
const nsIFrame* aStopAtAncestor = nullptr)
|
||||
{
|
||||
nsIFrame* cursor = aFrame;
|
||||
while (cursor != aStopAtAncestor) {
|
||||
nsIFrame* next;
|
||||
if (aBuilder->IsAnimatedGeometryRoot(cursor, &next))
|
||||
return cursor;
|
||||
cursor = next;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor)
|
||||
{
|
||||
if (aFrame == mCurrentFrame) {
|
||||
return mCurrentAnimatedGeometryRoot;
|
||||
}
|
||||
return ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
|
||||
{
|
||||
mCurrentAnimatedGeometryRoot = ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame *>(mCurrentFrame));
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -209,7 +209,19 @@ public:
|
||||
*/
|
||||
const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame,
|
||||
nsPoint* aOffset = nullptr);
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether a frame acts as an animated geometry root, optionally
|
||||
* returning the next ancestor to check.
|
||||
*/
|
||||
bool IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr);
|
||||
|
||||
/**
|
||||
* Returns the nearest ancestor frame to aFrame that is considered to have
|
||||
* (or will have) animated geometry. This can return aFrame.
|
||||
*/
|
||||
nsIFrame* FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFrame* aStopAtAncestor = nullptr);
|
||||
|
||||
/**
|
||||
* @return the root of the display list's frame (sub)tree, whose origin
|
||||
* establishes the coordinate system for the display list
|
||||
@ -311,6 +323,10 @@ public:
|
||||
const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
|
||||
const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
|
||||
const nsPoint& GetCurrentFrameOffsetToReferenceFrame() { return mCurrentOffsetToReferenceFrame; }
|
||||
const nsIFrame* GetCurrentAnimatedGeometryRoot() {
|
||||
return mCurrentAnimatedGeometryRoot;
|
||||
}
|
||||
void RecomputeCurrentAnimatedGeometryRoot();
|
||||
|
||||
/**
|
||||
* Returns true if merging and flattening of display lists should be
|
||||
@ -539,6 +555,7 @@ public:
|
||||
: mBuilder(aBuilder),
|
||||
mPrevFrame(aBuilder->mCurrentFrame),
|
||||
mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
|
||||
mPrevAnimatedGeometryRoot(mBuilder->mCurrentAnimatedGeometryRoot),
|
||||
mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
|
||||
mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
|
||||
mPrevDirtyRect(aBuilder->mDirtyRect),
|
||||
@ -555,6 +572,16 @@ public:
|
||||
aBuilder->FindReferenceFrameFor(aForChild,
|
||||
&aBuilder->mCurrentOffsetToReferenceFrame);
|
||||
}
|
||||
if (aBuilder->mCurrentFrame == aForChild->GetParent()) {
|
||||
if (aBuilder->IsAnimatedGeometryRoot(aForChild)) {
|
||||
aBuilder->mCurrentAnimatedGeometryRoot = aForChild;
|
||||
}
|
||||
} else {
|
||||
// Stop at the previous animated geometry root to help cases that
|
||||
// aren't immediate descendents.
|
||||
aBuilder->mCurrentAnimatedGeometryRoot =
|
||||
aBuilder->FindAnimatedGeometryRootFor(aForChild, aBuilder->mCurrentAnimatedGeometryRoot);
|
||||
}
|
||||
aBuilder->mCurrentFrame = aForChild;
|
||||
aBuilder->mDirtyRect = aDirtyRect;
|
||||
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
|
||||
@ -566,6 +593,11 @@ public:
|
||||
mBuilder->mCurrentReferenceFrame = aFrame;
|
||||
mBuilder->mCurrentOffsetToReferenceFrame = aOffset;
|
||||
}
|
||||
// Return the previous frame's animated geometry root, whether or not the
|
||||
// current frame is an immediate descendant.
|
||||
const nsIFrame* GetPrevAnimatedGeometryRoot() const {
|
||||
return mPrevAnimatedGeometryRoot;
|
||||
}
|
||||
~AutoBuildingDisplayList() {
|
||||
mBuilder->mCurrentFrame = mPrevFrame;
|
||||
mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
|
||||
@ -574,11 +606,13 @@ public:
|
||||
mBuilder->mDirtyRect = mPrevDirtyRect;
|
||||
mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
|
||||
mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler;
|
||||
mBuilder->mCurrentAnimatedGeometryRoot = mPrevAnimatedGeometryRoot;
|
||||
}
|
||||
private:
|
||||
nsDisplayListBuilder* mBuilder;
|
||||
const nsIFrame* mPrevFrame;
|
||||
const nsIFrame* mPrevReferenceFrame;
|
||||
nsIFrame* mPrevAnimatedGeometryRoot;
|
||||
nsDisplayLayerEventRegions* mPrevLayerEventRegions;
|
||||
nsPoint mPrevOffset;
|
||||
nsRect mPrevDirtyRect;
|
||||
@ -795,6 +829,8 @@ private:
|
||||
const nsIFrame* mCurrentReferenceFrame;
|
||||
// The offset from mCurrentFrame to mCurrentReferenceFrame.
|
||||
nsPoint mCurrentOffsetToReferenceFrame;
|
||||
// The animated geometry root for mCurrentFrame.
|
||||
nsIFrame* mCurrentAnimatedGeometryRoot;
|
||||
// will-change budget tracker
|
||||
nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
|
||||
mWillChangeBudget;
|
||||
|
@ -666,7 +666,8 @@ nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow)
|
||||
|
||||
// Initialize our view manager
|
||||
int32_t p2a = mPresContext->AppUnitsPerDevPixel();
|
||||
MOZ_ASSERT(p2a == mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel());
|
||||
MOZ_ASSERT(p2a ==
|
||||
mPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
|
||||
nscoord width = p2a * mBounds.width;
|
||||
nscoord height = p2a * mBounds.height;
|
||||
|
||||
|
@ -1718,8 +1718,8 @@ nsLayoutUtils::SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayeri
|
||||
reinterpret_cast<void*>(intptr_t(aLayerize)));
|
||||
}
|
||||
|
||||
static bool
|
||||
IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
|
||||
bool
|
||||
nsLayoutUtils::IsScrollbarThumbLayerized(nsIFrame* aThumbFrame)
|
||||
{
|
||||
return reinterpret_cast<intptr_t>(aThumbFrame->Properties().Get(ScrollbarThumbLayerized()));
|
||||
}
|
||||
@ -1729,55 +1729,7 @@ nsLayoutUtils::GetAnimatedGeometryRootForFrame(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame,
|
||||
const nsIFrame* aStopAtAncestor)
|
||||
{
|
||||
nsIFrame* f = aFrame;
|
||||
nsIFrame* stickyFrame = nullptr;
|
||||
while (f != aStopAtAncestor) {
|
||||
if (nsLayoutUtils::IsPopup(f))
|
||||
break;
|
||||
if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(f))
|
||||
break;
|
||||
if (!f->GetParent() &&
|
||||
nsLayoutUtils::ViewportHasDisplayPort(f->PresContext())) {
|
||||
// Viewport frames in a display port need to be animated geometry roots
|
||||
// for background-attachment:fixed elements.
|
||||
break;
|
||||
}
|
||||
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(f);
|
||||
if (!parent)
|
||||
break;
|
||||
nsIAtom* parentType = parent->GetType();
|
||||
// Treat the slider thumb as being as an active scrolled root when it wants
|
||||
// its own layer so that it can move without repainting.
|
||||
if (parentType == nsGkAtoms::sliderFrame && IsScrollbarThumbLayerized(f)) {
|
||||
break;
|
||||
}
|
||||
// Sticky frames are active if their nearest scrollable frame
|
||||
// is also active, just keep a record of sticky frames that we
|
||||
// encounter for now.
|
||||
if (f->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
|
||||
!stickyFrame) {
|
||||
stickyFrame = f;
|
||||
}
|
||||
if (parentType == nsGkAtoms::scrollFrame) {
|
||||
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
||||
if (sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == f) {
|
||||
// If we found a sticky frame inside this active scroll frame,
|
||||
// then use that. Otherwise use the scroll frame.
|
||||
if (stickyFrame) {
|
||||
return stickyFrame;
|
||||
}
|
||||
return f;
|
||||
} else {
|
||||
stickyFrame = nullptr;
|
||||
}
|
||||
}
|
||||
// Fixed-pos frames are parented by the viewport frame, which has no parent
|
||||
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) {
|
||||
return f;
|
||||
}
|
||||
f = parent;
|
||||
}
|
||||
return f;
|
||||
return aBuilder->FindAnimatedGeometryRootFor(aFrame, aStopAtAncestor);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
|
@ -512,6 +512,12 @@ public:
|
||||
*/
|
||||
static void SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayerize);
|
||||
|
||||
/**
|
||||
* Returns whether aThumbFrame wants its own layer due to having called
|
||||
* SetScrollbarThumbLayerization.
|
||||
*/
|
||||
static bool IsScrollbarThumbLayerized(nsIFrame* aThumbFrame);
|
||||
|
||||
/**
|
||||
* Finds the nearest ancestor frame to aItem that is considered to have (or
|
||||
* will have) "animated geometry". For example the scrolled frames of
|
||||
|
@ -929,7 +929,7 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
|
||||
|
||||
mDeviceContext = aDeviceContext;
|
||||
|
||||
if (mDeviceContext->SetPixelScale(mFullZoom))
|
||||
if (mDeviceContext->SetFullZoom(mFullZoom))
|
||||
mDeviceContext->FlushFontCache();
|
||||
mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
|
||||
|
||||
@ -1447,7 +1447,7 @@ nsPresContext::SetFullZoom(float aZoom)
|
||||
mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits);
|
||||
float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel);
|
||||
float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel);
|
||||
mDeviceContext->SetPixelScale(aZoom);
|
||||
mDeviceContext->SetFullZoom(aZoom);
|
||||
|
||||
NS_ASSERTION(!mSupressResizeReflow, "two zooms happening at the same time? impossible!");
|
||||
mSupressResizeReflow = true;
|
||||
|
@ -2395,6 +2395,21 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
// THIS IS THE COMMON CASE.
|
||||
// Not a pseudo or real stacking context. Do the simple thing and
|
||||
// return early.
|
||||
|
||||
if (aBuilder->IsBuildingLayerEventRegions()) {
|
||||
MOZ_ASSERT(buildingForChild.GetPrevAnimatedGeometryRoot() ==
|
||||
aBuilder->FindAnimatedGeometryRootFor(child->GetParent()));
|
||||
|
||||
// If this frame has a different animated geometry root than its parent,
|
||||
// make sure we accumulate event regions for its layer.
|
||||
nsIFrame *animatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(child);
|
||||
if (animatedGeometryRoot != buildingForChild.GetPrevAnimatedGeometryRoot()) {
|
||||
nsDisplayLayerEventRegions* eventRegions =
|
||||
new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
|
||||
aBuilder->SetLayerEventRegions(eventRegions);
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
|
||||
if (eventRegions) {
|
||||
eventRegions->AddFrame(aBuilder, child);
|
||||
|
@ -2879,6 +2879,8 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
nsRect displayPort;
|
||||
bool usingDisplayport = false;
|
||||
if (aBuilder->IsPaintingToWindow()) {
|
||||
bool wasUsingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), nullptr);
|
||||
|
||||
if (!mIsRoot) {
|
||||
// For a non-root scroll frame, override the value of the display port
|
||||
// base rect, and possibly create a display port if there isn't one
|
||||
@ -2903,6 +2905,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
// Override the dirty rectangle if the displayport has been set.
|
||||
if (usingDisplayport) {
|
||||
dirtyRect = displayPort;
|
||||
|
||||
// The cached animated geometry root for the display builder is out of
|
||||
// date if we just introduced a new animated geometry root.
|
||||
if (!wasUsingDisplayPort) {
|
||||
aBuilder->RecomputeCurrentAnimatedGeometryRoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user