Merge m-c to fx-team. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-12-23 13:19:37 -05:00
commit a77443ef61
164 changed files with 2554 additions and 1021 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "b60aedd37a5ccdb71893d31761988bcc17a82676",
"revision": "51051a09cdd5b1a3c6d2edcc9dd718823adabb59",
"repo_path": "integration/gaia-central"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View 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(&notValid);
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}}
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View File

@ -250,9 +250,10 @@ public:
};
PlatformDecoderModule* CreateBlankDecoderModule()
already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule()
{
return new BlankDecoderModule();
nsRefPtr<PlatformDecoderModule> pdm = new BlankDecoderModule();
return pdm.forget();
}
} // namespace mozilla

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -56,7 +56,7 @@ public:
memmove(data, aData, size);
}
~VP8Sample()
virtual ~VP8Sample()
{
delete data;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -295,6 +295,7 @@ private:
nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
};
bool DoesD3D11TextureSharingWork(ID3D11Device *device);
bool DoesD3D11DeviceWork(ID3D11Device *device);
#endif /* GFX_WINDOWS_PLATFORM_H */

View File

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

View File

@ -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, &params))
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, &params))
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, &params))
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, &params))
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_

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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