merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-11-21 12:57:00 +01:00
commit c461a4a6c1
120 changed files with 1640 additions and 630 deletions

View File

@ -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

View File

@ -2066,7 +2066,7 @@ nsDOMWindowUtils::GetFullZoom(float* aFullZoom)
return NS_OK;
}
*aFullZoom = presContext->DeviceContext()->GetPixelScale();
*aFullZoom = presContext->DeviceContext()->GetFullZoom();
return NS_OK;
}

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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):
"""

View File

@ -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)

View File

@ -63,7 +63,7 @@ def WebIDLTest(parser, harness):
"octet",
"DOMString",
"ByteString",
"ScalarValueString",
"USVString",
#"sequence<float>",
"object",
"ArrayBuffer",

View File

@ -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")

View File

@ -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>&);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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]

View File

@ -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>

View File

@ -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));
}

View File

@ -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;

View File

@ -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));
}

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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.

View File

@ -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();
}

View File

@ -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":

View File

@ -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);
}

View File

@ -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

View File

@ -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()

View File

@ -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;
}
};

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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);
}
}

View File

@ -68,6 +68,9 @@ public:
static void Message(const std::string& aMessage);
void ProcessRecordNames(GMPRecordIterator* aRecordIterator,
GMPErr aStatus);
private:
virtual ~FakeDecryptor() {}

View File

@ -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);
}

View File

@ -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__

View File

@ -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()

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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;

View File

@ -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__();
};

View File

@ -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_

View File

@ -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;

View File

@ -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_

View File

@ -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_

View File

@ -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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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();

View File

@ -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>

View File

@ -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) {

View File

@ -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;

View File

@ -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)]

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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 = "/";
};

View File

@ -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();

View File

@ -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);

View File

@ -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;
};

View File

@ -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]

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 =

View File

@ -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

View File

@ -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);

View File

@ -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
};

View File

@ -18,6 +18,7 @@ TEST_FILES = \
ecma_3_1/ \
ecma_5/ \
ecma_6/ \
ecma_7/ \
Intl/ \
js1_1/ \
js1_2/ \

View File

View 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);

View File

View File

View 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, "");
};
})();
}

View File

@ -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;
}
}

View File

@ -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. */

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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*

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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