mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
a77443ef61
@ -23,6 +23,7 @@ NS_IMETHODIMP
|
||||
xpcAccessible::GetParent(nsIAccessible** aParent)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aParent);
|
||||
*aParent = nullptr;
|
||||
if (!Intl())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -146,6 +147,10 @@ NS_IMETHODIMP
|
||||
xpcAccessible::GetIndexInParent(int32_t* aIndexInParent)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIndexInParent);
|
||||
*aIndexInParent = -1;
|
||||
|
||||
if (!Intl())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aIndexInParent = Intl()->IndexInParent();
|
||||
return *aIndexInParent != -1 ? NS_OK : NS_ERROR_FAILURE;
|
||||
@ -157,6 +162,9 @@ xpcAccessible::GetDOMNode(nsIDOMNode** aDOMNode)
|
||||
NS_ENSURE_ARG_POINTER(aDOMNode);
|
||||
*aDOMNode = nullptr;
|
||||
|
||||
if (!Intl())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsINode* node = Intl()->GetNode();
|
||||
if (node)
|
||||
CallQueryInterface(node, aDOMNode);
|
||||
@ -168,6 +176,10 @@ NS_IMETHODIMP
|
||||
xpcAccessible::GetDocument(nsIAccessibleDocument** aDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
*aDocument = nullptr;
|
||||
|
||||
if (!Intl())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_IF_ADDREF(*aDocument = ToXPCDocument(Intl()->Document()));
|
||||
return NS_OK;
|
||||
@ -177,6 +189,10 @@ NS_IMETHODIMP
|
||||
xpcAccessible::GetRootDocument(nsIAccessibleDocument** aRootDocument)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRootDocument);
|
||||
*aRootDocument = nullptr;
|
||||
|
||||
if (!Intl())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_IF_ADDREF(*aRootDocument = ToXPCDocument(Intl()->RootAccessible()));
|
||||
return NS_OK;
|
||||
@ -199,7 +215,7 @@ NS_IMETHODIMP
|
||||
xpcAccessible::GetState(uint32_t* aState, uint32_t* aExtraState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aState);
|
||||
|
||||
|
||||
if (!Intl())
|
||||
nsAccUtils::To32States(states::DEFUNCT, aState, aExtraState);
|
||||
else
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "b60aedd37a5ccdb71893d31761988bcc17a82676",
|
||||
"revision": "51051a09cdd5b1a3c6d2edcc9dd718823adabb59",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c2da2bafd4e809317e2ca70c9bf5c11136a32818"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="0db8a38f9fed18ae2abf5ef7e1b6e2a570b07e0e"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -39,10 +39,18 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
class StackClassChecker : public MatchFinder::MatchCallback {
|
||||
class ScopeChecker : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
enum Scope {
|
||||
eLocal,
|
||||
eGlobal
|
||||
};
|
||||
ScopeChecker(Scope scope_) :
|
||||
scope(scope_) {}
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
void noteInferred(QualType T, DiagnosticsEngine &Diag);
|
||||
private:
|
||||
Scope scope;
|
||||
};
|
||||
|
||||
class NonHeapClassChecker : public MatchFinder::MatchCallback {
|
||||
@ -56,9 +64,16 @@ private:
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
};
|
||||
|
||||
StackClassChecker stackClassChecker;
|
||||
class TrivialCtorDtorChecker : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
virtual void run(const MatchFinder::MatchResult &Result);
|
||||
};
|
||||
|
||||
ScopeChecker stackClassChecker;
|
||||
ScopeChecker globalClassChecker;
|
||||
NonHeapClassChecker nonheapClassChecker;
|
||||
ArithmeticArgChecker arithmeticArgChecker;
|
||||
TrivialCtorDtorChecker trivialCtorDtorChecker;
|
||||
MatchFinder astMatcher;
|
||||
};
|
||||
|
||||
@ -236,7 +251,8 @@ public:
|
||||
enum ClassAllocationNature {
|
||||
RegularClass = 0,
|
||||
NonHeapClass = 1,
|
||||
StackClass = 2
|
||||
StackClass = 2,
|
||||
GlobalClass = 3
|
||||
};
|
||||
|
||||
/// A cached data of whether classes are stack classes, non-heap classes, or
|
||||
@ -255,6 +271,9 @@ ClassAllocationNature getClassAttrs(CXXRecordDecl *D) {
|
||||
// Base class: anyone with this annotation is obviously a stack class
|
||||
if (MozChecker::hasCustomAnnotation(D, "moz_stack_class"))
|
||||
return StackClass;
|
||||
// Base class: anyone with this annotation is obviously a global class
|
||||
if (MozChecker::hasCustomAnnotation(D, "moz_global_class"))
|
||||
return GlobalClass;
|
||||
|
||||
// See if we cached the result.
|
||||
DenseMap<const CXXRecordDecl *,
|
||||
@ -283,6 +302,10 @@ ClassAllocationNature getClassAttrs(CXXRecordDecl *D) {
|
||||
inferredAllocCauses[D] = std::make_pair(
|
||||
base->getType()->getAsCXXRecordDecl(), StackClass);
|
||||
return StackClass;
|
||||
} else if (super == GlobalClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(
|
||||
base->getType()->getAsCXXRecordDecl(), GlobalClass);
|
||||
return GlobalClass;
|
||||
} else if (super == NonHeapClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(
|
||||
base->getType()->getAsCXXRecordDecl(), NonHeapClass);
|
||||
@ -297,6 +320,9 @@ ClassAllocationNature getClassAttrs(CXXRecordDecl *D) {
|
||||
if (fieldType == StackClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(*field, StackClass);
|
||||
return StackClass;
|
||||
} else if (fieldType == GlobalClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(*field, GlobalClass);
|
||||
return GlobalClass;
|
||||
} else if (fieldType == NonHeapClass) {
|
||||
inferredAllocCauses[D] = std::make_pair(*field, NonHeapClass);
|
||||
type = NonHeapClass;
|
||||
@ -324,6 +350,12 @@ AST_MATCHER(QualType, stackClassAggregate) {
|
||||
return getClassAttrs(Node) == StackClass;
|
||||
}
|
||||
|
||||
/// This matcher will match any class with the global class assertion or an
|
||||
/// array of such classes.
|
||||
AST_MATCHER(QualType, globalClassAggregate) {
|
||||
return getClassAttrs(Node) == GlobalClass;
|
||||
}
|
||||
|
||||
/// This matcher will match any class with the stack class assertion or an
|
||||
/// array of such classes.
|
||||
AST_MATCHER(QualType, nonheapClassAggregate) {
|
||||
@ -342,6 +374,12 @@ AST_MATCHER(Decl, noArithmeticExprInArgs) {
|
||||
return MozChecker::hasCustomAnnotation(&Node, "moz_no_arith_expr_in_arg");
|
||||
}
|
||||
|
||||
/// This matcher will match any C++ class that is marked as having a trivial
|
||||
/// constructor and destructor.
|
||||
AST_MATCHER(CXXRecordDecl, hasTrivialCtorDtor) {
|
||||
return MozChecker::hasCustomAnnotation(&Node, "moz_trivial_ctor_dtor");
|
||||
}
|
||||
|
||||
/// This matcher will match all arithmetic binary operators.
|
||||
AST_MATCHER(BinaryOperator, binaryArithmeticOperator) {
|
||||
BinaryOperatorKind opcode = Node.getOpcode();
|
||||
@ -393,7 +431,10 @@ bool isPlacementNew(const CXXNewExpr *expr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DiagnosticsMatcher::DiagnosticsMatcher() {
|
||||
DiagnosticsMatcher::DiagnosticsMatcher()
|
||||
: stackClassChecker(ScopeChecker::eLocal),
|
||||
globalClassChecker(ScopeChecker::eGlobal)
|
||||
{
|
||||
// Stack class assertion: non-local variables of a stack class are forbidden
|
||||
// (non-localness checked in the callback)
|
||||
astMatcher.addMatcher(varDecl(hasType(stackClassAggregate())).bind("node"),
|
||||
@ -402,14 +443,22 @@ DiagnosticsMatcher::DiagnosticsMatcher() {
|
||||
astMatcher.addMatcher(newExpr(hasType(pointerType(
|
||||
pointee(stackClassAggregate())
|
||||
))).bind("node"), &stackClassChecker);
|
||||
// Global class assertion: non-global variables of a global class are forbidden
|
||||
// (globalness checked in the callback)
|
||||
astMatcher.addMatcher(varDecl(hasType(globalClassAggregate())).bind("node"),
|
||||
&globalClassChecker);
|
||||
// Global class assertion: new global class is forbidden
|
||||
astMatcher.addMatcher(newExpr(hasType(pointerType(
|
||||
pointee(globalClassAggregate())
|
||||
))).bind("node"), &globalClassChecker);
|
||||
// Non-heap class assertion: new non-heap class is forbidden (unless placement
|
||||
// new)
|
||||
astMatcher.addMatcher(newExpr(hasType(pointerType(
|
||||
pointee(nonheapClassAggregate())
|
||||
))).bind("node"), &nonheapClassChecker);
|
||||
|
||||
// Any heap allocation function that returns a non-heap or a stack class is
|
||||
// definitely doing something wrong
|
||||
// Any heap allocation function that returns a non-heap or a stack class or
|
||||
// a global class is definitely doing something wrong
|
||||
astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
|
||||
returns(pointerType(pointee(nonheapClassAggregate()))))))).bind("node"),
|
||||
&nonheapClassChecker);
|
||||
@ -417,6 +466,10 @@ DiagnosticsMatcher::DiagnosticsMatcher() {
|
||||
returns(pointerType(pointee(stackClassAggregate()))))))).bind("node"),
|
||||
&stackClassChecker);
|
||||
|
||||
astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
|
||||
returns(pointerType(pointee(globalClassAggregate()))))))).bind("node"),
|
||||
&globalClassChecker);
|
||||
|
||||
astMatcher.addMatcher(callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
|
||||
anyOf(
|
||||
hasDescendant(binaryOperator(allOf(binaryArithmeticOperator(),
|
||||
@ -443,60 +496,81 @@ DiagnosticsMatcher::DiagnosticsMatcher() {
|
||||
)
|
||||
)).bind("call"),
|
||||
&arithmeticArgChecker);
|
||||
|
||||
astMatcher.addMatcher(recordDecl(hasTrivialCtorDtor()).bind("node"),
|
||||
&trivialCtorDtorChecker);
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::StackClassChecker::run(
|
||||
void DiagnosticsMatcher::ScopeChecker::run(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
||||
unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
|
||||
unsigned globalID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "variable of type %0 only valid as global");
|
||||
unsigned errorID = (scope == eGlobal) ? globalID : stackID;
|
||||
if (const VarDecl *d = Result.Nodes.getNodeAs<VarDecl>("node")) {
|
||||
// Ignore the match if it's a local variable.
|
||||
if (d->hasLocalStorage())
|
||||
return;
|
||||
if (scope == eLocal) {
|
||||
// Ignore the match if it's a local variable.
|
||||
if (d->hasLocalStorage())
|
||||
return;
|
||||
} else if (scope == eGlobal) {
|
||||
// Ignore the match if it's a global variable or a static member of a
|
||||
// class. The latter is technically not in the global scope, but for the
|
||||
// use case of classes that intend to avoid introducing static
|
||||
// initializers that is fine.
|
||||
if (d->hasGlobalStorage() && !d->isStaticLocal())
|
||||
return;
|
||||
}
|
||||
|
||||
Diag.Report(d->getLocation(), stackID) << d->getType();
|
||||
Diag.Report(d->getLocation(), errorID) << d->getType();
|
||||
noteInferred(d->getType(), Diag);
|
||||
} else if (const CXXNewExpr *expr =
|
||||
Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
|
||||
// If it's placement new, then this match doesn't count.
|
||||
if (isPlacementNew(expr))
|
||||
if (scope == eLocal && isPlacementNew(expr))
|
||||
return;
|
||||
Diag.Report(expr->getStartLoc(), stackID) << expr->getAllocatedType();
|
||||
Diag.Report(expr->getStartLoc(), errorID) << expr->getAllocatedType();
|
||||
noteInferred(expr->getAllocatedType(), Diag);
|
||||
} else if (const CallExpr *expr =
|
||||
Result.Nodes.getNodeAs<CallExpr>("node")) {
|
||||
QualType badType = expr->getCallReturnType()->getPointeeType();
|
||||
Diag.Report(expr->getLocStart(), stackID) << badType;
|
||||
Diag.Report(expr->getLocStart(), errorID) << badType;
|
||||
noteInferred(badType, Diag);
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::StackClassChecker::noteInferred(QualType T,
|
||||
void DiagnosticsMatcher::ScopeChecker::noteInferred(QualType T,
|
||||
DiagnosticsEngine &Diag) {
|
||||
unsigned inheritsID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note,
|
||||
"%0 is a stack class because it inherits from a stack class %1");
|
||||
"%0 is a %2 class because it inherits from a %2 class %1");
|
||||
unsigned memberID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note,
|
||||
"%0 is a stack class because member %1 is a stack class %2");
|
||||
"%0 is a %3 class because member %1 is a %3 class %2");
|
||||
const char* attribute = (scope == eGlobal) ?
|
||||
"moz_global_class" : "moz_stack_class";
|
||||
const char* type = (scope == eGlobal) ?
|
||||
"global" : "stack";
|
||||
|
||||
// Find the CXXRecordDecl that is the stack class of interest
|
||||
// Find the CXXRecordDecl that is the local/global class of interest
|
||||
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
|
||||
T = arrTy->getElementType();
|
||||
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
|
||||
|
||||
// Direct result, we're done.
|
||||
if (MozChecker::hasCustomAnnotation(clazz, "moz_stack_class"))
|
||||
if (MozChecker::hasCustomAnnotation(clazz, attribute))
|
||||
return;
|
||||
|
||||
const Decl *cause = inferredAllocCauses[clazz].first;
|
||||
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(cause)) {
|
||||
Diag.Report(clazz->getLocation(), inheritsID) << T << CRD->getDeclName();
|
||||
Diag.Report(clazz->getLocation(), inheritsID) <<
|
||||
T << CRD->getDeclName() << type;
|
||||
} else if (const FieldDecl *FD = dyn_cast<FieldDecl>(cause)) {
|
||||
Diag.Report(FD->getLocation(), memberID) << T << FD << FD->getType();
|
||||
Diag.Report(FD->getLocation(), memberID) <<
|
||||
T << FD << FD->getType() << type;
|
||||
}
|
||||
|
||||
|
||||
// Recursively follow this back.
|
||||
noteInferred(cast<ValueDecl>(cause)->getType(), Diag);
|
||||
}
|
||||
@ -561,6 +635,19 @@ void DiagnosticsMatcher::ArithmeticArgChecker::run(
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticsMatcher::TrivialCtorDtorChecker::run(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
||||
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "class %0 must have trivial constructors and destructors");
|
||||
const CXXRecordDecl *node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
|
||||
|
||||
bool badCtor = !node->hasTrivialDefaultConstructor();
|
||||
bool badDtor = !node->hasTrivialDestructor();
|
||||
if (badCtor || badDtor)
|
||||
Diag.Report(node->getLocStart(), errorID) << node;
|
||||
}
|
||||
|
||||
class MozCheckAction : public PluginASTAction {
|
||||
public:
|
||||
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {
|
||||
|
52
build/clang-plugin/tests/TestGlobalClass.cpp
Normal file
52
build/clang-plugin/tests/TestGlobalClass.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#define MOZ_GLOBAL_CLASS __attribute__((annotate("moz_global_class")))
|
||||
#include <stddef.h>
|
||||
|
||||
struct MOZ_GLOBAL_CLASS Global {
|
||||
int i;
|
||||
void *operator new(size_t x) throw() { return 0; }
|
||||
void *operator new(size_t blah, char *buffer) { return buffer; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MOZ_GLOBAL_CLASS TemplateClass {
|
||||
T i;
|
||||
};
|
||||
|
||||
void gobble(void *) { }
|
||||
|
||||
void misuseGlobalClass(int len) {
|
||||
Global notValid; // expected-error {{variable of type 'Global' only valid as global}}
|
||||
Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}}
|
||||
static Global valid; // expected-error {{variable of type 'Global' only valid as global}}
|
||||
static Global alsoValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}}
|
||||
|
||||
gobble(&valid);
|
||||
gobble(¬Valid);
|
||||
gobble(&alsoValid[0]);
|
||||
|
||||
gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}}
|
||||
gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}}
|
||||
gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid as global}}
|
||||
gobble(len <= 5 ? &valid : new Global); // expected-error {{variable of type 'Global' only valid as global}}
|
||||
|
||||
char buffer[sizeof(Global)];
|
||||
gobble(new (buffer) Global); // expected-error {{variable of type 'Global' only valid as global}}
|
||||
}
|
||||
|
||||
Global valid;
|
||||
struct RandomClass {
|
||||
Global nonstaticMember; // expected-note {{'RandomClass' is a global class because member 'nonstaticMember' is a global class 'Global'}}
|
||||
static Global staticMember;
|
||||
};
|
||||
struct MOZ_GLOBAL_CLASS RandomGlobalClass {
|
||||
Global nonstaticMember;
|
||||
static Global staticMember;
|
||||
};
|
||||
|
||||
struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global class because it inherits from a global class 'Global'}}
|
||||
struct MOZ_GLOBAL_CLASS GoodInherit : Global {};
|
||||
|
||||
void misuseGlobalClassEvenMore(int len) {
|
||||
BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}}
|
||||
RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}}
|
||||
}
|
58
build/clang-plugin/tests/TestTrivialCtorDtor.cpp
Normal file
58
build/clang-plugin/tests/TestTrivialCtorDtor.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor")))
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR EmptyClass{};
|
||||
|
||||
template <class T>
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR TemplateEmptyClass{};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedCtor { // expected-error {{class 'BadUserDefinedCtor' must have trivial constructors and destructors}}
|
||||
BadUserDefinedCtor() {}
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedDtor { // expected-error {{class 'BadUserDefinedDtor' must have trivial constructors and destructors}}
|
||||
~BadUserDefinedDtor() {}
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualDtor { // expected-error {{class 'BadVirtualDtor' must have trivial constructors and destructors}}
|
||||
virtual ~BadVirtualDtor() {}
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMember { // expected-error {{class 'BadVirtualMember' must have trivial constructors and destructors}}
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
void foo();
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadNonEmptyCtorDtor { // expected-error {{class 'BadNonEmptyCtorDtor' must have trivial constructors and destructors}}
|
||||
BadNonEmptyCtorDtor() { foo(); }
|
||||
~BadNonEmptyCtorDtor() { foo(); }
|
||||
};
|
||||
|
||||
struct NonTrivialCtor {
|
||||
NonTrivialCtor() { foo(); }
|
||||
};
|
||||
|
||||
struct NonTrivialDtor {
|
||||
~NonTrivialDtor() { foo(); }
|
||||
};
|
||||
|
||||
struct VirtualMember {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInBase : NonTrivialCtor { // expected-error {{class 'BadNonTrivialCtorInBase' must have trivial constructors and destructors}}
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInBase : NonTrivialDtor { // expected-error {{class 'BadNonTrivialDtorInBase' must have trivial constructors and destructors}}
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInMember { // expected-error {{class 'BadNonTrivialCtorInMember' must have trivial constructors and destructors}}
|
||||
NonTrivialCtor m;
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInMember { // expected-error {{class 'BadNonTrivialDtorInMember' must have trivial constructors and destructors}}
|
||||
NonTrivialDtor m;
|
||||
};
|
||||
|
||||
struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMemberInMember { // expected-error {{class 'BadVirtualMemberInMember' must have trivial constructors and destructors}}
|
||||
VirtualMember m;
|
||||
};
|
@ -7,10 +7,12 @@
|
||||
SOURCES += [
|
||||
'TestBadImplicitConversionCtor.cpp',
|
||||
'TestCustomHeap.cpp',
|
||||
'TestGlobalClass.cpp',
|
||||
'TestMustOverride.cpp',
|
||||
'TestNoArithmeticExprInArgument.cpp',
|
||||
'TestNonHeapClass.cpp',
|
||||
'TestStackClass.cpp',
|
||||
'TestTrivialCtorDtor.cpp',
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
13
configure.in
13
configure.in
@ -2274,8 +2274,17 @@ ia64*-hpux*)
|
||||
dnl For profile-guided optimization
|
||||
PROFILE_GEN_CFLAGS="-GL"
|
||||
PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
|
||||
PROFILE_USE_CFLAGS="-GL"
|
||||
PROFILE_USE_LDFLAGS="-LTCG:PGOPTIMIZE"
|
||||
dnl XXX: PGO builds can fail with warnings treated as errors,
|
||||
dnl specifically "no profile data available" appears to be
|
||||
dnl treated as an error sometimes. This might be a consequence
|
||||
dnl of using WARNINGS_AS_ERRORS in some modules, combined
|
||||
dnl with the linker doing most of the work in the whole-program
|
||||
dnl optimization/PGO case. I think it's probably a compiler bug,
|
||||
dnl but we work around it here.
|
||||
PROFILE_USE_CFLAGS="-GL -wd4624 -wd4952"
|
||||
dnl XXX: should be -LTCG:PGOPTIMIZE, but that fails on libxul.
|
||||
dnl Probably also a compiler bug, but what can you do?
|
||||
PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE"
|
||||
LDFLAGS="$LDFLAGS -DYNAMICBASE"
|
||||
dnl Minimum reqiurement of Gecko is VS2010 or later which supports
|
||||
dnl both SSSE3 and SSE4.1.
|
||||
|
@ -1096,6 +1096,13 @@ nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// ... unless there are no dots, and a slash, and alpha characters, and this is a valid host:
|
||||
if (firstDotLoc == uint32_t(kNotFound) && lastSlashLoc != uint32_t(kNotFound) &&
|
||||
hasAsciiAlpha && isValidAsciiHost) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// If we get here, we don't have a valid URI, or we did but the
|
||||
// host is not whitelisted, so we do a keyword search *anyway*:
|
||||
rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo, aPostData);
|
||||
|
@ -375,6 +375,14 @@ let testcases = [ {
|
||||
protocolChange: true,
|
||||
affectedByWhitelist: true,
|
||||
affectedByDNSForSingleHosts: true,
|
||||
}, {
|
||||
input: "5/2",
|
||||
fixedURI: "http://5/2",
|
||||
alternateURI: "http://www.5.com/2",
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
affectedByWhitelist: true,
|
||||
affectedByDNSForSingleHosts: true,
|
||||
}, {
|
||||
input: "moz ?.::%27",
|
||||
keywordLookup: true,
|
||||
@ -448,6 +456,32 @@ let testcases = [ {
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
affectedByWhitelist: true
|
||||
}, {
|
||||
input: "mozilla/",
|
||||
fixedURI: "http://mozilla/",
|
||||
alternateURI: "http://www.mozilla.com/",
|
||||
protocolChange: true,
|
||||
affectedByWhitelist: true,
|
||||
}, {
|
||||
input: "mozilla",
|
||||
fixedURI: "http://mozilla/",
|
||||
alternateURI: "http://www.mozilla.com/",
|
||||
protocolChange: true,
|
||||
keywordLookup: true,
|
||||
affectedByWhitelist: true,
|
||||
affectedByDNSForSingleHosts: true,
|
||||
}, {
|
||||
input: "mozilla5/2",
|
||||
fixedURI: "http://mozilla5/2",
|
||||
alternateURI: "http://www.mozilla5.com/2",
|
||||
protocolChange: true,
|
||||
affectedByWhitelist: true,
|
||||
}, {
|
||||
input: "mozilla/foo",
|
||||
fixedURI: "http://mozilla/foo",
|
||||
alternateURI: "http://www.mozilla.com/foo",
|
||||
protocolChange: true,
|
||||
affectedByWhitelist: true,
|
||||
}];
|
||||
|
||||
if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
|
||||
@ -467,10 +501,8 @@ if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
|
||||
input: "mozilla\\",
|
||||
fixedURI: "http://mozilla/",
|
||||
alternateURI: "http://www.mozilla.com/",
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
affectedByWhitelist: true,
|
||||
affectedByDNSForSingleHosts: true,
|
||||
});
|
||||
} else {
|
||||
testcases.push({
|
||||
|
@ -1461,7 +1461,9 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
// Being added to a document.
|
||||
SetInDocument();
|
||||
|
||||
if (GetCustomElementData()) {
|
||||
// Attached callback must be enqueued whenever custom element is inserted into a
|
||||
// document and this document has a browsing context.
|
||||
if (GetCustomElementData() && aDocument->GetDocShell()) {
|
||||
// Enqueue an attached callback for the custom element.
|
||||
aDocument->EnqueueLifecycleCallback(nsIDocument::eAttached, this);
|
||||
}
|
||||
@ -1673,7 +1675,9 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
|
||||
document->ClearBoxObjectFor(this);
|
||||
|
||||
if (GetCustomElementData()) {
|
||||
// Detached must be enqueued whenever custom element is removed from
|
||||
// the document and this document has a browsing context.
|
||||
if (GetCustomElementData() && document->GetDocShell()) {
|
||||
// Enqueue a detached callback for the custom element.
|
||||
document->EnqueueLifecycleCallback(nsIDocument::eDetached, this);
|
||||
}
|
||||
|
@ -445,13 +445,27 @@ CustomElementCallback::Call()
|
||||
ErrorResult rv;
|
||||
switch (mType) {
|
||||
case nsIDocument::eCreated:
|
||||
{
|
||||
// For the duration of this callback invocation, the element is being created
|
||||
// flag must be set to true.
|
||||
mOwnerData->mElementIsBeingCreated = true;
|
||||
|
||||
// The callback hasn't actually been invoked yet, but we need to flip
|
||||
// this now in order to enqueue the attached callback. This is a spec
|
||||
// bug (w3c bug 27437).
|
||||
mOwnerData->mCreatedCallbackInvoked = true;
|
||||
|
||||
// If ELEMENT is in a document and this document has a browsing context,
|
||||
// enqueue attached callback for ELEMENT.
|
||||
nsIDocument* document = mThisObject->GetUncomposedDoc();
|
||||
if (document && document->GetDocShell()) {
|
||||
document->EnqueueLifecycleCallback(nsIDocument::eAttached, mThisObject);
|
||||
}
|
||||
|
||||
static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
|
||||
mOwnerData->mElementIsBeingCreated = false;
|
||||
break;
|
||||
}
|
||||
case nsIDocument::eAttached:
|
||||
static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv);
|
||||
break;
|
||||
@ -5424,23 +5438,30 @@ nsIDocument::CreateElement(const nsAString& aTagName, ErrorResult& rv)
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::SwizzleCustomElement(Element* aElement,
|
||||
const nsAString& aTypeExtension,
|
||||
uint32_t aNamespaceID,
|
||||
ErrorResult& rv)
|
||||
nsDocument::SetupCustomElement(Element* aElement,
|
||||
uint32_t aNamespaceID,
|
||||
const nsAString* aTypeExtension)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> typeAtom(do_GetAtom(aTypeExtension));
|
||||
nsCOMPtr<nsIAtom> tagAtom = aElement->Tag();
|
||||
if (!mRegistry || tagAtom == typeAtom) {
|
||||
if (!mRegistry) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAtom> tagAtom = aElement->Tag();
|
||||
nsCOMPtr<nsIAtom> typeAtom = aTypeExtension ?
|
||||
do_GetAtom(*aTypeExtension) : tagAtom;
|
||||
|
||||
if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
|
||||
// Custom element setup in the parser happens after the "is"
|
||||
// attribute is added.
|
||||
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true);
|
||||
}
|
||||
|
||||
CustomElementDefinition* data;
|
||||
CustomElementHashKey key(aNamespaceID, typeAtom);
|
||||
if (!mRegistry->mCustomDefinitions.Get(&key, &data)) {
|
||||
// The type extension doesn't exist in the registry,
|
||||
// thus we don't need to swizzle, but it is possibly
|
||||
// an upgrade candidate.
|
||||
// thus we don't need to enqueue callback or adjust
|
||||
// the "is" attribute, but it is possibly an upgrade candidate.
|
||||
RegisterUnresolvedElement(aElement, typeAtom);
|
||||
return;
|
||||
}
|
||||
@ -5452,11 +5473,6 @@ nsDocument::SwizzleCustomElement(Element* aElement,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
|
||||
// Swizzling in the parser happens after the "is" attribute is added.
|
||||
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, aTypeExtension, true);
|
||||
}
|
||||
|
||||
// Enqueuing the created callback will set the CustomElementData on the
|
||||
// element, causing prototype swizzling to occur in Element::WrapObject.
|
||||
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data);
|
||||
@ -5472,10 +5488,9 @@ nsDocument::CreateElement(const nsAString& aTagName,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SwizzleCustomElement(elem, aTypeExtension,
|
||||
GetDefaultNamespaceID(), rv);
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
if (!aTagName.Equals(aTypeExtension)) {
|
||||
// Custom element type can not extend itself.
|
||||
SetupCustomElement(elem, GetDefaultNamespaceID(), &aTypeExtension);
|
||||
}
|
||||
|
||||
return elem.forget();
|
||||
@ -5540,9 +5555,9 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
|
||||
}
|
||||
}
|
||||
|
||||
SwizzleCustomElement(elem, aTypeExtension, nameSpaceId, rv);
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
if (!aQualifiedName.Equals(aTypeExtension)) {
|
||||
// A custom element type can not extend itself.
|
||||
SetupCustomElement(elem, nameSpaceId, &aTypeExtension);
|
||||
}
|
||||
|
||||
return elem.forget();
|
||||
@ -5769,12 +5784,12 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
|
||||
getter_AddRefs(newElement));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
ErrorResult errorResult;
|
||||
nsCOMPtr<Element> element = do_QueryInterface(newElement);
|
||||
document->SwizzleCustomElement(element, elemName, definition->mNamespaceID,
|
||||
errorResult);
|
||||
if (errorResult.Failed()) {
|
||||
return true;
|
||||
if (definition->mLocalName != typeAtom) {
|
||||
// This element is a custom element by extension, thus we need to
|
||||
// do some special setup. For non-extended custom elements, this happens
|
||||
// when the element is created.
|
||||
document->SetupCustomElement(element, definition->mNamespaceID, &elemName);
|
||||
}
|
||||
|
||||
rv = nsContentUtils::WrapNative(aCx, newElement, newElement, args.rval());
|
||||
@ -6095,7 +6110,7 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
|
||||
nsCOMPtr<nsIAtom> nameAtom;;
|
||||
nsCOMPtr<nsIAtom> nameAtom;
|
||||
int32_t namespaceID = kNameSpaceID_XHTML;
|
||||
JS::Rooted<JSObject*> protoObject(aCx);
|
||||
{
|
||||
@ -6273,16 +6288,6 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
|
||||
}
|
||||
|
||||
EnqueueLifecycleCallback(nsIDocument::eCreated, elem, nullptr, definition);
|
||||
//XXXsmaug It is unclear if we should use GetComposedDoc() here.
|
||||
if (elem->GetUncomposedDoc()) {
|
||||
// Normally callbacks can not be enqueued until the created
|
||||
// callback has been invoked, however, the attached callback
|
||||
// in element upgrade is an exception so pretend the created
|
||||
// callback has been invoked.
|
||||
elem->GetCustomElementData()->mCreatedCallbackInvoked = true;
|
||||
|
||||
EnqueueLifecycleCallback(nsIDocument::eAttached, elem, nullptr, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1557,11 +1557,12 @@ private:
|
||||
public:
|
||||
static void ProcessBaseElementQueue();
|
||||
|
||||
// Modify the prototype and "is" attribute of newly created custom elements.
|
||||
virtual void SwizzleCustomElement(Element* aElement,
|
||||
const nsAString& aTypeExtension,
|
||||
uint32_t aNamespaceID,
|
||||
mozilla::ErrorResult& rv);
|
||||
// Enqueue created callback or register upgrade candidate for
|
||||
// newly created custom elements, possibly extending an existing type.
|
||||
// ex. <x-button>, <button is="x-button> (type extension)
|
||||
virtual void SetupCustomElement(Element* aElement,
|
||||
uint32_t aNamespaceID,
|
||||
const nsAString* aTypeExtension);
|
||||
|
||||
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
|
||||
|
||||
|
@ -2237,10 +2237,9 @@ public:
|
||||
Element* aCustomElement,
|
||||
mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
|
||||
mozilla::dom::CustomElementDefinition* aDefinition = nullptr) = 0;
|
||||
virtual void SwizzleCustomElement(Element* aElement,
|
||||
const nsAString& aTypeExtension,
|
||||
uint32_t aNamespaceID,
|
||||
mozilla::ErrorResult& rv) = 0;
|
||||
virtual void SetupCustomElement(Element* aElement,
|
||||
uint32_t aNamespaceID,
|
||||
const nsAString* aTypeExtension = nullptr) = 0;
|
||||
virtual void
|
||||
RegisterElement(JSContext* aCx, const nsAString& aName,
|
||||
const mozilla::dom::ElementRegistrationOptions& aOptions,
|
||||
|
@ -363,6 +363,24 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
|
||||
rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (clone->IsElement()) {
|
||||
// The cloned node may be a custom element that may require
|
||||
// enqueing created callback and prototype swizzling.
|
||||
Element* elem = clone->AsElement();
|
||||
if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) {
|
||||
elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID());
|
||||
} else {
|
||||
// Check if node may be custom element by type extension.
|
||||
// ex. <button is="x-button">
|
||||
nsAutoString extension;
|
||||
if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) &&
|
||||
!extension.IsEmpty()) {
|
||||
elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID(),
|
||||
&extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aParent) {
|
||||
// If we're cloning we need to insert the cloned children into the cloned
|
||||
// parent.
|
||||
|
@ -2654,12 +2654,6 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
|
||||
mDecoder->SetPreservesPitch(mPreservesPitch);
|
||||
mDecoder->SetPlaybackRate(mPlaybackRate);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
}
|
||||
#endif
|
||||
if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
|
||||
mDecoder->SetMinimizePrerollUntilPlaybackStarts();
|
||||
}
|
||||
@ -2681,6 +2675,12 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Decoder successfully created, the decoder now owns the MediaResource
|
||||
// which owns the channel.
|
||||
mChannel = nullptr;
|
||||
|
@ -266,13 +266,7 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Element may be unresolved at this point.
|
||||
doc->RegisterUnresolvedElement(*aResult);
|
||||
|
||||
// Try to enqueue a created callback. The custom element data will be set
|
||||
// and created callback will be enqueued if the custom element type
|
||||
// has already been registered.
|
||||
doc->EnqueueLifecycleCallback(nsIDocument::eCreated, *aResult);
|
||||
doc->SetupCustomElement(*aResult, kNameSpaceID_XHTML);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -281,6 +281,9 @@ void MediaDecoder::DestroyDecodedStream()
|
||||
|
||||
if (GetDecodedStream()) {
|
||||
GetStateMachine()->ResyncMediaStreamClock();
|
||||
} else {
|
||||
// Avoid the redundant blocking to output stream.
|
||||
return;
|
||||
}
|
||||
|
||||
// All streams are having their SourceMediaStream disconnected, so they
|
||||
@ -292,19 +295,17 @@ void MediaDecoder::DestroyDecodedStream()
|
||||
// be careful not to send any messages after the Destroy().
|
||||
if (os.mStream->IsDestroyed()) {
|
||||
// Probably the DOM MediaStream was GCed. Clean up.
|
||||
if (os.mPort) {
|
||||
os.mPort->Destroy();
|
||||
}
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
mOutputStreams.RemoveElementAt(i);
|
||||
continue;
|
||||
}
|
||||
os.mStream->ChangeExplicitBlockerCount(1);
|
||||
// Explicitly remove all existing ports. This is not strictly necessary but it's
|
||||
// good form.
|
||||
if (os.mPort) {
|
||||
os.mPort->Destroy();
|
||||
os.mPort = nullptr;
|
||||
}
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
os.mPort = nullptr;
|
||||
}
|
||||
|
||||
mDecodedStream = nullptr;
|
||||
@ -842,7 +843,7 @@ void MediaDecoder::PlaybackEnded()
|
||||
|
||||
if (mShuttingDown ||
|
||||
mPlayState == PLAY_STATE_SEEKING ||
|
||||
(mPlayState == PLAY_STATE_LOADING)) {
|
||||
mPlayState == PLAY_STATE_LOADING) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -853,9 +854,8 @@ void MediaDecoder::PlaybackEnded()
|
||||
OutputStreamData& os = mOutputStreams[i];
|
||||
if (os.mStream->IsDestroyed()) {
|
||||
// Probably the DOM MediaStream was GCed. Clean up.
|
||||
if (os.mPort) {
|
||||
os.mPort->Destroy();
|
||||
}
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
mOutputStreams.RemoveElementAt(i);
|
||||
continue;
|
||||
}
|
||||
@ -863,9 +863,8 @@ void MediaDecoder::PlaybackEnded()
|
||||
// Shouldn't really be needed since mDecodedStream should already have
|
||||
// finished, but doesn't hurt.
|
||||
os.mStream->Finish();
|
||||
if (os.mPort) {
|
||||
os.mPort->Destroy();
|
||||
}
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
// Not really needed but it keeps the invariant that a stream not
|
||||
// connected to mDecodedStream is explicity blocked.
|
||||
os.mStream->ChangeExplicitBlockerCount(1);
|
||||
|
@ -2958,7 +2958,8 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
(JustExitedQuickBuffering() || HasLowUndecodedData());
|
||||
} else {
|
||||
MOZ_ASSERT(mReader->IsWaitForDataSupported());
|
||||
shouldBuffer = OutOfDecodedAudio() || OutOfDecodedVideo();
|
||||
shouldBuffer = (OutOfDecodedAudio() && mAudioRequestStatus == RequestStatus::Waiting) ||
|
||||
(OutOfDecodedVideo() && mVideoRequestStatus == RequestStatus::Waiting);
|
||||
}
|
||||
if (shouldBuffer) {
|
||||
if (currentFrame) {
|
||||
|
@ -207,7 +207,8 @@ ExtractH264CodecDetails(const nsAString& aCodec,
|
||||
int16_t& aProfile,
|
||||
int16_t& aLevel)
|
||||
{
|
||||
// H.264 codecs parameters have a type defined as avc1.PPCCLL, where
|
||||
// H.264 codecs parameters have a type defined as avcN.PPCCLL, where
|
||||
// N = avc type. avc3 is avcc with SPS & PPS implicit (within stream)
|
||||
// PP = profile_idc, CC = constraint_set flags, LL = level_idc.
|
||||
// We ignore the constraint_set flags, as it's not clear from any
|
||||
// documentation what constraints the platform decoders support.
|
||||
@ -217,9 +218,9 @@ ExtractH264CodecDetails(const nsAString& aCodec,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the codec starts with "avc1.".
|
||||
// Verify the codec starts with "avc1." or "avc3.".
|
||||
const nsAString& sample = Substring(aCodec, 0, 5);
|
||||
if (!sample.EqualsASCII("avc1.")) {
|
||||
if (!sample.EqualsASCII("avc1.") && !sample.EqualsASCII("avc3.")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
286
dom/media/fmp4/AVCCDecoderModule.cpp
Normal file
286
dom/media/fmp4/AVCCDecoderModule.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#include "AVCCDecoderModule.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
class AVCCMediaDataDecoder : public MediaDataDecoder {
|
||||
public:
|
||||
|
||||
AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
|
||||
virtual ~AVCCMediaDataDecoder();
|
||||
|
||||
virtual nsresult Init() MOZ_OVERRIDE;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
virtual nsresult Flush() MOZ_OVERRIDE;
|
||||
virtual nsresult Drain() MOZ_OVERRIDE;
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE;
|
||||
virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
|
||||
virtual bool IsDormantNeeded() MOZ_OVERRIDE;
|
||||
virtual void AllocateMediaResources() MOZ_OVERRIDE;
|
||||
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
|
||||
virtual void ReleaseDecoder() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Will create the required MediaDataDecoder if we have a AVC SPS.
|
||||
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
|
||||
// will set mError accordingly.
|
||||
nsresult CreateDecoder();
|
||||
nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
mp4_demuxer::VideoDecoderConfig mCurrentConfig;
|
||||
layers::LayersBackend mLayersBackend;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
nsRefPtr<MediaTaskQueue> mVideoTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsresult mLastError;
|
||||
};
|
||||
|
||||
AVCCMediaDataDecoder::AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mPDM(aPDM)
|
||||
, mCurrentConfig(aConfig)
|
||||
, mLayersBackend(aLayersBackend)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mVideoTaskQueue(aVideoTaskQueue)
|
||||
, mCallback(aCallback)
|
||||
, mDecoder(nullptr)
|
||||
, mLastError(NS_OK)
|
||||
{
|
||||
CreateDecoder();
|
||||
}
|
||||
|
||||
AVCCMediaDataDecoder::~AVCCMediaDataDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Init()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Init();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample);
|
||||
if (!mDecoder) {
|
||||
// It is not possible to create an AVCC H264 decoder without SPS.
|
||||
// As such, creation will fail if the extra_data just extracted doesn't
|
||||
// contain a SPS.
|
||||
nsresult rv = CreateDecoderAndInit(aSample);
|
||||
if (rv == NS_ERROR_NOT_INITIALIZED) {
|
||||
// We are missing the required SPS to create the decoder.
|
||||
// Ignore for the time being, the MP4Sample will be dropped.
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
aSample->extra_data = mCurrentConfig.extra_data;
|
||||
|
||||
return mDecoder->Input(aSample);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Flush()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Flush();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Drain()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Drain();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Shutdown()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Shutdown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsWaitingMediaResources()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsWaitingMediaResources();
|
||||
}
|
||||
return MediaDataDecoder::IsWaitingMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsDormantNeeded()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsDormantNeeded();
|
||||
}
|
||||
return MediaDataDecoder::IsDormantNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::AllocateMediaResources()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->AllocateMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::ReleaseMediaResources()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->ReleaseMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::ReleaseDecoder()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->ReleaseDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CreateDecoder()
|
||||
{
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) {
|
||||
// nothing found yet, will try again later
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
|
||||
mLayersBackend,
|
||||
mImageContainer,
|
||||
mVideoTaskQueue,
|
||||
mCallback);
|
||||
if (!mDecoder) {
|
||||
mLastError = NS_ERROR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
mCurrentConfig.extra_data = extra_data;
|
||||
|
||||
nsresult rv = CreateDecoder();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return Init();
|
||||
}
|
||||
|
||||
// AVCCDecoderModule
|
||||
|
||||
AVCCDecoderModule::AVCCDecoderModule(PlatformDecoderModule* aPDM)
|
||||
: mPDM(aPDM)
|
||||
{
|
||||
MOZ_ASSERT(aPDM);
|
||||
}
|
||||
|
||||
AVCCDecoderModule::~AVCCDecoderModule()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCDecoderModule::Startup()
|
||||
{
|
||||
return mPDM->Startup();
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCDecoderModule::Shutdown()
|
||||
{
|
||||
return mPDM->Shutdown();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
nsRefPtr<MediaDataDecoder> decoder;
|
||||
|
||||
if (strcmp(aConfig.mime_type, "video/avc") ||
|
||||
!mPDM->DecoderNeedsAVCC(aConfig)) {
|
||||
// There is no need for an AVCC wrapper for non-AVC content.
|
||||
decoder = mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
} else {
|
||||
decoder = new AVCCMediaDataDecoder(mPDM,
|
||||
aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AVCCDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
return mPDM->CreateAudioDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCDecoderModule::SupportsAudioMimeType(const char* aMimeType)
|
||||
{
|
||||
return mPDM->SupportsAudioMimeType(aMimeType);
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCDecoderModule::SupportsVideoMimeType(const char* aMimeType)
|
||||
{
|
||||
return mPDM->SupportsVideoMimeType(aMimeType);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
54
dom/media/fmp4/AVCCDecoderModule.h
Normal file
54
dom/media/fmp4/AVCCDecoderModule.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_AVCCDecoderModule_h
|
||||
#define mozilla_AVCCDecoderModule_h
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AVCCMediaDataDecoder;
|
||||
|
||||
// AVCCDecoderModule is a PlatformDecoderModule wrapper used to ensure that
|
||||
// only AVCC format is fed to the underlying PlatformDecoderModule.
|
||||
// The AVCCDecoderModule allows playback of content where the SPS NAL may not be
|
||||
// provided in the init segment (e.g. AVC3 or Annex B)
|
||||
// AVCCDecoderModule will monitor the input data, and will delay creation of the
|
||||
// MediaDataDecoder until a SPS and PPS NALs have been extracted.
|
||||
//
|
||||
// AVCC-only decoder modules are AppleVideoDecoder and EMEH264Decoder.
|
||||
|
||||
class AVCCDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
explicit AVCCDecoderModule(PlatformDecoderModule* aPDM);
|
||||
virtual ~AVCCDecoderModule();
|
||||
|
||||
virtual nsresult Startup() MOZ_OVERRIDE;
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
|
||||
virtual bool SupportsVideoMimeType(const char* aMimeType) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_AVCCDecoderModule_h
|
@ -250,9 +250,10 @@ public:
|
||||
|
||||
};
|
||||
|
||||
PlatformDecoderModule* CreateBlankDecoderModule()
|
||||
already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule()
|
||||
{
|
||||
return new BlankDecoderModule();
|
||||
nsRefPtr<PlatformDecoderModule> pdm = new BlankDecoderModule();
|
||||
return pdm.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -672,9 +672,15 @@ MP4Reader::ResetDecode()
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
Flush(kVideo);
|
||||
mDemuxer->SeekVideo(0);
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
mDemuxer->SeekVideo(0);
|
||||
}
|
||||
Flush(kAudio);
|
||||
mDemuxer->SeekAudio(0);
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
mDemuxer->SeekAudio(0);
|
||||
}
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ private:
|
||||
size_t SizeOfQueue(TrackType aTrack);
|
||||
|
||||
nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
|
||||
nsAutoPtr<PlatformDecoderModule> mPlatform;
|
||||
nsRefPtr<PlatformDecoderModule> mPlatform;
|
||||
|
||||
class DecoderCallback : public MediaDataDecoderCallback {
|
||||
public:
|
||||
|
@ -5,6 +5,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "AVCCDecoderModule.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "WMFDecoderModule.h"
|
||||
#endif
|
||||
@ -31,7 +33,7 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern PlatformDecoderModule* CreateBlankDecoderModule();
|
||||
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
|
||||
|
||||
bool PlatformDecoderModule::sUseBlankDecoder = false;
|
||||
bool PlatformDecoderModule::sFFmpegDecoderEnabled = false;
|
||||
@ -76,7 +78,7 @@ PlatformDecoderModule::Init()
|
||||
|
||||
#ifdef MOZ_EME
|
||||
/* static */
|
||||
PlatformDecoderModule*
|
||||
already_AddRefed<PlatformDecoderModule>
|
||||
PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
|
||||
bool aHasAudio,
|
||||
bool aHasVideo,
|
||||
@ -90,7 +92,7 @@ PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
|
||||
cdmDecodesVideo = caps.CanDecryptAndDecodeVideo();
|
||||
}
|
||||
|
||||
nsAutoPtr<PlatformDecoderModule> pdm;
|
||||
nsRefPtr<PlatformDecoderModule> pdm;
|
||||
if ((!cdmDecodesAudio && aHasAudio) || (!cdmDecodesVideo && aHasVideo)) {
|
||||
// The CDM itself can't decode. We need to wrap a PDM to decode the
|
||||
// decrypted output of the CDM.
|
||||
@ -100,56 +102,69 @@ PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
|
||||
}
|
||||
}
|
||||
|
||||
return new EMEDecoderModule(aProxy,
|
||||
pdm.forget(),
|
||||
cdmDecodesAudio,
|
||||
cdmDecodesVideo);
|
||||
nsRefPtr<PlatformDecoderModule> emepdm(
|
||||
new AVCCDecoderModule(new EMEDecoderModule(aProxy,
|
||||
pdm,
|
||||
cdmDecodesAudio,
|
||||
cdmDecodesVideo)));
|
||||
return emepdm.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
PlatformDecoderModule*
|
||||
already_AddRefed<PlatformDecoderModule>
|
||||
PlatformDecoderModule::Create()
|
||||
{
|
||||
// Note: This runs on the decode thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> m(CreatePDM());
|
||||
|
||||
if (m && NS_SUCCEEDED(m->Startup())) {
|
||||
return m.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<PlatformDecoderModule>
|
||||
PlatformDecoderModule::CreatePDM()
|
||||
{
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){
|
||||
return new AndroidDecoderModule();
|
||||
nsRefPtr<PlatformDecoderModule> m(new AndroidDecoderModule());
|
||||
return m.forget();
|
||||
}
|
||||
#endif
|
||||
if (sUseBlankDecoder) {
|
||||
return CreateBlankDecoderModule();
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
nsAutoPtr<WMFDecoderModule> m(new WMFDecoderModule());
|
||||
if (NS_SUCCEEDED(m->Startup())) {
|
||||
return m.forget();
|
||||
}
|
||||
nsRefPtr<PlatformDecoderModule> m(new WMFDecoderModule());
|
||||
return m.forget();
|
||||
#endif
|
||||
#ifdef MOZ_FFMPEG
|
||||
if (sFFmpegDecoderEnabled) {
|
||||
nsAutoPtr<PlatformDecoderModule> m(FFmpegRuntimeLinker::CreateDecoderModule());
|
||||
nsRefPtr<PlatformDecoderModule> m(FFmpegRuntimeLinker::CreateDecoderModule());
|
||||
if (m) {
|
||||
return m.forget();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
nsAutoPtr<AppleDecoderModule> m(new AppleDecoderModule());
|
||||
if (NS_SUCCEEDED(m->Startup())) {
|
||||
return m.forget();
|
||||
}
|
||||
nsRefPtr<PlatformDecoderModule> m(new AVCCDecoderModule(new AppleDecoderModule()));
|
||||
return m.forget();
|
||||
#endif
|
||||
#ifdef MOZ_GONK_MEDIACODEC
|
||||
if (sGonkDecoderEnabled) {
|
||||
return new GonkDecoderModule();
|
||||
nsRefPtr<PlatformDecoderModule> m(new GonkDecoderModule());
|
||||
return m.forget();
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if(sAndroidMCDecoderEnabled){
|
||||
return new AndroidDecoderModule();
|
||||
nsRefPtr<PlatformDecoderModule> m(new AndroidDecoderModule());
|
||||
return m.forget();
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
@ -167,4 +182,10 @@ PlatformDecoderModule::SupportsVideoMimeType(const char* aMimeType)
|
||||
return !strcmp(aMimeType, "video/mp4") || !strcmp(aMimeType, "video/avc");
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -54,6 +54,8 @@ typedef int64_t Microseconds;
|
||||
// "media.fragmented-mp4.use-blank-decoder" is true.
|
||||
class PlatformDecoderModule {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule)
|
||||
|
||||
// Call on the main thread to initialize the static state
|
||||
// needed by Create().
|
||||
static void Init();
|
||||
@ -64,7 +66,13 @@ public:
|
||||
// PlatformDecoderModules alive at the same time. There is one
|
||||
// PlatformDecoderModule created per MP4Reader.
|
||||
// This is called on the decode task queue.
|
||||
static PlatformDecoderModule* Create();
|
||||
static already_AddRefed<PlatformDecoderModule> Create();
|
||||
// As Create() but do not initialize the created PlatformDecoderModule.
|
||||
static already_AddRefed<PlatformDecoderModule> CreatePDM();
|
||||
|
||||
// Perform any per-instance initialization.
|
||||
// This is called on the decode task queue.
|
||||
virtual nsresult Startup() { return NS_OK; };
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
|
||||
@ -72,10 +80,11 @@ public:
|
||||
// does not decode, we create a PDM and use that to create MediaDataDecoders
|
||||
// that we use on on aTaskQueue to decode the decrypted stream.
|
||||
// This is called on the decode task queue.
|
||||
static PlatformDecoderModule* CreateCDMWrapper(CDMProxy* aProxy,
|
||||
bool aHasAudio,
|
||||
bool aHasVideo,
|
||||
MediaTaskQueue* aTaskQueue);
|
||||
static already_AddRefed<PlatformDecoderModule>
|
||||
CreateCDMWrapper(CDMProxy* aProxy,
|
||||
bool aHasAudio,
|
||||
bool aHasVideo,
|
||||
MediaTaskQueue* aTaskQueue);
|
||||
#endif
|
||||
|
||||
// Called to shutdown the decoder module and cleanup state. The PDM
|
||||
@ -124,10 +133,12 @@ public:
|
||||
virtual bool SupportsAudioMimeType(const char* aMimeType);
|
||||
virtual bool SupportsVideoMimeType(const char* aMimeType);
|
||||
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
// Indicates if the video decoder requires AVCC format.
|
||||
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig);
|
||||
|
||||
protected:
|
||||
PlatformDecoderModule() {}
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
// Caches pref media.fragmented-mp4.use-blank-decoder
|
||||
static bool sUseBlankDecoder;
|
||||
static bool sFFmpegDecoderEnabled;
|
||||
|
@ -72,7 +72,7 @@ SharedDecoderManager::CreateVideoDecoder(
|
||||
MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
if (!mDecoder) {
|
||||
nsAutoPtr<PlatformDecoderModule> platform(PlatformDecoderModule::Create());
|
||||
nsRefPtr<PlatformDecoderModule> platform(PlatformDecoderModule::Create());
|
||||
mDecoder = platform->CreateVideoDecoder(
|
||||
aConfig, aLayersBackend, aImageContainer, aVideoTaskQueue, mCallback);
|
||||
if (!mDecoder) {
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
}
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
|
||||
mp4_demuxer::AnnexB::ConvertSample(aSample);
|
||||
mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
|
||||
return MediaCodecDataDecoder::Input(aSample);
|
||||
}
|
||||
|
||||
@ -262,8 +262,8 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig&
|
||||
if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) {
|
||||
uint8_t* csd0 = new uint8_t[2];
|
||||
|
||||
csd0[0] = aConfig.audio_specific_config[0];
|
||||
csd0[1] = aConfig.audio_specific_config[1];
|
||||
csd0[0] = (*aConfig.audio_specific_config)[0];
|
||||
csd0[1] = (*aConfig.audio_specific_config)[1];
|
||||
|
||||
jobject buffer = env->NewDirectByteBuffer(csd0, 2);
|
||||
format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer);
|
||||
|
@ -293,7 +293,7 @@ AppleATDecoder::DecodeSample(mp4_demuxer::MP4Sample* aSample)
|
||||
|
||||
nsresult
|
||||
AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
|
||||
const mozilla::Vector<uint8_t>& aExtraData)
|
||||
const nsTArray<uint8_t>& aExtraData)
|
||||
{
|
||||
// Request the properties from CoreAudio using the codec magic cookie
|
||||
AudioFormatInfo formatInfo;
|
||||
@ -302,8 +302,8 @@ AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
|
||||
if (mFormatID == kAudioFormatMPEG4AAC) {
|
||||
formatInfo.mASBD.mFormatFlags = mConfig.extended_profile;
|
||||
}
|
||||
formatInfo.mMagicCookieSize = aExtraData.length();
|
||||
formatInfo.mMagicCookie = aExtraData.begin();
|
||||
formatInfo.mMagicCookieSize = aExtraData.Length();
|
||||
formatInfo.mMagicCookie = aExtraData.Elements();
|
||||
|
||||
UInt32 formatListSize;
|
||||
// Attempt to retrieve the default format using
|
||||
@ -374,7 +374,7 @@ AppleATDecoder::SetupDecoder(mp4_demuxer::MP4Sample* aSample)
|
||||
// This will provide us with an updated magic cookie for use with
|
||||
// GetInputAudioDescription.
|
||||
if (NS_SUCCEEDED(GetImplicitAACMagicCookie(aSample)) &&
|
||||
!mMagicCookie.length()) {
|
||||
!mMagicCookie.Length()) {
|
||||
// nothing found yet, will try again later
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
@ -387,8 +387,8 @@ AppleATDecoder::SetupDecoder(mp4_demuxer::MP4Sample* aSample)
|
||||
PodZero(&inputFormat);
|
||||
nsresult rv =
|
||||
GetInputAudioDescription(inputFormat,
|
||||
mMagicCookie.length() ?
|
||||
mMagicCookie : mConfig.extra_data);
|
||||
mMagicCookie.Length() ?
|
||||
mMagicCookie : *mConfig.extra_data);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@ -449,7 +449,7 @@ _MetadataCallback(void* aAppleATDecoder,
|
||||
decoder->mFileStreamError = true;
|
||||
return;
|
||||
}
|
||||
decoder->mMagicCookie.append(data.get(), size);
|
||||
decoder->mMagicCookie.AppendElements(data.get(), size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,7 +495,7 @@ AppleATDecoder::GetImplicitAACMagicCookie(const mp4_demuxer::MP4Sample* aSample)
|
||||
NS_WARNING("Couldn't parse sample");
|
||||
}
|
||||
|
||||
if (status || mFileStreamError || mMagicCookie.length()) {
|
||||
if (status || mFileStreamError || mMagicCookie.Length()) {
|
||||
// We have decoded a magic cookie or an error occurred as such
|
||||
// we won't need the stream any longer.
|
||||
AudioFileStreamClose(mStream);
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "nsIThread.h"
|
||||
@ -24,7 +23,7 @@ public:
|
||||
AppleATDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
~AppleATDecoder();
|
||||
virtual ~AppleATDecoder();
|
||||
|
||||
virtual nsresult Init() MOZ_OVERRIDE;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
@ -36,13 +35,13 @@ public:
|
||||
const mp4_demuxer::AudioDecoderConfig& mConfig;
|
||||
|
||||
// Use to extract magic cookie for HE-AAC detection.
|
||||
mozilla::Vector<uint8_t> mMagicCookie;
|
||||
nsTArray<uint8_t> mMagicCookie;
|
||||
// Will be set to true should an error occurred while attempting to retrieve
|
||||
// the magic cookie property.
|
||||
bool mFileStreamError;
|
||||
|
||||
private:
|
||||
RefPtr<MediaTaskQueue> mTaskQueue;
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
AudioConverterRef mConverter;
|
||||
AudioStreamBasicDescription mOutputFormat;
|
||||
@ -53,7 +52,7 @@ private:
|
||||
void SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample);
|
||||
nsresult DecodeSample(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
|
||||
const mozilla::Vector<uint8_t>& aExtraData);
|
||||
const nsTArray<uint8_t>& aExtraData);
|
||||
// Setup AudioConverter once all information required has been gathered.
|
||||
// Will return NS_ERROR_NOT_INITIALIZED if more data is required.
|
||||
nsresult SetupDecoder(mp4_demuxer::MP4Sample* aSample);
|
||||
|
@ -198,4 +198,10 @@ AppleDecoderModule::SupportsAudioMimeType(const char* aMimeType)
|
||||
return !strcmp(aMimeType, "audio/mp4a-latm") || !strcmp(aMimeType, "audio/mpeg");
|
||||
}
|
||||
|
||||
bool
|
||||
AppleDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -16,9 +16,7 @@ public:
|
||||
AppleDecoderModule();
|
||||
virtual ~AppleDecoderModule();
|
||||
|
||||
// Perform any per-instance initialization.
|
||||
// Main thread only.
|
||||
nsresult Startup();
|
||||
virtual nsresult Startup() MOZ_OVERRIDE;
|
||||
|
||||
// Called when the decoders have shutdown. Main thread only.
|
||||
// Does this really need to be main thread only????
|
||||
@ -39,6 +37,8 @@ public:
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) MOZ_OVERRIDE;
|
||||
|
||||
static void Init();
|
||||
static nsresult CanDecode();
|
||||
|
@ -404,8 +404,8 @@ AppleVDADecoder::InitializeSession()
|
||||
CFDictionaryRef
|
||||
AppleVDADecoder::CreateDecoderSpecification()
|
||||
{
|
||||
const uint8_t* extradata = mConfig.extra_data.begin();
|
||||
int extrasize = mConfig.extra_data.length();
|
||||
const uint8_t* extradata = mConfig.extra_data->Elements();
|
||||
int extrasize = mConfig.extra_data->Length();
|
||||
|
||||
OSType format = 'avc1';
|
||||
AutoCFRelease<CFNumberRef> avc_width =
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define mozilla_AppleVDADecoder_h
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "MP4Reader.h"
|
||||
#include "MP4Decoder.h"
|
||||
@ -70,7 +69,7 @@ public:
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
~AppleVDADecoder();
|
||||
virtual ~AppleVDADecoder();
|
||||
virtual nsresult Init() MOZ_OVERRIDE;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
virtual nsresult Flush() MOZ_OVERRIDE;
|
||||
@ -87,9 +86,9 @@ public:
|
||||
CFDictionaryRef CreateOutputConfiguration();
|
||||
|
||||
const mp4_demuxer::VideoDecoderConfig& mConfig;
|
||||
RefPtr<MediaTaskQueue> mTaskQueue;
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
layers::ImageContainer* mImageContainer;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
ReorderQueue mReorderQueue;
|
||||
|
||||
private:
|
||||
|
@ -260,7 +260,7 @@ AppleVTDecoder::InitializeSession()
|
||||
|
||||
#ifdef LOG_MEDIA_SHA1
|
||||
SHA1Sum avc_hash;
|
||||
avc_hash.update(mConfig.extra_data.begin(), mConfig.extra_data.length());
|
||||
avc_hash.update(mConfig.extra_data->Elements(), mConfig.extra_data->Length());
|
||||
uint8_t digest_buf[SHA1Sum::kHashSize];
|
||||
avc_hash.finish(digest_buf);
|
||||
nsAutoCString avc_digest;
|
||||
@ -268,7 +268,7 @@ AppleVTDecoder::InitializeSession()
|
||||
avc_digest.AppendPrintf("%02x", digest_buf[i]);
|
||||
}
|
||||
LOG("AVCDecoderConfig %ld bytes sha1 %s",
|
||||
mConfig.extra_data.length(), avc_digest.get());
|
||||
mConfig.extra_data->Length(), avc_digest.get());
|
||||
#endif // LOG_MEDIA_SHA1
|
||||
|
||||
AutoCFRelease<CFDictionaryRef> extensions = CreateDecoderExtensions();
|
||||
@ -312,8 +312,8 @@ AppleVTDecoder::CreateDecoderExtensions()
|
||||
{
|
||||
AutoCFRelease<CFDataRef> avc_data =
|
||||
CFDataCreate(kCFAllocatorDefault,
|
||||
mConfig.extra_data.begin(),
|
||||
mConfig.extra_data.length());
|
||||
mConfig.extra_data->Elements(),
|
||||
mConfig.extra_data->Length());
|
||||
|
||||
const void* atomsKey[] = { CFSTR("avcC") };
|
||||
const void* atomsValue[] = { avc_data };
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
MediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
~AppleVTDecoder();
|
||||
virtual ~AppleVTDecoder();
|
||||
virtual nsresult Init() MOZ_OVERRIDE;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
|
||||
virtual nsresult Flush() MOZ_OVERRIDE;
|
||||
|
@ -278,9 +278,8 @@ EMEAudioDecoder::GmpInit()
|
||||
mAudioChannels = mConfig.channel_count;
|
||||
|
||||
nsTArray<uint8_t> extraData;
|
||||
extraData.AppendElements(&mConfig.audio_specific_config[0],
|
||||
mConfig.audio_specific_config.length());
|
||||
|
||||
extraData.AppendElements(mConfig.audio_specific_config->Elements(),
|
||||
mConfig.audio_specific_config->Length());
|
||||
mGMP->InitDecode(kGMPAudioCodecAAC,
|
||||
mAudioChannels,
|
||||
mConfig.bits_per_sample,
|
||||
|
@ -258,4 +258,10 @@ EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
|
||||
return emeDecoder.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
EMEDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
{
|
||||
return mCDMDecodesVideo && aConfig.crypto.valid;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -45,10 +45,13 @@ public:
|
||||
MediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
// Will be null if CDM has decoding capability.
|
||||
nsAutoPtr<PlatformDecoderModule> mPDM;
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
// We run the PDM on its own task queue.
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
bool mCDMDecodesAudio;
|
||||
|
@ -277,8 +277,8 @@ EMEH264Decoder::GmpInit()
|
||||
|
||||
nsTArray<uint8_t> codecSpecific;
|
||||
codecSpecific.AppendElement(0); // mPacketizationMode.
|
||||
codecSpecific.AppendElements(mConfig.extra_data.begin(),
|
||||
mConfig.extra_data.length());
|
||||
codecSpecific.AppendElements(mConfig.extra_data->Elements(),
|
||||
mConfig.extra_data->Length());
|
||||
|
||||
rv = mGMP->InitDecode(codec,
|
||||
codecSpecific,
|
||||
|
@ -24,8 +24,7 @@ FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
|
||||
, mCallback(aCallback)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FFmpegAudioDecoder);
|
||||
mExtraData.append(aConfig.audio_specific_config.begin(),
|
||||
aConfig.audio_specific_config.length());
|
||||
mExtraData = aConfig.audio_specific_config;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "FFmpegLibs.h"
|
||||
#include "FFmpegLog.h"
|
||||
#include "FFmpegDataDecoder.h"
|
||||
@ -25,6 +24,7 @@ FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(MediaTaskQueue* aTaskQueue,
|
||||
: mTaskQueue(aTaskQueue)
|
||||
, mCodecContext(nullptr)
|
||||
, mFrame(NULL)
|
||||
, mExtraData(nullptr)
|
||||
, mCodecID(aCodecID)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FFmpegDataDecoder);
|
||||
@ -94,11 +94,15 @@ FFmpegDataDecoder<LIBAV_VER>::Init()
|
||||
mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
|
||||
mCodecContext->thread_safe_callbacks = false;
|
||||
|
||||
mCodecContext->extradata_size = mExtraData.length();
|
||||
for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) {
|
||||
mExtraData.append(0);
|
||||
if (mExtraData) {
|
||||
mCodecContext->extradata_size = mExtraData->Length();
|
||||
for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) {
|
||||
mExtraData->AppendElement(0);
|
||||
}
|
||||
mCodecContext->extradata = mExtraData->Elements();
|
||||
} else {
|
||||
mCodecContext->extradata_size = 0;
|
||||
}
|
||||
mCodecContext->extradata = mExtraData.begin();
|
||||
|
||||
if (codec->capabilities & CODEC_CAP_DR1) {
|
||||
mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "FFmpegLibs.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
@ -41,7 +41,7 @@ protected:
|
||||
MediaTaskQueue* mTaskQueue;
|
||||
AVCodecContext* mCodecContext;
|
||||
AVFrame* mFrame;
|
||||
Vector<uint8_t> mExtraData;
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> mExtraData;
|
||||
|
||||
private:
|
||||
static bool sFFmpegInitDone;
|
||||
|
@ -18,7 +18,12 @@ template <int V>
|
||||
class FFmpegDecoderModule : public PlatformDecoderModule
|
||||
{
|
||||
public:
|
||||
static PlatformDecoderModule* Create() { return new FFmpegDecoderModule(); }
|
||||
static already_AddRefed<PlatformDecoderModule>
|
||||
Create()
|
||||
{
|
||||
nsRefPtr<PlatformDecoderModule> pdm = new FFmpegDecoderModule();
|
||||
return pdm.forget();
|
||||
}
|
||||
|
||||
FFmpegDecoderModule() {}
|
||||
virtual ~FFmpegDecoderModule() {}
|
||||
@ -57,6 +62,7 @@ public:
|
||||
{
|
||||
return FFmpegH264Decoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "ImageContainer.h"
|
||||
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
|
||||
#include "FFmpegH264Decoder.h"
|
||||
|
||||
@ -32,7 +33,6 @@ FFmpegH264Decoder<LIBAV_VER>::FFmpegH264Decoder(
|
||||
, mImageContainer(aImageContainer)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FFmpegH264Decoder);
|
||||
mExtraData.append(aConfig.extra_data.begin(), aConfig.extra_data.length());
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -53,6 +53,7 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
|
||||
aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
packet.data = aSample->data;
|
||||
packet.size = aSample->size;
|
||||
|
@ -21,14 +21,14 @@ FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus =
|
||||
struct AvFormatLib
|
||||
{
|
||||
const char* Name;
|
||||
PlatformDecoderModule* (*Factory)();
|
||||
already_AddRefed<PlatformDecoderModule> (*Factory)();
|
||||
uint32_t Version;
|
||||
};
|
||||
|
||||
template <int V> class FFmpegDecoderModule
|
||||
{
|
||||
public:
|
||||
static PlatformDecoderModule* Create();
|
||||
static already_AddRefed<PlatformDecoderModule> Create();
|
||||
};
|
||||
|
||||
static const AvFormatLib sLibs[] = {
|
||||
@ -101,14 +101,14 @@ FFmpegRuntimeLinker::Bind(const char* aLibName, uint32_t Version)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ PlatformDecoderModule*
|
||||
/* static */ already_AddRefed<PlatformDecoderModule>
|
||||
FFmpegRuntimeLinker::CreateDecoderModule()
|
||||
{
|
||||
if (!Link()) {
|
||||
return nullptr;
|
||||
}
|
||||
PlatformDecoderModule* module = sLib->Factory();
|
||||
return module;
|
||||
nsRefPtr<PlatformDecoderModule> module = sLib->Factory();
|
||||
return module.forget();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
@ -7,12 +7,12 @@
|
||||
#ifndef __FFmpegRuntimeLinker_h__
|
||||
#define __FFmpegRuntimeLinker_h__
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
class PlatformDecoderModule;
|
||||
struct AvFormatLib;
|
||||
|
||||
class FFmpegRuntimeLinker
|
||||
@ -20,7 +20,7 @@ class FFmpegRuntimeLinker
|
||||
public:
|
||||
static bool Link();
|
||||
static void Unlink();
|
||||
static PlatformDecoderModule* CreateDecoderModule();
|
||||
static already_AddRefed<PlatformDecoderModule> CreateDecoderModule();
|
||||
|
||||
private:
|
||||
static void* sLinkedLib;
|
||||
|
@ -46,8 +46,8 @@ GonkAudioDecoderManager::GonkAudioDecoderManager(
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkAudioDecoderManager);
|
||||
MOZ_ASSERT(mAudioChannels);
|
||||
mUserData.AppendElements(&aConfig.audio_specific_config[0],
|
||||
aConfig.audio_specific_config.length());
|
||||
mUserData.AppendElements(aConfig.audio_specific_config->Elements(),
|
||||
aConfig.audio_specific_config->Length());
|
||||
// Pass through mp3 without applying an ADTS header.
|
||||
if (strcmp(aConfig.mime_type, "audio/mp4a-latm") != 0) {
|
||||
mUseAdts = false;
|
||||
|
@ -445,7 +445,7 @@ GonkVideoDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
status_t rv;
|
||||
if (aSample != nullptr) {
|
||||
// We must prepare samples in AVC Annex B.
|
||||
mp4_demuxer::AnnexB::ConvertSample(aSample);
|
||||
mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
|
||||
// Forward sample data to the decoder.
|
||||
|
||||
QueueFrameTimeIn(aSample->composition_timestamp, aSample->duration);
|
||||
|
@ -5,6 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'AVCCDecoderModule.h',
|
||||
'MP4Decoder.h',
|
||||
'MP4Reader.h',
|
||||
'MP4Stream.h',
|
||||
@ -13,6 +14,7 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AVCCDecoderModule.cpp',
|
||||
'BlankDecoderModule.cpp',
|
||||
'MP4Decoder.cpp',
|
||||
'MP4Stream.cpp',
|
||||
|
@ -83,8 +83,8 @@ WMFAudioMFTManager::WMFAudioMFTManager(
|
||||
} else if (!strcmp(aConfig.mime_type, "audio/mp4a-latm")) {
|
||||
mStreamType = AAC;
|
||||
AACAudioSpecificConfigToUserData(aConfig.aac_profile,
|
||||
&aConfig.audio_specific_config[0],
|
||||
aConfig.audio_specific_config.length(),
|
||||
aConfig.audio_specific_config->Elements(),
|
||||
aConfig.audio_specific_config->Length(),
|
||||
mUserData);
|
||||
} else {
|
||||
mStreamType = Unknown;
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
virtual ~WMFDecoderModule();
|
||||
|
||||
// Initializes the module, loads required dynamic libraries, etc.
|
||||
nsresult Startup();
|
||||
virtual nsresult Startup() MOZ_OVERRIDE;
|
||||
|
||||
// Called when the decoders have shutdown.
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE;
|
||||
|
@ -215,7 +215,7 @@ WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (mStreamType != VP8 && mStreamType != VP9) {
|
||||
// We must prepare samples in AVC Annex B.
|
||||
mp4_demuxer::AnnexB::ConvertSample(aSample);
|
||||
mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample);
|
||||
}
|
||||
// Forward sample data to the decoder.
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
class WriteRecordClient : public GMPRecordClient {
|
||||
public:
|
||||
@ -25,7 +26,7 @@ public:
|
||||
|
||||
virtual void OpenComplete(GMPErr aStatus) MOZ_OVERRIDE {
|
||||
if (GMP_SUCCEEDED(aStatus)) {
|
||||
mRecord->Write(&mData.front(), mData.size());
|
||||
mRecord->Write(mData.size() ? &mData.front() : nullptr, mData.size());
|
||||
} else {
|
||||
GMPRunOnMainThread(mOnFailure);
|
||||
mOnSuccess->Destroy();
|
||||
|
@ -72,43 +72,6 @@ GMPLoader* CreateGMPLoader(SandboxStarter* aStarter) {
|
||||
return static_cast<GMPLoader*>(new GMPLoaderImpl(aStarter));
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) && defined(HASH_NODE_ID_WITH_DEVICE_ID)
|
||||
MOZ_NEVER_INLINE
|
||||
static bool
|
||||
GetStackAfterCurrentFrame(uint8_t** aOutTop, uint8_t** aOutBottom)
|
||||
{
|
||||
// "Top" of the free space on the stack is directly after the memory
|
||||
// holding our return address.
|
||||
uint8_t* top = (uint8_t*)_AddressOfReturnAddress();
|
||||
|
||||
// Look down the stack until we find the guard page...
|
||||
MEMORY_BASIC_INFORMATION memInfo = {0};
|
||||
uint8_t* bottom = top;
|
||||
while (1) {
|
||||
if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
|
||||
return false;
|
||||
}
|
||||
if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) {
|
||||
bottom = (uint8_t*)memInfo.BaseAddress + memInfo.RegionSize;
|
||||
#ifdef DEBUG
|
||||
if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
|
||||
return false;
|
||||
}
|
||||
assert(!(memInfo.Protect & PAGE_GUARD)); // Should have found boundary.
|
||||
#endif
|
||||
break;
|
||||
} else if (memInfo.State != MEM_COMMIT ||
|
||||
(memInfo.AllocationProtect & PAGE_READWRITE) != PAGE_READWRITE) {
|
||||
return false;
|
||||
}
|
||||
bottom = (uint8_t*)memInfo.BaseAddress - 1;
|
||||
}
|
||||
*aOutTop = top;
|
||||
*aOutBottom = bottom;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
GMPLoaderImpl::Load(const char* aLibPath,
|
||||
uint32_t aLibPathLen,
|
||||
@ -146,17 +109,9 @@ GMPLoaderImpl::Load(const char* aLibPath,
|
||||
if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) {
|
||||
return false;
|
||||
}
|
||||
// We've successfully bound the origin salt to node id.
|
||||
// rlz_lib::GetRawMachineId and/or the system functions it
|
||||
// called could have left user identifiable data on the stack,
|
||||
// so carefully zero the stack down to the guard page.
|
||||
uint8_t* top;
|
||||
uint8_t* bottom;
|
||||
if (!GetStackAfterCurrentFrame(&top, &bottom)) {
|
||||
return false;
|
||||
}
|
||||
assert(top >= bottom);
|
||||
SecureZeroMemory(bottom, (top - bottom));
|
||||
// TODO: (Bug 1114867) Clear any memory on the stack that may have been
|
||||
// used by functions we've called that may have left behind data that
|
||||
// can be used to uniquely identify the user.
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
@ -148,27 +148,30 @@ GMPParent::LoadProcess()
|
||||
|
||||
bool opened = Open(mProcess->GetChannel(), mProcess->GetChildProcessHandle());
|
||||
if (!opened) {
|
||||
LOGD(("%s::%s: Failed to create new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOGD(("%s::%s: Created new process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
LOGD(("%s::%s: Created new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
|
||||
bool ok = SendSetNodeId(mNodeId);
|
||||
if (!ok) {
|
||||
LOGD(("%s::%s: Failed to send node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOGD(("%s::%s: Failed to send node id %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
LOGD(("%s::%s: Sent node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
|
||||
ok = SendStartPlugin();
|
||||
if (!ok) {
|
||||
LOGD(("%s::%s: Failed to send start to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOGD(("%s::%s: Failed to send start %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
LOGD(("%s::%s: Sent StartPlugin to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
}
|
||||
|
||||
mState = GMPStateLoaded;
|
||||
|
@ -9,6 +9,7 @@ support-files =
|
||||
[test_MediaSource_disabled.html]
|
||||
[test_BufferedSeek.html]
|
||||
[test_BufferingWait.html]
|
||||
skip-if = true # bug 1093133
|
||||
[test_EndOfStream.html]
|
||||
skip-if = (toolkit == 'android' || buildapp == 'mulet') #timeout android/mulet only bug 1101187
|
||||
[test_FrameSelection.html]
|
||||
|
@ -171,10 +171,6 @@ var gPlayTests = [
|
||||
// Test playback of a WebM file with non-zero start time.
|
||||
{ name:"split.webm", type:"video/webm", duration:1.967 },
|
||||
|
||||
// Test playback of a WebM file with vp9 video
|
||||
//{ name:"vp9.webm", type:"video/webm", duration:4 },
|
||||
{ name:"vp9cake.webm", type:"video/webm", duration:7.966 },
|
||||
|
||||
// Test playback of a raw file
|
||||
{ name:"seek.yuv", type:"video/x-raw-yuv", duration:1.833 },
|
||||
|
||||
@ -222,7 +218,11 @@ var gPlayTests = [
|
||||
{ name:"vbr-head.mp3", type:"audio/mpeg", duration:10.00 },
|
||||
|
||||
// Invalid file
|
||||
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
|
||||
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN },
|
||||
|
||||
// Test playback of a WebM file with vp9 video
|
||||
//{ name:"vp9.webm", type:"video/webm", duration:4 },
|
||||
{ name:"vp9cake.webm", type:"video/webm", duration:7.966 }
|
||||
];
|
||||
|
||||
// A file for each type we can support.
|
||||
|
@ -116,6 +116,20 @@ function startTest(test, token) {
|
||||
|
||||
document.body.appendChild(v);
|
||||
v.play();
|
||||
|
||||
if (test.name == "vp9cake.webm") {
|
||||
// Log events for debugging.
|
||||
var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
|
||||
"loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
|
||||
"waiting", "pause"];
|
||||
function logEvent(e) {
|
||||
var v = e.target;
|
||||
info(e.target.token + ": got " + e.type);
|
||||
}
|
||||
events.forEach(function(e) {
|
||||
v.addEventListener(e, logEvent, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
manager.runTests(gPlayTests, startTest);
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
memmove(data, aData, size);
|
||||
}
|
||||
|
||||
~VP8Sample()
|
||||
virtual ~VP8Sample()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ private:
|
||||
VP8Sample* PopSample();
|
||||
|
||||
nsRefPtr<WebMReader> mReader;
|
||||
nsAutoPtr<PlatformDecoderModule> mPlatform;
|
||||
nsRefPtr<PlatformDecoderModule> mPlatform;
|
||||
nsRefPtr<MediaDataDecoder> mMediaDataDecoder;
|
||||
|
||||
// TaskQueue on which decoder can choose to decode.
|
||||
|
@ -178,9 +178,11 @@ int32_t NetUtils::do_dhcp_do_request(const char *ifname,
|
||||
char domains[PROPERTY_VALUE_MAX];
|
||||
ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns,
|
||||
server, lease, vendorinfo, domains);
|
||||
} else if (sdkVersion == 19) {
|
||||
// JB 4.4
|
||||
} else if (sdkVersion >= 19) {
|
||||
// KitKat 4.4.X
|
||||
// http://androidxref.com/4.4_r1/xref/system/core/libnetutils/dhcp_utils.c#18
|
||||
// Lollipop 5.0
|
||||
//http://androidxref.com/5.0.0_r2/xref/system/core/libnetutils/dhcp_utils.c#186
|
||||
DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char**, char*, uint32_t*, char*, char*, char*)
|
||||
USE_DLFUNC(dhcp_do_request)
|
||||
char *dns[3] = {dns1, dns2, nullptr};
|
||||
|
@ -5,6 +5,10 @@ support-files =
|
||||
[test_bug900724.html]
|
||||
[test_bug1017896.html]
|
||||
[test_content_element.html]
|
||||
[test_custom_element_adopt_callbacks.html]
|
||||
[test_custom_element_callback_innerhtml.html]
|
||||
[test_custom_element_clone_callbacks.html]
|
||||
[test_custom_element_clone_callbacks_extended.html]
|
||||
[test_nested_content_element.html]
|
||||
[test_dest_insertion_points.html]
|
||||
[test_dest_insertion_points_shadow.html]
|
||||
|
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1081039
|
||||
-->
|
||||
<head>
|
||||
<title>Test callbacks for adopted custom elements.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<template id="template"><x-foo></x-foo></template>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a>
|
||||
<script>
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
p.createdCallback = function() {
|
||||
ok(false, "Created callback should not be called for adopted node.");
|
||||
};
|
||||
|
||||
document.registerElement("x-foo", { prototype: p });
|
||||
|
||||
var template = document.getElementById("template");
|
||||
var adoptedFoo = document.adoptNode(template.content.firstChild);
|
||||
is(adoptedFoo.nodeName, "X-FOO");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1102502
|
||||
-->
|
||||
<head>
|
||||
<title>Test for attached callback for element created in the document by the parser</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1102502">Bug 1102502</a>
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var attachedCallbackCount = 0;
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
|
||||
p.createdCallback = function() {
|
||||
ok(true, "createdCallback called.");
|
||||
};
|
||||
|
||||
p.attachedCallback = function() {
|
||||
ok(true, "attachedCallback should be called when the parser creates an element in the document.");
|
||||
attachedCallbackCount++;
|
||||
// attachedCallback should be called twice, once for the element created for innerHTML and
|
||||
// once for the element created in this document.
|
||||
if (attachedCallbackCount == 2) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
document.registerElement("x-foo", { prototype: p });
|
||||
|
||||
var container = document.getElementById("container");
|
||||
container.innerHTML = '<x-foo></x-foo>';
|
||||
|
||||
</script>
|
||||
|
||||
<x-foo></x-foo>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,54 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1081039
|
||||
-->
|
||||
<head>
|
||||
<title>Test callbacks for cloned custom elements.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Test to make sure created callback is called on clones that are upgraded and clones
|
||||
// created after registering the custom element.
|
||||
|
||||
var callbackCalledOnUpgrade = false;
|
||||
var callbackCalledOnClone = false;
|
||||
|
||||
var foo = document.createElement("x-foo");
|
||||
var fooClone = foo.cloneNode(true);
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
p.createdCallback = function() {
|
||||
is(this.__proto__, p, "Correct prototype should be set on custom elements.");
|
||||
|
||||
if (this == fooClone) {
|
||||
// Callback called for the element created before registering the custom element.
|
||||
// Should be called on element upgrade.
|
||||
is(callbackCalledOnUpgrade, false, "Upgrade should only be called once per clone.");
|
||||
callbackCalledOnUpgrade = true;
|
||||
} else if (this != foo) {
|
||||
// Callback called for the element created after registering the custom element.
|
||||
is(callbackCalledOnClone, false, "Upgrade should only be called once per clone.");
|
||||
callbackCalledOnClone = true;
|
||||
}
|
||||
|
||||
if (callbackCalledOnUpgrade && callbackCalledOnClone) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-foo", { prototype: p });
|
||||
|
||||
var anotherFooClone = foo.cloneNode(true);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1081039
|
||||
-->
|
||||
<head>
|
||||
<title>Test callbacks for cloned extended custom elements.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081039">Bug 1081039</a>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Test to make sure created callback is called on clones that are upgraded and clones
|
||||
// created after registering the custom element.
|
||||
|
||||
var callbackCalledOnUpgrade = false;
|
||||
var callbackCalledOnClone = false;
|
||||
|
||||
var foo = document.createElement("button", "x-foo");
|
||||
is(foo.getAttribute("is"), "x-foo");
|
||||
|
||||
var fooClone = foo.cloneNode(true);
|
||||
|
||||
var p = Object.create(HTMLButtonElement.prototype);
|
||||
p.createdCallback = function() {
|
||||
is(this.__proto__, p, "Correct prototype should be set on custom elements.");
|
||||
|
||||
if (this == fooClone) {
|
||||
// Callback called for the element created before registering the custom element.
|
||||
// Should be called on element upgrade.
|
||||
is(callbackCalledOnUpgrade, false, "Upgrade should only be called once per clone.");
|
||||
callbackCalledOnUpgrade = true;
|
||||
} else if (this != foo) {
|
||||
// Callback called for the element created after registering the custom element.
|
||||
is(callbackCalledOnClone, false, "Upgrade should only be called once per clone.");
|
||||
callbackCalledOnClone = true;
|
||||
}
|
||||
|
||||
if (callbackCalledOnUpgrade && callbackCalledOnClone) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-foo", { prototype: p, extends: "button" });
|
||||
|
||||
var anotherFooClone = foo.cloneNode(true);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -14,6 +14,8 @@
|
||||
<pre id="feedback"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
|
||||
function() {
|
||||
var worker = new Worker("websocket_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
@ -38,7 +40,9 @@
|
||||
};
|
||||
|
||||
worker.postMessage('foobar');
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -15,6 +15,8 @@
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
|
||||
function() {
|
||||
var worker = new Worker("websocket_basic_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
@ -49,7 +51,9 @@
|
||||
}
|
||||
|
||||
runTest();
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -15,6 +15,8 @@
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
|
||||
function() {
|
||||
var worker = new Worker("websocket_loadgroup_worker.js");
|
||||
|
||||
var stopped = false;
|
||||
@ -53,7 +55,9 @@
|
||||
}
|
||||
|
||||
runTest();
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -19,6 +19,8 @@ onmessage = function() {
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
|
||||
function() {
|
||||
var blob = new Blob([document.getElementById("js_script").textContent],
|
||||
{type: "text/javascript"});
|
||||
var url = URL.createObjectURL(blob);
|
||||
@ -63,8 +65,10 @@ onmessage = function() {
|
||||
t();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -152,7 +152,7 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"URLSearchParams",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"WebSocket",
|
||||
{ name: "WebSocket", pref: "dom.workers.websocket.enabled" },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Worker",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -111,7 +111,7 @@ ClientCanvasLayer::Initialize(const Data& aData)
|
||||
case mozilla::layers::LayersBackend::LAYERS_D3D10:
|
||||
case mozilla::layers::LayersBackend::LAYERS_D3D11: {
|
||||
#ifdef XP_WIN
|
||||
if (mGLContext->IsANGLE() && DoesD3D11DeviceWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device())) {
|
||||
if (mGLContext->IsANGLE() && DoesD3D11TextureSharingWork(gfxWindowsPlatform::GetPlatform()->GetD3D11Device())) {
|
||||
factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps);
|
||||
}
|
||||
#endif
|
||||
|
@ -595,7 +595,6 @@ CopyFrontToBack(TextureClient* aFront,
|
||||
|
||||
void
|
||||
TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
|
||||
bool aCanRerasterizeValidRegion,
|
||||
nsIntRegion& aAddPaintedRegion)
|
||||
{
|
||||
if (mBackBuffer && mFrontBuffer) {
|
||||
@ -614,9 +613,7 @@ TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
|
||||
|
||||
aAddPaintedRegion = regionToCopy;
|
||||
|
||||
if (regionToCopy.IsEmpty() ||
|
||||
(aCanRerasterizeValidRegion &&
|
||||
regionToCopy.Area() < tileSize.width * tileSize.height * MINIMUM_TILE_COPY_AREA)) {
|
||||
if (regionToCopy.IsEmpty()) {
|
||||
// Just redraw it all.
|
||||
return;
|
||||
}
|
||||
@ -713,7 +710,6 @@ TileClient::GetBackBuffer(const nsIntRegion& aDirtyRegion,
|
||||
SurfaceMode aMode,
|
||||
bool *aCreatedTextureClient,
|
||||
nsIntRegion& aAddPaintedRegion,
|
||||
bool aCanRerasterizeValidRegion,
|
||||
RefPtr<TextureClient>* aBackBufferOnWhite)
|
||||
{
|
||||
// Try to re-use the front-buffer if possible
|
||||
@ -778,7 +774,7 @@ TileClient::GetBackBuffer(const nsIntRegion& aDirtyRegion,
|
||||
mInvalidBack = nsIntRect(0, 0, mBackBuffer->GetSize().width, mBackBuffer->GetSize().height);
|
||||
}
|
||||
|
||||
ValidateBackBufferFromFront(aDirtyRegion, aCanRerasterizeValidRegion, aAddPaintedRegion);
|
||||
ValidateBackBufferFromFront(aDirtyRegion, aAddPaintedRegion);
|
||||
|
||||
*aBackBufferOnWhite = mBackBufferOnWhite;
|
||||
return mBackBuffer;
|
||||
@ -1116,7 +1112,6 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
aTile.GetBackBuffer(offsetScaledDirtyRegion,
|
||||
content, mode,
|
||||
&createdTextureClient, extraPainted,
|
||||
usingTiledDrawTarget,
|
||||
&backBufferOnWhite);
|
||||
|
||||
extraPainted.MoveBy(aTileOrigin);
|
||||
@ -1150,8 +1145,6 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
}
|
||||
|
||||
if (usingTiledDrawTarget) {
|
||||
aTile.Flip();
|
||||
|
||||
if (createdTextureClient) {
|
||||
if (!mCompositableClient->AddTextureClient(backBuffer)) {
|
||||
NS_WARNING("Failed to add tile TextureClient.");
|
||||
@ -1180,6 +1173,7 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
moz2DTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x * mResolution, aTileOrigin.y * mResolution);
|
||||
if (!dt || (backBufferOnWhite && !dtOnWhite)) {
|
||||
aTile.DiscardFrontBuffer();
|
||||
aTile.DiscardBackBuffer();
|
||||
return aTile;
|
||||
}
|
||||
|
||||
@ -1195,13 +1189,10 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
dirtyRect->height);
|
||||
drawRect.Scale(mResolution);
|
||||
|
||||
gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution),
|
||||
NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution),
|
||||
drawRect.width,
|
||||
drawRect.height);
|
||||
gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
|
||||
// Mark the newly updated area as invalid in the back buffer
|
||||
aTile.mInvalidBack.Or(aTile.mInvalidBack, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
|
||||
// Mark the newly updated area as invalid in the front buffer
|
||||
aTile.mInvalidFront.Or(aTile.mInvalidFront,
|
||||
nsIntRect(NS_roundf(drawRect.x), NS_roundf(drawRect.y),
|
||||
drawRect.width, drawRect.height));
|
||||
|
||||
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
|
||||
dt->FillRect(drawRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
|
||||
@ -1212,8 +1203,10 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
}
|
||||
|
||||
// The new buffer is now validated, remove the dirty region from it.
|
||||
aTile.mInvalidFront.Sub(nsIntRect(0, 0, GetTileSize().width, GetTileSize().height),
|
||||
offsetScaledDirtyRegion);
|
||||
aTile.mInvalidBack.Sub(nsIntRect(0, 0, GetTileSize().width, GetTileSize().height),
|
||||
offsetScaledDirtyRegion);
|
||||
|
||||
aTile.Flip();
|
||||
|
||||
return aTile;
|
||||
}
|
||||
|
@ -239,7 +239,6 @@ struct TileClient
|
||||
gfxContentType aContent, SurfaceMode aMode,
|
||||
bool *aCreatedTextureClient,
|
||||
nsIntRegion& aAddPaintedRegion,
|
||||
bool aCanRerasterizeValidRegion,
|
||||
RefPtr<TextureClient>* aTextureClientOnWhite);
|
||||
|
||||
void DiscardFrontBuffer();
|
||||
@ -279,7 +278,6 @@ private:
|
||||
// Copies dirty pixels from the front buffer into the back buffer,
|
||||
// and records the copied region in aAddPaintedRegion.
|
||||
void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
|
||||
bool aCanRerasterizeValidRegion,
|
||||
nsIntRegion& aAddPaintedRegion);
|
||||
};
|
||||
|
||||
|
@ -778,7 +778,7 @@ uint32_t
|
||||
gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
||||
bool aLineBreakBefore, gfxFloat aWidth,
|
||||
PropertyProvider *aProvider,
|
||||
bool aSuppressInitialBreak,
|
||||
SuppressBreak aSuppressBreak,
|
||||
gfxFloat *aTrimWhitespace,
|
||||
Metrics *aMetrics,
|
||||
gfxFont::BoundingBoxType aBoundingBoxType,
|
||||
@ -847,7 +847,8 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
||||
// line: if the width is too small for even one character to fit, it
|
||||
// could be the first and last break opportunity on the line, and that
|
||||
// would trigger an infinite loop.
|
||||
if (!aSuppressInitialBreak || i > aStart) {
|
||||
if (aSuppressBreak != eSuppressAllBreaks &&
|
||||
(aSuppressBreak != eSuppressInitialBreak || i > aStart)) {
|
||||
bool atNaturalBreak = mCharacterGlyphs[i].CanBreakBefore() == 1;
|
||||
bool atHyphenationBreak =
|
||||
!atNaturalBreak && haveHyphenation && hyphenBuffer[i - bufferStart];
|
||||
@ -1766,7 +1767,7 @@ gfxFontGroup::GetFontAt(int32_t i, uint32_t aCh)
|
||||
}
|
||||
font = fe->FindOrMakeFont(&mStyle, mFonts[i].NeedsBold(),
|
||||
unicodeRangeMap);
|
||||
if (font && !font->Valid()) {
|
||||
if (!font || !font->Valid()) {
|
||||
ff.SetInvalid();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -307,6 +307,14 @@ public:
|
||||
gfxFloat *aAdvanceWidthDelta,
|
||||
gfxContext *aRefContext);
|
||||
|
||||
enum SuppressBreak {
|
||||
eNoSuppressBreak,
|
||||
// Measure the range of text as if there is no break before it.
|
||||
eSuppressInitialBreak,
|
||||
// Measure the range of text as if it contains no break
|
||||
eSuppressAllBreaks
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the longest substring that will fit into the given width.
|
||||
* Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
|
||||
@ -331,10 +339,7 @@ public:
|
||||
* is up to the end of the string
|
||||
* @param aLineBreakBefore set to true if and only if there is an actual
|
||||
* line break at the start of this string.
|
||||
* @param aSuppressInitialBreak if true, then we assume there is no possible
|
||||
* linebreak before aStart. If false, then we will check the internal
|
||||
* line break opportunity state before deciding whether to return 0 as the
|
||||
* character to break before.
|
||||
* @param aSuppressBreak what break should be suppressed.
|
||||
* @param aTrimWhitespace if non-null, then we allow a trailing run of
|
||||
* spaces to be trimmed; the width of the space(s) will not be included in
|
||||
* the measured string width for comparison with the limit aWidth, and
|
||||
@ -368,7 +373,7 @@ public:
|
||||
uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
||||
bool aLineBreakBefore, gfxFloat aWidth,
|
||||
PropertyProvider *aProvider,
|
||||
bool aSuppressInitialBreak,
|
||||
SuppressBreak aSuppressBreak,
|
||||
gfxFloat *aTrimWhitespace,
|
||||
Metrics *aMetrics,
|
||||
gfxFont::BoundingBoxType aBoundingBoxType,
|
||||
|
@ -433,7 +433,7 @@ gfxWindowsPlatform::UpdateRenderMode()
|
||||
if (isVistaOrHigher && !safeMode && tryD2D &&
|
||||
device &&
|
||||
device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 &&
|
||||
DoesD3D11DeviceWork(device)) {
|
||||
DoesD3D11TextureSharingWork(device)) {
|
||||
|
||||
VerifyD2DDevice(d2dForceEnabled);
|
||||
if (mD2DDevice && GetD3D11Device()) {
|
||||
@ -1553,10 +1553,6 @@ gfxWindowsPlatform::GetDXGIAdapter()
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
#define TEXTURE_SIZE 32
|
||||
|
||||
// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
|
||||
// with E_OUTOFMEMORY.
|
||||
bool DoesD3D11DeviceWork(ID3D11Device *device)
|
||||
{
|
||||
static bool checked;
|
||||
@ -1590,6 +1586,29 @@ bool DoesD3D11DeviceWork(ID3D11Device *device)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define TEXTURE_SIZE 32
|
||||
|
||||
// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
|
||||
// with E_OUTOFMEMORY.
|
||||
bool DoesD3D11TextureSharingWork(ID3D11Device *device)
|
||||
{
|
||||
static bool checked;
|
||||
static bool result;
|
||||
|
||||
if (checked)
|
||||
return result;
|
||||
checked = true;
|
||||
|
||||
if (gfxPrefs::Direct2DForceEnabled() ||
|
||||
gfxPrefs::LayersAccelerationForceEnabled())
|
||||
{
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> texture;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
@ -1785,7 +1804,7 @@ gfxWindowsPlatform::InitD3D11Devices()
|
||||
adapter = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
|
||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return;
|
||||
}
|
||||
|
@ -295,6 +295,7 @@ private:
|
||||
nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
|
||||
};
|
||||
|
||||
bool DoesD3D11TextureSharingWork(ID3D11Device *device);
|
||||
bool DoesD3D11DeviceWork(ID3D11Device *device);
|
||||
|
||||
#endif /* GFX_WINDOWS_PLATFORM_H */
|
||||
|
@ -1031,7 +1031,7 @@ imgLoader::imgLoader()
|
||||
already_AddRefed<imgLoader>
|
||||
imgLoader::GetInstance()
|
||||
{
|
||||
static StaticRefPtr<imgLoader> singleton;
|
||||
static nsRefPtr<imgLoader> singleton;
|
||||
if (!singleton) {
|
||||
singleton = imgLoader::Create();
|
||||
if (!singleton)
|
||||
|
@ -553,271 +553,6 @@ struct ParamTraitsMozilla<nsresult> {
|
||||
|
||||
template <class P> struct ParamTraits : ParamTraitsMozilla<P> {};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generic message subclasses
|
||||
|
||||
// Used for asynchronous messages.
|
||||
template <class ParamType>
|
||||
class MessageWithTuple : public Message {
|
||||
public:
|
||||
typedef ParamType Param;
|
||||
|
||||
MessageWithTuple(int32_t routing_id, uint16_t type, const Param& p)
|
||||
: Message(routing_id, type, PRIORITY_NORMAL) {
|
||||
WriteParam(this, p);
|
||||
}
|
||||
|
||||
static bool Read(const Message* msg, Param* p) {
|
||||
void* iter = NULL;
|
||||
bool rv = ReadParam(msg, &iter, p);
|
||||
DCHECK(rv) << "Error deserializing message " << msg->type();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Generic dispatcher. Should cover most cases.
|
||||
template<class T, class Method>
|
||||
static bool Dispatch(const Message* msg, T* obj, Method func) {
|
||||
Param p;
|
||||
if (Read(msg, &p)) {
|
||||
DispatchToMethod(obj, func, p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following dispatchers exist for the case where the callback function
|
||||
// needs the message as well. They assume that "Param" is a type of Tuple
|
||||
// (except the one arg case, as there is no Tuple1).
|
||||
template<class T, typename TA>
|
||||
static bool Dispatch(const Message* msg, T* obj,
|
||||
void (T::*func)(const Message&, TA)) {
|
||||
Param p;
|
||||
if (Read(msg, &p)) {
|
||||
(obj->*func)(*msg, p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T, typename TA, typename TB>
|
||||
static bool Dispatch(const Message* msg, T* obj,
|
||||
void (T::*func)(const Message&, TA, TB)) {
|
||||
Param p;
|
||||
if (Read(msg, &p)) {
|
||||
(obj->*func)(*msg, p.a, p.b);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T, typename TA, typename TB, typename TC>
|
||||
static bool Dispatch(const Message* msg, T* obj,
|
||||
void (T::*func)(const Message&, TA, TB, TC)) {
|
||||
Param p;
|
||||
if (Read(msg, &p)) {
|
||||
(obj->*func)(*msg, p.a, p.b, p.c);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T, typename TA, typename TB, typename TC, typename TD>
|
||||
static bool Dispatch(const Message* msg, T* obj,
|
||||
void (T::*func)(const Message&, TA, TB, TC, TD)) {
|
||||
Param p;
|
||||
if (Read(msg, &p)) {
|
||||
(obj->*func)(*msg, p.a, p.b, p.c, p.d);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T, typename TA, typename TB, typename TC, typename TD,
|
||||
typename TE>
|
||||
static bool Dispatch(const Message* msg, T* obj,
|
||||
void (T::*func)(const Message&, TA, TB, TC, TD, TE)) {
|
||||
Param p;
|
||||
if (Read(msg, &p)) {
|
||||
(obj->*func)(*msg, p.a, p.b, p.c, p.d, p.e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const Message* msg, std::wstring* l) {
|
||||
Param p;
|
||||
if (Read(msg, &p))
|
||||
LogParam(p, l);
|
||||
}
|
||||
|
||||
// Functions used to do manual unpacking. Only used by the automation code,
|
||||
// these should go away once that code uses SyncChannel.
|
||||
template<typename TA, typename TB>
|
||||
static bool Read(const IPC::Message* msg, TA* a, TB* b) {
|
||||
ParamType params;
|
||||
if (!Read(msg, ¶ms))
|
||||
return false;
|
||||
*a = params.a;
|
||||
*b = params.b;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TA, typename TB, typename TC>
|
||||
static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c) {
|
||||
ParamType params;
|
||||
if (!Read(msg, ¶ms))
|
||||
return false;
|
||||
*a = params.a;
|
||||
*b = params.b;
|
||||
*c = params.c;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TA, typename TB, typename TC, typename TD>
|
||||
static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d) {
|
||||
ParamType params;
|
||||
if (!Read(msg, ¶ms))
|
||||
return false;
|
||||
*a = params.a;
|
||||
*b = params.b;
|
||||
*c = params.c;
|
||||
*d = params.d;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TA, typename TB, typename TC, typename TD, typename TE>
|
||||
static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d, TE* e) {
|
||||
ParamType params;
|
||||
if (!Read(msg, ¶ms))
|
||||
return false;
|
||||
*a = params.a;
|
||||
*b = params.b;
|
||||
*c = params.c;
|
||||
*d = params.d;
|
||||
*e = params.e;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// This class assumes that its template argument is a RefTuple (a Tuple with
|
||||
// reference elements).
|
||||
template <class RefTuple>
|
||||
class ParamDeserializer : public MessageReplyDeserializer {
|
||||
public:
|
||||
explicit ParamDeserializer(const RefTuple& out) : out_(out) { }
|
||||
|
||||
bool SerializeOutputParameters(const IPC::Message& msg, void* iter) {
|
||||
return ReadParam(&msg, &iter, &out_);
|
||||
}
|
||||
|
||||
RefTuple out_;
|
||||
};
|
||||
|
||||
// Used for synchronous messages.
|
||||
template <class SendParamType, class ReplyParamType>
|
||||
class MessageWithReply : public SyncMessage {
|
||||
public:
|
||||
typedef SendParamType SendParam;
|
||||
typedef ReplyParamType ReplyParam;
|
||||
|
||||
MessageWithReply(int32_t routing_id, uint16_t type,
|
||||
const SendParam& send, const ReplyParam& reply)
|
||||
: SyncMessage(routing_id, type, PRIORITY_NORMAL,
|
||||
new ParamDeserializer<ReplyParam>(reply)) {
|
||||
WriteParam(this, send);
|
||||
}
|
||||
|
||||
static void Log(const Message* msg, std::wstring* l) {
|
||||
if (msg->is_sync()) {
|
||||
SendParam p;
|
||||
void* iter = SyncMessage::GetDataIterator(msg);
|
||||
if (ReadParam(msg, &iter, &p))
|
||||
LogParam(p, l);
|
||||
|
||||
} else {
|
||||
// This is an outgoing reply. Now that we have the output parameters, we
|
||||
// can finally log the message.
|
||||
typename ReplyParam::ValueTuple p;
|
||||
void* iter = SyncMessage::GetDataIterator(msg);
|
||||
if (ReadParam(msg, &iter, &p))
|
||||
LogParam(p, l);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class Method>
|
||||
static bool Dispatch(const Message* msg, T* obj, Method func) {
|
||||
SendParam send_params;
|
||||
void* iter = GetDataIterator(msg);
|
||||
Message* reply = GenerateReply(msg);
|
||||
bool error;
|
||||
if (ReadParam(msg, &iter, &send_params)) {
|
||||
typename ReplyParam::ValueTuple reply_params;
|
||||
DispatchToMethod(obj, func, send_params, &reply_params);
|
||||
WriteParam(reply, reply_params);
|
||||
error = false;
|
||||
} else {
|
||||
NOTREACHED() << "Error deserializing message " << msg->type();
|
||||
reply->set_reply_error();
|
||||
error = true;
|
||||
}
|
||||
|
||||
obj->Send(reply);
|
||||
return !error;
|
||||
}
|
||||
|
||||
template<class T, class Method>
|
||||
static bool DispatchDelayReply(const Message* msg, T* obj, Method func) {
|
||||
SendParam send_params;
|
||||
void* iter = GetDataIterator(msg);
|
||||
Message* reply = GenerateReply(msg);
|
||||
bool error;
|
||||
if (ReadParam(msg, &iter, &send_params)) {
|
||||
Tuple1<Message&> t = MakeRefTuple(*reply);
|
||||
|
||||
DispatchToMethod(obj, func, send_params, &t);
|
||||
error = false;
|
||||
} else {
|
||||
NOTREACHED() << "Error deserializing message " << msg->type();
|
||||
reply->set_reply_error();
|
||||
obj->Send(reply);
|
||||
error = true;
|
||||
}
|
||||
return !error;
|
||||
}
|
||||
|
||||
template<typename TA>
|
||||
static void WriteReplyParams(Message* reply, TA a) {
|
||||
ReplyParam p(a);
|
||||
WriteParam(reply, p);
|
||||
}
|
||||
|
||||
template<typename TA, typename TB>
|
||||
static void WriteReplyParams(Message* reply, TA a, TB b) {
|
||||
ReplyParam p(a, b);
|
||||
WriteParam(reply, p);
|
||||
}
|
||||
|
||||
template<typename TA, typename TB, typename TC>
|
||||
static void WriteReplyParams(Message* reply, TA a, TB b, TC c) {
|
||||
ReplyParam p(a, b, c);
|
||||
WriteParam(reply, p);
|
||||
}
|
||||
|
||||
template<typename TA, typename TB, typename TC, typename TD>
|
||||
static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) {
|
||||
ReplyParam p(a, b, c, d);
|
||||
WriteParam(reply, p);
|
||||
}
|
||||
|
||||
template<typename TA, typename TB, typename TC, typename TD, typename TE>
|
||||
static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) {
|
||||
ReplyParam p(a, b, c, d, e);
|
||||
WriteParam(reply, p);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // CHROME_COMMON_IPC_MESSAGE_UTILS_H_
|
||||
|
@ -692,12 +692,6 @@ struct GCMethods<JSFunction *>
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef JS_DEBUG
|
||||
/* This helper allows us to assert that Rooted<T> is scoped within a request. */
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsInRequest(JSContext *cx);
|
||||
#endif
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
namespace JS {
|
||||
@ -730,9 +724,6 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
: ptr(js::GCMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
#ifdef JS_DEBUG
|
||||
MOZ_ASSERT(js::IsInRequest(cx));
|
||||
#endif
|
||||
init(js::ContextFriendFields::get(cx));
|
||||
}
|
||||
|
||||
@ -741,9 +732,6 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
: ptr(initial)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
#ifdef JS_DEBUG
|
||||
MOZ_ASSERT(js::IsInRequest(cx));
|
||||
#endif
|
||||
init(js::ContextFriendFields::get(cx));
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,45 @@
|
||||
* 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/. */
|
||||
|
||||
// ES6 draft rev29 (2014/12/06) 22.2.3.8 %TypedArray%.prototype.fill(value [, start [, end ]])
|
||||
function TypedArrayFill(value, start = 0, end = undefined) {
|
||||
// This function is not generic.
|
||||
if (!IsObject(this) || !IsTypedArray(this)) {
|
||||
return callFunction(CallTypedArrayMethodIfWrapped, this, value, start, end,
|
||||
"TypedArrayFill");
|
||||
}
|
||||
|
||||
// Steps 1-2.
|
||||
var O = this;
|
||||
|
||||
// Steps 3-5.
|
||||
var len = TypedArrayLength(O);
|
||||
|
||||
// Steps 6-7.
|
||||
var relativeStart = ToInteger(start);
|
||||
|
||||
// Step 8.
|
||||
var k = relativeStart < 0
|
||||
? std_Math_max(len + relativeStart, 0)
|
||||
: std_Math_min(relativeStart, len);
|
||||
|
||||
// Steps 9-10.
|
||||
var relativeEnd = end === undefined ? len : ToInteger(end);
|
||||
|
||||
// Step 11.
|
||||
var final = relativeEnd < 0
|
||||
? std_Math_max(len + relativeEnd, 0)
|
||||
: std_Math_min(relativeEnd, len);
|
||||
|
||||
// Step 12.
|
||||
for (; k < final; k++) {
|
||||
O[k] = value;
|
||||
}
|
||||
|
||||
// Step 13.
|
||||
return O;
|
||||
}
|
||||
|
||||
// ES6 draft rev28 (2014/10/14) 22.2.3.10 %TypedArray%.prototype.find(predicate[, thisArg]).
|
||||
function TypedArrayFind(predicate, thisArg = undefined) {
|
||||
// This function is not generic.
|
||||
|
@ -1806,8 +1806,17 @@ ia64*-hpux*)
|
||||
dnl For profile-guided optimization
|
||||
PROFILE_GEN_CFLAGS="-GL"
|
||||
PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
|
||||
PROFILE_USE_CFLAGS="-GL"
|
||||
PROFILE_USE_LDFLAGS="-LTCG:PGOPTIMIZE"
|
||||
dnl XXX: PGO builds can fail with warnings treated as errors,
|
||||
dnl specifically "no profile data available" appears to be
|
||||
dnl treated as an error sometimes. This might be a consequence
|
||||
dnl of using WARNINGS_AS_ERRORS in some modules, combined
|
||||
dnl with the linker doing most of the work in the whole-program
|
||||
dnl optimization/PGO case. I think it's probably a compiler bug,
|
||||
dnl but we work around it here.
|
||||
PROFILE_USE_CFLAGS="-GL -wd4624 -wd4952"
|
||||
dnl XXX: should be -LTCG:PGOPTIMIZE, but that fails on libxul.
|
||||
dnl Probably also a compiler bug, but what can you do?
|
||||
PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE"
|
||||
LDFLAGS="$LDFLAGS -DYNAMICBASE"
|
||||
fi
|
||||
AC_DEFINE(HAVE_SNPRINTF)
|
||||
|
@ -271,6 +271,9 @@ MarkPagesUnused(void *p, size_t size)
|
||||
bool
|
||||
MarkPagesInUse(void *p, size_t size)
|
||||
{
|
||||
if (!DecommitEnabled())
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
|
||||
return true;
|
||||
}
|
||||
@ -344,6 +347,9 @@ MarkPagesUnused(void *p, size_t size)
|
||||
bool
|
||||
MarkPagesInUse(void *p, size_t size)
|
||||
{
|
||||
if (!DecommitEnabled())
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
|
||||
return true;
|
||||
}
|
||||
@ -661,6 +667,9 @@ MarkPagesUnused(void *p, size_t size)
|
||||
bool
|
||||
MarkPagesInUse(void *p, size_t size)
|
||||
{
|
||||
if (!DecommitEnabled())
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(OffsetFromAligned(p, pageSize) == 0);
|
||||
return true;
|
||||
}
|
||||
|
@ -871,34 +871,24 @@ Statistics::beginPhase(Phase phase)
|
||||
{
|
||||
Phase parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT;
|
||||
|
||||
// Re-entry is allowed during callbacks. Do not account nested GC time
|
||||
// against the callbacks.
|
||||
// Re-entry is allowed during callbacks, so pause callback phases while
|
||||
// other phases are in progress, auto-resuming after they end. As a result,
|
||||
// nested GC time will not be accounted against the callback phases.
|
||||
//
|
||||
// Reuse this mechanism for managing PHASE_MUTATOR.
|
||||
if (parent == PHASE_GC_BEGIN || parent == PHASE_GC_END || parent == PHASE_MUTATOR) {
|
||||
suspendedPhases[suspendedPhaseNestingDepth++] = parent;
|
||||
MOZ_ASSERT(suspendedPhaseNestingDepth <= mozilla::ArrayLength(suspendedPhases));
|
||||
endPhase(parent);
|
||||
recordPhaseEnd(parent);
|
||||
parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT;
|
||||
}
|
||||
|
||||
// Guard against any other re-entry.
|
||||
#ifdef DEBUG
|
||||
if (phaseStartTimes[phase]) {
|
||||
fprintf(stderr, "phase %d already has start time of %ld; recursive entry detected!\n",
|
||||
phase, phaseStartTimes[phase]);
|
||||
for (int i = 0; i < phaseNestingDepth; i++)
|
||||
fprintf(stderr, " stack[%d]: %d\n", i, phaseNesting[i]);
|
||||
MOZ_CRASH("My horse for a stack trace!\n");
|
||||
}
|
||||
MOZ_ASSERT(!phaseStartTimes[phase]);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(phases[phase].index == phase);
|
||||
MOZ_ASSERT(phaseNestingDepth < MAX_NESTING);
|
||||
MOZ_ASSERT_IF(gcDepth == 1 && phase != PHASE_MINOR_GC, phases[phase].parent == parent);
|
||||
#endif
|
||||
|
||||
phaseNesting[phaseNestingDepth] = phase;
|
||||
phaseNestingDepth++;
|
||||
@ -907,7 +897,7 @@ Statistics::beginPhase(Phase phase)
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endPhase(Phase phase)
|
||||
Statistics::recordPhaseEnd(Phase phase)
|
||||
{
|
||||
int64_t now = PRMJ_Now();
|
||||
|
||||
@ -921,18 +911,19 @@ Statistics::endPhase(Phase phase)
|
||||
slices.back().phaseTimes[phase] += t;
|
||||
phaseTimes[phase] += t;
|
||||
phaseStartTimes[phase] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endPhase(Phase phase)
|
||||
{
|
||||
recordPhaseEnd(phase);
|
||||
|
||||
// When emptying the stack, we may need to resume a callback phase
|
||||
// (PHASE_GC_BEGIN/END) or if not, return to timing the mutator
|
||||
// (PHASE_MUTATOR).
|
||||
//
|
||||
// However, if the phase we're ending is PHASE_MUTATOR, that means
|
||||
// beginPhase is calling endPhase(PHASE_MUTATOR) because some other phase
|
||||
// is starting. So don't resume any earlier phase.
|
||||
if (phaseNestingDepth == 0 && suspendedPhaseNestingDepth > 0 && phase != PHASE_MUTATOR) {
|
||||
// (PHASE_GC_BEGIN/END) or return to timing the mutator (PHASE_MUTATOR).
|
||||
if (phaseNestingDepth == 0 && suspendedPhaseNestingDepth > 0) {
|
||||
Phase resumePhase = suspendedPhases[--suspendedPhaseNestingDepth];
|
||||
if (resumePhase == PHASE_MUTATOR)
|
||||
timedGCTime += now - timedGCStart;
|
||||
timedGCTime += PRMJ_Now() - timedGCStart;
|
||||
beginPhase(resumePhase);
|
||||
}
|
||||
}
|
||||
|
@ -229,6 +229,8 @@ struct Statistics
|
||||
void beginGC(JSGCInvocationKind kind);
|
||||
void endGC();
|
||||
|
||||
void recordPhaseEnd(Phase phase);
|
||||
|
||||
void gcDuration(int64_t *total, int64_t *maxPause);
|
||||
void sccDurations(int64_t *total, int64_t *maxPause);
|
||||
void printStats();
|
||||
|
32
js/src/jit-test/tests/ion/recover-lambdas-bug1113940.js
Normal file
32
js/src/jit-test/tests/ion/recover-lambdas-bug1113940.js
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
gczeal(14);
|
||||
|
||||
// The object metadata callback can iterate over the stack. Thus during the
|
||||
// allocation of the lambda we might inspect the stack which is still incomplete
|
||||
// because the lambda is not yet reconstructed.
|
||||
setObjectMetadataCallback(function() {});
|
||||
function f() {
|
||||
(function() {
|
||||
'' ^ Object
|
||||
})();
|
||||
}
|
||||
x = 0;
|
||||
for (var j = 0; j < 99; ++j) {
|
||||
x += f();
|
||||
}
|
||||
|
||||
try {
|
||||
x = true;
|
||||
setObjectMetadataCallback(function([x, y, z], ... Debugger) {});
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
var f = function() {
|
||||
function g() {
|
||||
x++;
|
||||
}
|
||||
g();
|
||||
}
|
||||
f();
|
||||
}
|
||||
} catch (e) {
|
||||
assertEq(e instanceof TypeError, true);
|
||||
}
|
@ -9529,19 +9529,6 @@ CodeGenerator::loadJSScriptForBlock(MBasicBlock *block, Register reg)
|
||||
masm.movePtr(ImmGCPtr(script), reg);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitHaveSameClass(LHaveSameClass *ins)
|
||||
{
|
||||
Register lhs = ToRegister(ins->lhs());
|
||||
Register rhs = ToRegister(ins->rhs());
|
||||
Register temp = ToRegister(ins->getTemp(0));
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
masm.loadObjClass(lhs, temp);
|
||||
masm.loadObjClass(rhs, output);
|
||||
masm.cmpPtrSet(Assembler::Equal, temp, output, output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitHasClass(LHasClass *ins)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user