From 5600b41cb1fbdfa927ade8a773f9217ae2586cf1 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 22 Dec 2014 12:38:41 +0100 Subject: [PATCH 01/64] Bug 1114368 - Use GCC builtins in MathAlgorithms.h on mingw. r=froydnj --- mfbt/MathAlgorithms.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mfbt/MathAlgorithms.h b/mfbt/MathAlgorithms.h index abfc2184847e..41be25960fb3 100644 --- a/mfbt/MathAlgorithms.h +++ b/mfbt/MathAlgorithms.h @@ -146,7 +146,7 @@ Abs(const long double aLongDouble) } // namespace mozilla -#if defined(_WIN32) && \ +#if defined(_MSC_VER) && \ (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) # define MOZ_BITSCAN_WINDOWS From d1f0ddee76fb6be67dbcdfb4756bc8ed31f10d26 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Mon, 22 Dec 2014 13:16:48 +0100 Subject: [PATCH 02/64] Bug 1107328 - IonMonkey: Also check for boxed constants when checking for constants, r=jandem --- js/src/jit/EffectiveAddressAnalysis.cpp | 12 +- js/src/jit/IonAnalysis.cpp | 14 +- js/src/jit/IonBuilder.cpp | 29 ++-- js/src/jit/Lowering.cpp | 12 +- js/src/jit/MCallOptimize.cpp | 34 ++--- js/src/jit/MIR.cpp | 167 +++++++++++++++--------- js/src/jit/MIR.h | 7 + js/src/jit/RangeAnalysis.cpp | 38 +++--- js/src/jit/ScalarReplacement.cpp | 6 +- js/src/jit/arm/Lowering-arm.cpp | 12 +- js/src/jit/mips/Lowering-mips.cpp | 12 +- 11 files changed, 194 insertions(+), 149 deletions(-) diff --git a/js/src/jit/EffectiveAddressAnalysis.cpp b/js/src/jit/EffectiveAddressAnalysis.cpp index 34559a3620bf..04552edcea9e 100644 --- a/js/src/jit/EffectiveAddressAnalysis.cpp +++ b/js/src/jit/EffectiveAddressAnalysis.cpp @@ -21,10 +21,10 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MOZ_ASSERT(index->type() == MIRType_Int32); MDefinition *shift = lsh->rhs(); - if (!shift->isConstant()) + if (!shift->isConstantValue()) return; - Value shiftValue = shift->toConstant()->value(); + Value shiftValue = shift->constantValue(); if (!shiftValue.isInt32() || !IsShiftInScaleRange(shiftValue.toInt32())) return; @@ -47,8 +47,8 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MDefinition *other = add->getOperand(1 - add->indexOf(*use)); - if (other->isConstant()) { - displacement += other->toConstant()->value().toInt32(); + if (other->isConstantValue()) { + displacement += other->constantValue().toInt32(); } else { if (base) break; @@ -72,11 +72,11 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MBitAnd *bitAnd = use->consumer()->toDefinition()->toBitAnd(); MDefinition *other = bitAnd->getOperand(1 - bitAnd->indexOf(*use)); - if (!other->isConstant() || !other->toConstant()->value().isInt32()) + if (!other->isConstantValue() || !other->constantValue().isInt32()) return; uint32_t bitsClearedByShift = elemSize - 1; - uint32_t bitsClearedByMask = ~uint32_t(other->toConstant()->value().toInt32()); + uint32_t bitsClearedByMask = ~uint32_t(other->constantValue().toInt32()); if ((bitsClearedByShift & bitsClearedByMask) != bitsClearedByMask) return; diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index a19b39d5d84c..3a8caf552756 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -260,7 +260,7 @@ MaybeFoldConditionBlock(MIRGraph &graph, MBasicBlock *initialBlock) MBasicBlock *trueTarget = trueBranch; if (BlockComputesConstant(trueBranch, trueResult)) { - trueTarget = trueResult->toConstant()->valueToBoolean() + trueTarget = trueResult->constantToBoolean() ? finalTest->ifTrue() : finalTest->ifFalse(); testBlock->removePredecessor(trueBranch); @@ -272,7 +272,7 @@ MaybeFoldConditionBlock(MIRGraph &graph, MBasicBlock *initialBlock) MBasicBlock *falseTarget = falseBranch; if (BlockComputesConstant(falseBranch, falseResult)) { - falseTarget = falseResult->toConstant()->valueToBoolean() + falseTarget = falseResult->constantToBoolean() ? finalTest->ifTrue() : finalTest->ifFalse(); testBlock->removePredecessor(falseBranch); @@ -2270,8 +2270,8 @@ jit::ExtractLinearSum(MDefinition *ins) if (ins->type() != MIRType_Int32) return SimpleLinearSum(ins, 0); - if (ins->isConstant()) { - const Value &v = ins->toConstant()->value(); + if (ins->isConstantValue()) { + const Value &v = ins->constantValue(); MOZ_ASSERT(v.isInt32()); return SimpleLinearSum(nullptr, v.toInt32()); } else if (ins->isAdd() || ins->isSub()) { @@ -2672,8 +2672,8 @@ LinearSum::add(MDefinition *term, int32_t scale) if (scale == 0) return true; - if (term->isConstant()) { - int32_t constant = term->toConstant()->value().toInt32(); + if (term->isConstantValue()) { + int32_t constant = term->constantValue().toInt32(); if (!SafeMul(constant, scale, &constant)) return false; return add(constant); @@ -2751,7 +2751,7 @@ jit::ConvertLinearSum(TempAllocator &alloc, MBasicBlock *block, const LinearSum for (size_t i = 0; i < sum.numTerms(); i++) { LinearTerm term = sum.term(i); - MOZ_ASSERT(!term.term->isConstant()); + MOZ_ASSERT(!term.term->isConstantValue()); if (term.scale == 1) { if (def) { def = MAdd::New(alloc, def, term.term); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index af82e4fec42f..7be54d2071f5 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -2261,9 +2261,8 @@ IonBuilder::processDoWhileCondEnd(CFGState &state) return ControlStatus_Error; // Test for do {} while(false) and don't create a loop in that case. - if (vins->isConstant()) { - MConstant *cte = vins->toConstant(); - if (cte->value().isBoolean() && !cte->value().toBoolean()) { + if (vins->isConstantValue() && !vins->constantValue().isMagic()) { + if (!vins->constantToBoolean()) { current->end(MGoto::New(alloc(), successor)); current = nullptr; @@ -4568,7 +4567,7 @@ IonBuilder::makeInliningDecision(JSObject *targetArg, CallInfo &callInfo) bool hasOpportunities = false; for (size_t i = 0, e = callInfo.argv().length(); !hasOpportunities && i < e; i++) { MDefinition *arg = callInfo.argv()[i]; - hasOpportunities = arg->isLambda() || arg->isConstant(); + hasOpportunities = arg->isLambda() || arg->isConstantValue(); } if (!hasOpportunities) @@ -5930,10 +5929,10 @@ IonBuilder::jsop_eval(uint32_t argc) // name on the scope chain and the eval is performing a call on that // value. Use a dynamic scope chain lookup rather than a full eval. if (string->isConcat() && - string->getOperand(1)->isConstant() && - string->getOperand(1)->toConstant()->value().isString()) + string->getOperand(1)->isConstantValue() && + string->getOperand(1)->constantValue().isString()) { - JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom(); + JSAtom *atom = &string->getOperand(1)->constantValue().toString()->asAtom(); if (StringEqualsAscii(atom, "()")) { MDefinition *name = string->getOperand(0); @@ -7846,10 +7845,10 @@ IonBuilder::getElemTryArgumentsInlined(bool *emitted, MDefinition *obj, MDefinit MOZ_ASSERT(!info().argsObjAliasesFormals()); // When the id is constant, we can just return the corresponding inlined argument - if (index->isConstant() && index->toConstant()->value().isInt32()) { + if (index->isConstantValue() && index->constantValue().isInt32()) { MOZ_ASSERT(inliningDepth_ > 0); - int32_t id = index->toConstant()->value().toInt32(); + int32_t id = index->constantValue().toInt32(); index->setImplicitlyUsedUnchecked(); if (id < (int32_t)inlineCallInfo_->argc() && id >= 0) @@ -8065,8 +8064,8 @@ IonBuilder::addTypedArrayLengthAndData(MDefinition *obj, MOZ_ASSERT((index != nullptr) == (elements != nullptr)); JSObject *tarr = nullptr; - if (obj->isConstant() && obj->toConstant()->value().isObject()) - tarr = &obj->toConstant()->value().toObject(); + if (obj->isConstantValue() && obj->constantValue().isObject()) + tarr = &obj->constantValue().toObject(); else if (obj->resultTypeSet()) tarr = obj->resultTypeSet()->getSingleton(); @@ -8123,8 +8122,8 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id, // If the index is an already shifted constant, undo the shift to get the // absolute offset being accessed. - if (id->isConstant() && id->toConstant()->value().isInt32()) { - int32_t index = id->toConstant()->value().toInt32(); + if (id->isConstantValue() && id->constantValue().isInt32()) { + int32_t index = id->constantValue().toInt32(); MConstant *offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType))); current->add(offset); return offset; @@ -8132,9 +8131,9 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id, if (!id->isRsh() || id->isEffectful()) return nullptr; - if (!id->getOperand(1)->isConstant()) + if (!id->getOperand(1)->isConstantValue()) return nullptr; - const Value &value = id->getOperand(1)->toConstant()->value(); + const Value &value = id->getOperand(1)->constantValue(); if (!value.isInt32() || uint32_t(value.toInt32()) != TypedArrayShift(viewType)) return nullptr; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 1d724cf4fc9b..96d7179ea46a 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -623,7 +623,7 @@ ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp) MDefinition *lhs = *lhsp; MDefinition *rhs = *rhsp; - if (lhs->isConstant()) { + if (lhs->isConstantValue()) { *rhsp = lhs; *lhsp = rhs; return ReverseCompareOp(op); @@ -643,8 +643,8 @@ LIRGenerator::visitTest(MTest *test) MOZ_ASSERT(opd->type() != MIRType_String); // Testing a constant. - if (opd->isConstant()) { - bool result = opd->toConstant()->valueToBoolean(); + if (opd->isConstantValue() && !opd->constantValue().isMagic()) { + bool result = opd->constantToBoolean(); add(new(alloc()) LGoto(result ? ifTrue : ifFalse)); return; } @@ -1491,7 +1491,7 @@ LIRGenerator::visitMul(MMul *ins) // If our RHS is a constant -1 and we don't have to worry about // overflow, we can optimize to an LNegI. - if (!ins->fallible() && rhs->isConstant() && rhs->toConstant()->value() == Int32Value(-1)) + if (!ins->fallible() && rhs->isConstantValue() && rhs->constantValue() == Int32Value(-1)) defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(lhs)), ins, 0); else lowerMulI(ins, lhs, rhs); @@ -1500,7 +1500,7 @@ LIRGenerator::visitMul(MMul *ins) ReorderCommutative(&lhs, &rhs, ins); // If our RHS is a constant -1.0, we can optimize to an LNegD. - if (rhs->isConstant() && rhs->toConstant()->value() == DoubleValue(-1.0)) + if (rhs->isConstantValue() && rhs->constantValue() == DoubleValue(-1.0)) defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0); else lowerForFPU(new(alloc()) LMathD(JSOP_MUL), ins, lhs, rhs); @@ -1509,7 +1509,7 @@ LIRGenerator::visitMul(MMul *ins) ReorderCommutative(&lhs, &rhs, ins); // We apply the same optimizations as for doubles - if (rhs->isConstant() && rhs->toConstant()->value() == Float32Value(-1.0f)) + if (rhs->isConstantValue() && rhs->constantValue() == Float32Value(-1.0f)) defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0); else lowerForFPU(new(alloc()) LMathF(JSOP_MUL), ins, lhs, rhs); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index c422f9a07a0a..73d2413b7b78 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -378,7 +378,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) return InliningStatus_NotInlined; MDefinition *arg = callInfo.getArg(0); - if (!arg->isConstant()) { + if (!arg->isConstantValue()) { callInfo.setImplicitlyUsedUnchecked(); ArrayObject *templateArray = &templateObject->as(); MNewArrayDynamicLength *ins = @@ -391,7 +391,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) } // Negative lengths generate a RangeError, unhandled by the inline path. - initLength = arg->toConstant()->value().toInt32(); + initLength = arg->constantValue().toInt32(); if (initLength >= NativeObject::NELEMENTS_LIMIT) return InliningStatus_NotInlined; @@ -1038,10 +1038,10 @@ IonBuilder::inlineMathPow(CallInfo &callInfo) MDefinition *output = nullptr; // Optimize some constant powers. - if (callInfo.getArg(1)->isConstant() && - callInfo.getArg(1)->toConstant()->value().isNumber()) + if (callInfo.getArg(1)->isConstantValue() && + callInfo.getArg(1)->constantValue().isNumber()) { - double pow = callInfo.getArg(1)->toConstant()->value().toNumber(); + double pow = callInfo.getArg(1)->constantValue().toNumber(); // Math.pow(x, 0.5) is a sqrt with edge-case detection. if (pow == 0.5) { @@ -1216,8 +1216,8 @@ IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max) case MIRType_Float32: // Don't force a double MMinMax for arguments that would be a NOP // when doing an integer MMinMax. - if (arg->isConstant()) { - double cte = arg->toConstant()->value().toDouble(); + if (arg->isConstantValue()) { + double cte = arg->constantValue().toDouble(); // min(int32, cte >= INT32_MAX) = int32 if (cte >= INT32_MAX && !max) break; @@ -1368,14 +1368,14 @@ IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo) IonBuilder::InliningStatus IonBuilder::inlineConstantCharCodeAt(CallInfo &callInfo) { - if (!callInfo.thisArg()->isConstant()) + if (!callInfo.thisArg()->isConstantValue()) return InliningStatus_NotInlined; - if (!callInfo.getArg(0)->isConstant()) + if (!callInfo.getArg(0)->isConstantValue()) return InliningStatus_NotInlined; - const js::Value *strval = callInfo.thisArg()->toConstant()->vp(); - const js::Value *idxval = callInfo.getArg(0)->toConstant()->vp(); + const js::Value *strval = callInfo.thisArg()->constantVp(); + const js::Value *idxval = callInfo.getArg(0)->constantVp(); if (!strval->isString() || !idxval->isInt32()) return InliningStatus_NotInlined; @@ -2033,9 +2033,9 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo) // Don't inline if we don't have a constant slot. MDefinition *arg = callInfo.getArg(1); - if (!arg->isConstant()) + if (!arg->isConstantValue()) return InliningStatus_NotInlined; - uint32_t slot = arg->toConstant()->value().toPrivateUint32(); + uint32_t slot = arg->constantValue().toPrivateUint32(); callInfo.setImplicitlyUsedUnchecked(); @@ -2061,9 +2061,9 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo) // Don't inline if we don't have a constant slot. MDefinition *arg = callInfo.getArg(1); - if (!arg->isConstant()) + if (!arg->isConstantValue()) return InliningStatus_NotInlined; - uint32_t slot = arg->toConstant()->value().toPrivateUint32(); + uint32_t slot = arg->constantValue().toPrivateUint32(); callInfo.setImplicitlyUsedUnchecked(); @@ -2259,9 +2259,9 @@ IonBuilder::inlineAssertFloat32(CallInfo &callInfo) MDefinition *secondArg = callInfo.getArg(1); MOZ_ASSERT(secondArg->type() == MIRType_Boolean); - MOZ_ASSERT(secondArg->isConstant()); + MOZ_ASSERT(secondArg->isConstantValue()); - bool mustBeFloat32 = secondArg->toConstant()->value().toBoolean(); + bool mustBeFloat32 = secondArg->constantValue().toBoolean(); current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32)); MConstant *undefined = MConstant::New(alloc(), UndefinedValue()); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index ca19104a0798..bf8895fa1821 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -71,17 +71,45 @@ MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op) fprintf(fp, "%c", tolower(name[i])); } +const Value & +MDefinition::constantValue() +{ + MOZ_ASSERT(isConstantValue()); + + if (isBox()) + return getOperand(0)->constantValue(); + return toConstant()->value(); +} + +const Value * +MDefinition::constantVp() +{ + MOZ_ASSERT(isConstantValue()); + if (isBox()) + return getOperand(0)->constantVp(); + return toConstant()->vp(); +} + +bool +MDefinition::constantToBoolean() +{ + MOZ_ASSERT(isConstantValue()); + if (isBox()) + return getOperand(0)->constantToBoolean(); + return toConstant()->valueToBoolean(); +} + static MConstant * EvaluateConstantOperands(TempAllocator &alloc, MBinaryInstruction *ins, bool *ptypeChange = nullptr) { MDefinition *left = ins->getOperand(0); MDefinition *right = ins->getOperand(1); - if (!left->isConstant() || !right->isConstant()) + if (!left->isConstantValue() || !right->isConstantValue()) return nullptr; - Value lhs = left->toConstant()->value(); - Value rhs = right->toConstant()->value(); + Value lhs = left->constantValue(); + Value rhs = right->constantValue(); Value ret = UndefinedValue(); switch (ins->op()) { @@ -146,10 +174,10 @@ EvaluateExactReciprocal(TempAllocator &alloc, MDiv *ins) MDefinition *left = ins->getOperand(0); MDefinition *right = ins->getOperand(1); - if (!right->isConstant()) + if (!right->isConstantValue()) return nullptr; - Value rhs = right->toConstant()->value(); + Value rhs = right->constantValue(); int32_t num; if (!mozilla::NumberIsInt32(rhs.toNumber(), &num)) @@ -355,8 +383,8 @@ MTest::foldsTo(TempAllocator &alloc) return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue()); } - if (op->isConstant()) - return MGoto::New(alloc, op->toConstant()->valueToBoolean() ? ifTrue() : ifFalse()); + if (op->isConstantValue() && !op->constantValue().isMagic()) + return MGoto::New(alloc, op->constantToBoolean() ? ifTrue() : ifFalse()); switch (op->type()) { case MIRType_Undefined: @@ -768,7 +796,7 @@ MSimdValueX4::foldsTo(TempAllocator &alloc) for (size_t i = 0; i < 4; ++i) { MDefinition *op = getOperand(i); MOZ_ASSERT(op->type() == scalarType); - if (!op->isConstant()) + if (!op->isConstantValue()) allConstants = false; if (i > 0 && op != getOperand(i - 1)) allSame = false; @@ -783,14 +811,14 @@ MSimdValueX4::foldsTo(TempAllocator &alloc) case MIRType_Int32x4: { int32_t a[4]; for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->value().toInt32(); + a[i] = getOperand(i)->constantValue().toInt32(); cst = SimdConstant::CreateX4(a); break; } case MIRType_Float32x4: { float a[4]; for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->value().toNumber(); + a[i] = getOperand(i)->constantValue().toNumber(); cst = SimdConstant::CreateX4(a); break; } @@ -809,7 +837,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) { DebugOnly scalarType = SimdTypeToScalarType(type()); MDefinition *op = getOperand(0); - if (!op->isConstant()) + if (!op->isConstantValue()) return this; MOZ_ASSERT(op->type() == scalarType); @@ -817,7 +845,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) switch (type()) { case MIRType_Int32x4: { int32_t a[4]; - int32_t v = getOperand(0)->toConstant()->value().toInt32(); + int32_t v = getOperand(0)->constantValue().toInt32(); for (size_t i = 0; i < 4; ++i) a[i] = v; cst = SimdConstant::CreateX4(a); @@ -825,7 +853,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) } case MIRType_Float32x4: { float a[4]; - float v = getOperand(0)->toConstant()->value().toNumber(); + float v = getOperand(0)->constantValue().toNumber(); for (size_t i = 0; i < 4; ++i) a[i] = v; cst = SimdConstant::CreateX4(a); @@ -1096,8 +1124,8 @@ MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDef MDefinition* MStringLength::foldsTo(TempAllocator &alloc) { - if ((type() == MIRType_Int32) && (string()->isConstant())) { - Value value = string()->toConstant()->value(); + if ((type() == MIRType_Int32) && (string()->isConstantValue())) { + Value value = string()->constantValue(); JSAtom *atom = &value.toString()->asAtom(); return MConstant::New(alloc, Int32Value(atom->length())); } @@ -1884,12 +1912,10 @@ MMinMax::foldsTo(TempAllocator &alloc) if (!lhs()->isConstant() && !rhs()->isConstant()) return this; - MDefinition *operand = lhs()->isConstant() ? rhs() : lhs(); - MConstant *constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant(); + MDefinition *operand = lhs()->isConstantValue() ? rhs() : lhs(); + const js::Value &val = lhs()->isConstantValue() ? lhs()->constantValue() : rhs()->constantValue(); if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) { - const js::Value &val = constant->value(); - // min(int32, cte >= INT32_MAX) = int32 if (val.isDouble() && val.toDouble() >= INT32_MAX && !isMax()) { MLimitedTruncate *limit = @@ -1959,25 +1985,25 @@ MDiv::analyzeEdgeCasesForward() return; // Try removing divide by zero check - if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0)) + if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0)) canBeDivideByZero_ = false; // If lhs is a constant int != INT32_MIN, then // negative overflow check can be skipped. - if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(INT32_MIN)) + if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(INT32_MIN)) canBeNegativeOverflow_ = false; // If rhs is a constant int != -1, likewise. - if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(-1)) + if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(-1)) canBeNegativeOverflow_ = false; // If lhs is != 0, then negative zero check can be skipped. - if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(0)) + if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(0)) setCanBeNegativeZero(false); // If rhs is >= 0, likewise. - if (rhs()->isConstant()) { - const js::Value &val = rhs()->toConstant()->value(); + if (rhs()->isConstantValue()) { + const js::Value &val = rhs()->constantValue(); if (val.isInt32() && val.toInt32() >= 0) setCanBeNegativeZero(false); } @@ -2015,11 +2041,11 @@ MMod::analyzeEdgeCasesForward() if (specialization_ != MIRType_Int32) return; - if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0)) + if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0)) canBeDivideByZero_ = false; - if (rhs()->isConstant()) { - int32_t n = rhs()->toConstant()->value().toInt32(); + if (rhs()->isConstantValue()) { + int32_t n = rhs()->constantValue().toInt32(); if (n > 0 && !IsPowerOfTwo(n)) canBePowerOfTwoDivisor_ = false; } @@ -2093,15 +2119,15 @@ MMul::analyzeEdgeCasesForward() return; // If lhs is > 0, no need for negative zero check. - if (lhs()->isConstant()) { - const js::Value &val = lhs()->toConstant()->value(); + if (lhs()->isConstantValue()) { + const js::Value &val = lhs()->constantValue(); if (val.isInt32() && val.toInt32() > 0) setCanBeNegativeZero(false); } // If rhs is > 0, likewise. - if (rhs()->isConstant()) { - const js::Value &val = rhs()->toConstant()->value(); + if (rhs()->isConstantValue()) { + const js::Value &val = rhs()->constantValue(); if (val.isInt32() && val.toInt32() > 0) setCanBeNegativeZero(false); } @@ -2370,15 +2396,15 @@ MustBeUInt32(MDefinition *def, MDefinition **pwrapped) *pwrapped = def->toUrsh()->getOperand(0); MDefinition *rhs = def->toUrsh()->getOperand(1); return !def->toUrsh()->bailoutsDisabled() - && rhs->isConstant() - && rhs->toConstant()->value().isInt32() - && rhs->toConstant()->value().toInt32() == 0; + && rhs->isConstantValue() + && rhs->constantValue().isInt32() + && rhs->constantValue().toInt32() == 0; } - if (def->isConstant()) { + if (def->isConstantValue()) { *pwrapped = def; - return def->toConstant()->value().isInt32() - && def->toConstant()->value().toInt32() >= 0; + return def->constantValue().isInt32() + && def->constantValue().toInt32() >= 0; } return false; @@ -2553,7 +2579,7 @@ MBitNot::foldsTo(TempAllocator &alloc) MDefinition *input = getOperand(0); if (input->isConstant()) { - js::Value v = Int32Value(~(input->toConstant()->value().toInt32())); + js::Value v = Int32Value(~(input->constantValue().toInt32())); return MConstant::New(alloc, v); } @@ -2878,11 +2904,14 @@ MDefinition * MTruncateToInt32::foldsTo(TempAllocator &alloc) { MDefinition *input = getOperand(0); + if (input->isBox()) + input = input->getOperand(0); + if (input->type() == MIRType_Int32) return input; if (input->type() == MIRType_Double && input->isConstant()) { - const Value &v = input->toConstant()->value(); + const Value &v = input->constantValue(); int32_t ret = ToInt32(v.toDouble()); return MConstant::New(alloc, Int32Value(ret)); } @@ -2893,12 +2922,15 @@ MTruncateToInt32::foldsTo(TempAllocator &alloc) MDefinition * MToDouble::foldsTo(TempAllocator &alloc) { - MDefinition *in = input(); - if (in->type() == MIRType_Double) - return in; + MDefinition *input = getOperand(0); + if (input->isBox()) + input = input->getOperand(0); - if (in->isConstant()) { - const Value &v = in->toConstant()->value(); + if (input->type() == MIRType_Double) + return input; + + if (input->isConstant()) { + const Value &v = input->toConstant()->value(); if (v.isNumber()) { double out = v.toNumber(); return MConstant::New(alloc, DoubleValue(out)); @@ -2911,15 +2943,19 @@ MToDouble::foldsTo(TempAllocator &alloc) MDefinition * MToFloat32::foldsTo(TempAllocator &alloc) { - if (input()->type() == MIRType_Float32) - return input(); + MDefinition *input = getOperand(0); + if (input->isBox()) + input = input->getOperand(0); + + if (input->type() == MIRType_Float32) + return input; // If x is a Float32, Float32(Double(x)) == x - if (input()->isToDouble() && input()->toToDouble()->input()->type() == MIRType_Float32) - return input()->toToDouble()->input(); + if (input->isToDouble() && input->toToDouble()->input()->type() == MIRType_Float32) + return input->toToDouble()->input(); - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input->isConstant()) { + const Value &v = input->toConstant()->value(); if (v.isNumber()) { float out = v.toNumber(); MConstant *c = MConstant::New(alloc, DoubleValue(out)); @@ -2934,6 +2970,9 @@ MDefinition * MToString::foldsTo(TempAllocator &alloc) { MDefinition *in = input(); + if (in->isBox()) + in = in->getOperand(0); + if (in->type() == MIRType_String) return in; return this; @@ -2942,8 +2981,8 @@ MToString::foldsTo(TempAllocator &alloc) MDefinition * MClampToUint8::foldsTo(TempAllocator &alloc) { - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input()->isConstantValue()) { + const Value &v = input()->constantValue(); if (v.isDouble()) { int32_t clamped = ClampDoubleToUint8(v.toDouble()); return MConstant::New(alloc, Int32Value(clamped)); @@ -3358,8 +3397,8 @@ MDefinition * MNot::foldsTo(TempAllocator &alloc) { // Fold if the input is constant - if (input()->isConstant()) { - bool result = input()->toConstant()->valueToBoolean(); + if (input()->isConstantValue() && !input()->constantValue().isMagic()) { + bool result = input()->constantToBoolean(); if (type() == MIRType_Int32) return MConstant::New(alloc, Int32Value(!result)); @@ -3925,8 +3964,8 @@ MGetPropertyCache::updateForReplacement(MDefinition *ins) { MDefinition * MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc) { - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input()->isConstantValue()) { + const Value &v = input()->constantValue(); if (v.isInt32()) return MConstant::New(alloc, DoubleValue(uint32_t(v.toInt32()))); } @@ -3937,8 +3976,8 @@ MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc) MDefinition * MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc) { - if (input()->isConstant()) { - const Value &v = input()->toConstant()->value(); + if (input()->isConstantValue()) { + const Value &v = input()->constantValue(); if (v.isInt32()) { double dval = double(uint32_t(v.toInt32())); if (IsFloat32Representable(dval)) @@ -3987,8 +4026,8 @@ MSqrt::trySpecializeFloat32(TempAllocator &alloc) { MDefinition * MClz::foldsTo(TempAllocator &alloc) { - if (num()->isConstant()) { - int32_t n = num()->toConstant()->value().toInt32(); + if (num()->isConstantValue()) { + int32_t n = num()->constantValue().toInt32(); if (n == 0) return MConstant::New(alloc, Int32Value(32)); return MConstant::New(alloc, Int32Value(mozilla::CountLeadingZeroes32(n))); @@ -4000,9 +4039,9 @@ MClz::foldsTo(TempAllocator &alloc) MDefinition * MBoundsCheck::foldsTo(TempAllocator &alloc) { - if (index()->isConstant() && length()->isConstant()) { - uint32_t len = length()->toConstant()->value().toInt32(); - uint32_t idx = index()->toConstant()->value().toInt32(); + if (index()->isConstantValue() && length()->isConstantValue()) { + uint32_t len = length()->constantValue().toInt32(); + uint32_t idx = index()->constantValue().toInt32(); if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) return index(); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 909e114f04a0..cdd30ce3f2d9 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -752,6 +752,13 @@ class MDefinition : public MNode MIR_OPCODE_LIST(OPCODE_CASTS) # undef OPCODE_CASTS + bool isConstantValue() { + return isConstant() || (isBox() && getOperand(0)->isConstant()); + } + const Value &constantValue(); + const Value *constantVp(); + bool constantToBoolean(); + inline MInstruction *toInstruction(); inline const MInstruction *toInstruction() const; bool isInstruction() const { diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 4f7bf6c108bb..73956c675497 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -174,12 +174,12 @@ RangeAnalysis::addBetaNodes() conservativeUpper = GenericNaN(); } - if (left->isConstant() && left->toConstant()->value().isNumber()) { - bound = left->toConstant()->value().toNumber(); + if (left->isConstantValue() && left->constantValue().isNumber()) { + bound = left->constantValue().toNumber(); val = right; jsop = ReverseCompareOp(jsop); - } else if (right->isConstant() && right->toConstant()->value().isNumber()) { - bound = right->toConstant()->value().toNumber(); + } else if (right->isConstantValue() && right->constantValue().isNumber()) { + bound = right->constantValue().toNumber(); val = left; } else if (left->type() == MIRType_Int32 && right->type() == MIRType_Int32) { MDefinition *smaller = nullptr; @@ -1310,14 +1310,14 @@ MLsh::computeRange(TempAllocator &alloc) left.wrapAroundToInt32(); MDefinition *rhs = getOperand(1); - if (!rhs->isConstant()) { - right.wrapAroundToShiftCount(); - setRange(Range::lsh(alloc, &left, &right)); + if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { + int32_t c = rhs->constantValue().toInt32(); + setRange(Range::lsh(alloc, &left, c)); return; } - int32_t c = rhs->toConstant()->value().toInt32(); - setRange(Range::lsh(alloc, &left, c)); + right.wrapAroundToShiftCount(); + setRange(Range::lsh(alloc, &left, &right)); } void @@ -1328,14 +1328,14 @@ MRsh::computeRange(TempAllocator &alloc) left.wrapAroundToInt32(); MDefinition *rhs = getOperand(1); - if (!rhs->isConstant()) { - right.wrapAroundToShiftCount(); - setRange(Range::rsh(alloc, &left, &right)); + if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { + int32_t c = rhs->constantValue().toInt32(); + setRange(Range::rsh(alloc, &left, c)); return; } - int32_t c = rhs->toConstant()->value().toInt32(); - setRange(Range::rsh(alloc, &left, c)); + right.wrapAroundToShiftCount(); + setRange(Range::rsh(alloc, &left, &right)); } void @@ -1353,11 +1353,11 @@ MUrsh::computeRange(TempAllocator &alloc) right.wrapAroundToShiftCount(); MDefinition *rhs = getOperand(1); - if (!rhs->isConstant()) { - setRange(Range::ursh(alloc, &left, &right)); - } else { - int32_t c = rhs->toConstant()->value().toInt32(); + if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { + int32_t c = rhs->constantValue().toInt32(); setRange(Range::ursh(alloc, &left, c)); + } else { + setRange(Range::ursh(alloc, &left, &right)); } MOZ_ASSERT(range()->lower() >= 0); @@ -2734,7 +2734,7 @@ CloneForDeadBranches(TempAllocator &alloc, MInstruction *candidate) candidate->block()->insertBefore(candidate, clone); - if (!candidate->isConstant()) { + if (!candidate->isConstantValue()) { MOZ_ASSERT(clone->canRecoverOnBailout()); clone->setRecoveredOnBailout(); } diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 2900fc54f0d4..c96ba425751b 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -533,10 +533,10 @@ IndexOf(MDefinition *ins, int32_t *res) indexDef = indexDef->toBoundsCheck()->index(); if (indexDef->isToInt32()) indexDef = indexDef->toToInt32()->getOperand(0); - if (!indexDef->isConstant()) + if (!indexDef->isConstantValue()) return false; - Value index = indexDef->toConstant()->value(); + Value index = indexDef->constantValue(); if (!index.isInt32()) return false; *res = index.toInt32(); @@ -966,7 +966,7 @@ ArrayMemoryView::visitSetInitializedLength(MSetInitializedLength *ins) // To obtain the length, we need to add 1 to it, and thus we need to create // a new constant that we register in the ArrayState. state_ = BlockState::Copy(alloc_, state_); - int32_t initLengthValue = ins->index()->toConstant()->value().toInt32() + 1; + int32_t initLengthValue = ins->index()->constantValue().toInt32() + 1; MConstant *initLength = MConstant::New(alloc_, Int32Value(initLengthValue)); ins->block()->insertBefore(ins, initLength); ins->block()->insertBefore(ins, state_); diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index 04327f229870..b75169543a74 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -492,10 +492,10 @@ LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins) LAllocation ptrAlloc; // For the ARM it is best to keep the 'ptr' in a register if a bounds check is needed. - if (ptr->isConstant() && !ins->needsBoundsCheck()) { + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { // A bounds check is only skipped for a positive index. - MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->constantVp()); } else { ptrAlloc = useRegisterAtStart(ptr); } @@ -510,9 +510,9 @@ LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) MOZ_ASSERT(ptr->type() == MIRType_Int32); LAllocation ptrAlloc; - if (ptr->isConstant() && !ins->needsBoundsCheck()) { - MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { + MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->constantVp()); } else { ptrAlloc = useRegisterAtStart(ptr); } diff --git a/js/src/jit/mips/Lowering-mips.cpp b/js/src/jit/mips/Lowering-mips.cpp index 68c59be55f81..60364bad6101 100644 --- a/js/src/jit/mips/Lowering-mips.cpp +++ b/js/src/jit/mips/Lowering-mips.cpp @@ -470,11 +470,11 @@ LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins) // For MIPS it is best to keep the 'ptr' in a register if a bounds check // is needed. - if (ptr->isConstant() && !ins->needsBoundsCheck()) { - int32_t ptrValue = ptr->toConstant()->value().toInt32(); + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { + int32_t ptrValue = ptr->constantValue().toInt32(); // A bounds check is only skipped for a positive index. MOZ_ASSERT(ptrValue >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + ptrAlloc = LAllocation(ptr->constantVp()); } else ptrAlloc = useRegisterAtStart(ptr); @@ -488,9 +488,9 @@ LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) MOZ_ASSERT(ptr->type() == MIRType_Int32); LAllocation ptrAlloc; - if (ptr->isConstant() && !ins->needsBoundsCheck()) { - MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); + if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { + MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->constantVp()); } else ptrAlloc = useRegisterAtStart(ptr); From ee70891e45df210088b24857462c759d925856ca Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Tue, 16 Dec 2014 11:21:11 -0500 Subject: [PATCH 03/64] Bug 1066383, rework custom html menu item handling to support contextmenu attribute in separate process, r=janv,mconley,peterv --- b2g/installer/package-manifest.in | 2 + browser/base/content/browser.js | 4 +- browser/base/content/content.js | 12 +- browser/base/content/nsContextMenu.js | 15 +- browser/base/content/tabbrowser.xml | 1 + browser/base/content/test/general/browser.ini | 2 + .../browser_contextmenu_childprocess.js | 87 ++++++ .../test/general/test_contextmenu.html | 2 +- browser/installer/package-manifest.in | 2 + dom/html/HTMLMenuElement.cpp | 17 +- dom/html/htmlMenuBuilder.js | 132 +++++++++ dom/html/htmlMenuBuilder.manifest | 3 + dom/html/moz.build | 5 + dom/html/nsIMenuBuilder.idl | 26 +- dom/webidl/HTMLMenuElement.webidl | 6 +- dom/xul/moz.build | 2 - dom/xul/nsIXULContextMenuBuilder.idl | 38 --- dom/xul/nsXULContextMenuBuilder.cpp | 230 --------------- dom/xul/nsXULContextMenuBuilder.h | 51 ---- mobile/android/installer/package-manifest.in | 2 + toolkit/modules/PageMenu.jsm | 266 ++++++++++++++---- 21 files changed, 515 insertions(+), 390 deletions(-) create mode 100644 browser/base/content/test/general/browser_contextmenu_childprocess.js create mode 100644 dom/html/htmlMenuBuilder.js create mode 100644 dom/html/htmlMenuBuilder.manifest delete mode 100644 dom/xul/nsIXULContextMenuBuilder.idl delete mode 100644 dom/xul/nsXULContextMenuBuilder.cpp delete mode 100644 dom/xul/nsXULContextMenuBuilder.h diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 59ace3c21438..f2e0b172b9e8 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -401,6 +401,8 @@ @BINPATH@/components/nsSidebar.js @BINPATH@/components/nsAsyncShutdown.manifest @BINPATH@/components/nsAsyncShutdown.js +@RESPATH@/components/htmlMenuBuilder.js +@RESPATH@/components/htmlMenuBuilder.manifest ; WiFi, NetworkManager, NetworkStats #ifdef MOZ_WIDGET_GONK diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 692f008f8f0c..a4c876229527 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -259,10 +259,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter", "nsICrashReporter"); #endif -XPCOMUtils.defineLazyGetter(this, "PageMenu", function() { +XPCOMUtils.defineLazyGetter(this, "PageMenuParent", function() { let tmp = {}; Cu.import("resource://gre/modules/PageMenu.jsm", tmp); - return new tmp.PageMenu(); + return new tmp.PageMenuParent(); }); /** diff --git a/browser/base/content/content.js b/browser/base/content/content.js index b2356a6fe4e7..9fc0fd64847e 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -43,6 +43,11 @@ XPCOMUtils.defineLazyGetter(this, "SimpleServiceDiscovery", function() { }); return ssdp; }); +XPCOMUtils.defineLazyGetter(this, "PageMenuChild", function() { + let tmp = {}; + Cu.import("resource://gre/modules/PageMenu.jsm", tmp); + return new tmp.PageMenuChild(); +}); // TabChildGlobal var global = this; @@ -102,6 +107,10 @@ addMessageListener("SecondScreen:tab-mirror", function(message) { } }); +addMessageListener("ContextMenu:DoCustomCommand", function(message) { + PageMenuChild.executeMenu(message.data); +}); + addEventListener("DOMFormHasPassword", function(event) { InsecurePasswordUtils.checkForInsecurePasswords(event.target); LoginManagerContent.onFormPassword(event); @@ -148,7 +157,8 @@ let handleContentContextMenu = function (event) { InlineSpellCheckerContent.initContextMenu(event, editFlags, this); } - sendSyncMessage("contextmenu", { editFlags, spellInfo, addonInfo }, { event, popupNode: event.target }); + let customMenuItems = PageMenuChild.build(event.target); + sendSyncMessage("contextmenu", { editFlags, spellInfo, customMenuItems, addonInfo }, { event, popupNode: event.target }); } else { // Break out to the parent window and pass the add-on info along diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 4dc54af0cdcc..196882fd942f 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -24,10 +24,15 @@ nsContextMenu.prototype = { return; this.hasPageMenu = false; - // FIXME (bug 1047751) - The page menu is disabled in e10s. - if (!aIsShift && !this.isRemote) { - this.hasPageMenu = PageMenu.maybeBuildAndAttachMenu(this.target, - aXulMenu); + if (!aIsShift) { + if (this.isRemote) { + this.hasPageMenu = + PageMenuParent.addToPopup(gContextMenuContentData.customMenuItems, + this.browser, aXulMenu); + } + else { + this.hasPageMenu = PageMenuParent.buildAndAddToPopup(this.target, aXulMenu); + } } this.isFrameImage = document.getElementById("isFrameImage"); @@ -1766,7 +1771,7 @@ nsContextMenu.prototype = { } // Check if this is a page menu item: - if (e.target.hasAttribute(PageMenu.GENERATEDITEMID_ATTR)) { + if (e.target.hasAttribute(PageMenuParent.GENERATEDITEMID_ATTR)) { this._telemetryClickID = "custom-page-item"; } else { this._telemetryClickID = (e.target.id || "unknown").replace(/^context-/i, ""); diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index b081551681c6..87d36f9722f0 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3175,6 +3175,7 @@ browser: browser, editFlags: aMessage.data.editFlags, spellInfo: spellInfo, + customMenuItems: aMessage.data.customMenuItems, addonInfo: aMessage.data.addonInfo }; let popup = browser.ownerDocument.getElementById("contentAreaContextMenu"); let event = gContextMenuContentData.event; diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 317df6f578d4..a3b50024baa2 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -72,6 +72,7 @@ support-files = redirect_bug623155.sjs searchSuggestionEngine.sjs searchSuggestionEngine.xml + subtst_contextmenu.html test-mixedcontent-securityerrors.html test_bug435035.html test_bug462673.html @@ -486,4 +487,5 @@ skip-if = e10s # bug 1100687 - test directly manipulates content (content.docume [browser_mcb_redirect.js] skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account [browser_windowactivation.js] +[browser_contextmenu_childprocess.js] [browser_bug963945.js] diff --git a/browser/base/content/test/general/browser_contextmenu_childprocess.js b/browser/base/content/test/general/browser_contextmenu_childprocess.js new file mode 100644 index 000000000000..c967137919ff --- /dev/null +++ b/browser/base/content/test/general/browser_contextmenu_childprocess.js @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const gBaseURL = "https://example.com/browser/browser/base/content/test/general/"; + +add_task(function *() { + let tab = gBrowser.addTab(); + let browser = gBrowser.getBrowserForTab(tab); + + gBrowser.selectedTab = tab; + yield promiseTabLoadEvent(tab, gBaseURL + "subtst_contextmenu.html"); + + let popupShownPromise = promiseWaitForEvent(window, "popupshown", true); + + // Get the point of the element with the page menu (test-pagemenu) and + // synthesize a right mouse click there. + let eventDetails = { type : "contextmenu", button : 2 }; + let rect = browser.contentWindow.document.getElementById("test-pagemenu").getBoundingClientRect(); + EventUtils.synthesizeMouse(browser, rect.x + rect.width / 2, rect.y + rect.height / 2, eventDetails, window); + + let event = yield popupShownPromise; + + let contextMenu = document.getElementById("contentAreaContextMenu"); + checkMenu(contextMenu); + contextMenu.hidePopup(); + gBrowser.removeCurrentTab(); +}); + +function checkItems(menuitem, arr) +{ + for (let i = 0; i < arr.length; i += 2) { + let str = arr[i]; + let details = arr[i + 1]; + if (str == "---") { + is(menuitem.localName, "menuseparator", "menuseparator"); + } + else if ("children" in details) { + is(menuitem.localName, "menu", "submenu"); + is(menuitem.getAttribute("label"), str, str + " label"); + checkItems(menuitem.firstChild.firstChild, details.children); + } + else { + is(menuitem.localName, "menuitem", str + " menuitem"); + + is(menuitem.getAttribute("label"), str, str + " label"); + is(menuitem.getAttribute("type"), details.type, str + " type"); + is(menuitem.getAttribute("image"), details.icon ? gBaseURL + details.icon : "", str + " icon"); + + if (details.checked) + is(menuitem.getAttribute("checked"), "true", str + " checked"); + else + ok(!menuitem.hasAttribute("checked"), str + " checked"); + + if (details.disabled) + is(menuitem.getAttribute("disabled"), "true", str + " disabled"); + else + ok(!menuitem.hasAttribute("disabled"), str + " disabled"); + } + + menuitem = menuitem.nextSibling; + } +} + +function checkMenu(contextMenu) +{ + let items = [ "Plain item", {type: "", icon: "", checked: false, disabled: false}, + "Disabled item", {type: "", icon: "", checked: false, disabled: true}, + "Item w/ textContent", {type: "", icon: "", checked: false, disabled: false}, + "---", null, + "Checkbox", {type: "checkbox", icon: "", checked: true, disabled: false}, + "---", null, + "Radio1", {type: "checkbox", icon: "", checked: true, disabled: false}, + "Radio2", {type: "checkbox", icon: "", checked: false, disabled: false}, + "Radio3", {type: "checkbox", icon: "", checked: false, disabled: false}, + "---", null, + "Item w/ icon", {type: "", icon: "favicon.ico", checked: false, disabled: false}, + "Item w/ bad icon", {type: "", icon: "", checked: false, disabled: false}, + "---", null, + "Submenu", { children: + ["Radio1", {type: "checkbox", icon: "", checked: false, disabled: false}, + "Radio2", {type: "checkbox", icon: "", checked: true, disabled: false}, + "Radio3", {type: "checkbox", icon: "", checked: false, disabled: false}, + "---", null, + "Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}] } + ]; + checkItems(contextMenu.childNodes[2], items); +} diff --git a/browser/base/content/test/general/test_contextmenu.html b/browser/base/content/test/general/test_contextmenu.html index edb7c705d502..c87ae2b5c40e 100644 --- a/browser/base/content/test/general/test_contextmenu.html +++ b/browser/base/content/test/general/test_contextmenu.html @@ -495,7 +495,7 @@ function runTest(testNum) { "context-viewinfo", true ].concat(inspectItems)); - invokeItemAction("0"); + invokeItemAction("1"); closeContextMenu(); // run mozRequestFullScreen on the element we're testing diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 0feaf0fe704f..a2f944bb616d 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -542,6 +542,8 @@ @RESPATH@/components/Identity.manifest @RESPATH@/components/recording-cmdline.js @RESPATH@/components/recording-cmdline.manifest +@RESPATH@/components/htmlMenuBuilder.js +@RESPATH@/components/htmlMenuBuilder.manifest @RESPATH@/components/PermissionSettings.js @RESPATH@/components/PermissionSettings.manifest diff --git a/dom/html/HTMLMenuElement.cpp b/dom/html/HTMLMenuElement.cpp index 8553534119f5..a15e7d0ea79f 100644 --- a/dom/html/HTMLMenuElement.cpp +++ b/dom/html/HTMLMenuElement.cpp @@ -9,11 +9,13 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/dom/HTMLMenuElementBinding.h" #include "mozilla/dom/HTMLMenuItemElement.h" +#include "nsIMenuBuilder.h" #include "nsAttrValueInlines.h" #include "nsContentUtils.h" -#include "nsXULContextMenuBuilder.h" #include "nsIURI.h" +#define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1" + NS_IMPL_NS_NEW_HTML_ELEMENT(Menu) namespace mozilla { @@ -97,12 +99,8 @@ HTMLMenuElement::CreateBuilder(nsIMenuBuilder** _retval) { NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR); - *_retval = nullptr; - - if (mType == MENU_TYPE_CONTEXT) { - NS_ADDREF(*_retval = new nsXULContextMenuBuilder()); - } - + nsCOMPtr builder = CreateBuilder(); + builder.swap(*_retval); return NS_OK; } @@ -113,8 +111,9 @@ HTMLMenuElement::CreateBuilder() return nullptr; } - nsCOMPtr ret = new nsXULContextMenuBuilder(); - return ret.forget(); + nsCOMPtr builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID); + NS_WARN_IF(!builder); + return builder.forget(); } NS_IMETHODIMP diff --git a/dom/html/htmlMenuBuilder.js b/dom/html/htmlMenuBuilder.js new file mode 100644 index 000000000000..863fc4d74b13 --- /dev/null +++ b/dom/html/htmlMenuBuilder.js @@ -0,0 +1,132 @@ +/* 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/. */ + +// This component is used to build the menus for the HTML contextmenu attribute. + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +const Cc = Components.classes; +const Ci = Components.interfaces; + +// A global value that is used to identify each menu item. It is +// incremented with each one that is found. +var gGeneratedId = 1; + +function HTMLMenuBuilder() { + this.currentNode = null; + this.root = null; + this.items = {}; + this.nestedStack = []; +}; + +// Building is done in two steps: +// The first generates a hierarchical JS object that contains the menu structure. +// This object is returned by toJSONString. +// +// The second step can take this structure and generate a XUL menu hierarchy or +// other UI from this object. The default UI is done in PageMenu.jsm. +// +// When a multi-process browser is used, the first step is performed by the child +// process and the second step is performed by the parent process. + +HTMLMenuBuilder.prototype = +{ + classID: Components.ID("{51c65f5d-0de5-4edc-9058-60e50cef77f8}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMenuBuilder]), + + currentNode: null, + root: null, + items: {}, + nestedStack: [], + + toJSONString: function() { + return JSON.stringify(this.root); + }, + + openContainer: function(aLabel) { + if (!this.currentNode) { + this.root = { + type: "menu", + children: [] + }; + this.currentNode = this.root; + } + else { + let parent = this.currentNode; + this.currentNode = { + type: "menu", + label: aLabel, + children: [] + }; + parent.children.push(this.currentNode); + this.nestedStack.push(parent); + } + }, + + addItemFor: function(aElement, aCanLoadIcon) { + if (!("children" in this.currentNode)) { + return; + } + + let item = { + type: "menuitem", + label: aElement.label + }; + + let elementType = aElement.type; + if (elementType == "checkbox" || elementType == "radio") { + item.checkbox = true; + + if (aElement.checked) { + item.checked = true; + } + } + + let icon = aElement.icon; + if (icon.length > 0 && aCanLoadIcon) { + item.icon = icon; + } + + if (aElement.disabled) { + item.disabled = true; + } + + item.id = gGeneratedId++; + this.currentNode.children.push(item); + + this.items[item.id] = aElement; + }, + + addSeparator: function() { + if (!("children" in this.currentNode)) { + return; + } + + this.currentNode.children.push({ type: "separator"}); + }, + + undoAddSeparator: function() { + if (!("children" in this.currentNode)) { + return; + } + + let children = this.currentNode.children; + if (children.length && children[children.length - 1].type == "separator") { + children.pop(); + } + }, + + closeContainer: function() { + this.currentNode = this.nestedStack.length ? this.nestedStack.pop() : this.root; + }, + + click: function(id) { + let item = this.items[id]; + if (item) { + item.click(); + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HTMLMenuBuilder]); diff --git a/dom/html/htmlMenuBuilder.manifest b/dom/html/htmlMenuBuilder.manifest new file mode 100644 index 000000000000..b245f8fe2de5 --- /dev/null +++ b/dom/html/htmlMenuBuilder.manifest @@ -0,0 +1,3 @@ +component {51c65f5d-0de5-4edc-9058-60e50cef77f8} htmlMenuBuilder.js +contract @mozilla.org/content/html-menu-builder;1 {51c65f5d-0de5-4edc-9058-60e50cef77f8} + diff --git a/dom/html/moz.build b/dom/html/moz.build index cd725e70d2a4..97f6d1799026 100644 --- a/dom/html/moz.build +++ b/dom/html/moz.build @@ -215,6 +215,11 @@ SOURCES += [ 'PluginDocument.cpp', ] +EXTRA_COMPONENTS += [ + 'htmlMenuBuilder.js', + 'htmlMenuBuilder.manifest' +] + FAIL_ON_WARNINGS = True MSVC_ENABLE_PGO = True diff --git a/dom/html/nsIMenuBuilder.idl b/dom/html/nsIMenuBuilder.idl index a925fbcb709e..02664480fa46 100644 --- a/dom/html/nsIMenuBuilder.idl +++ b/dom/html/nsIMenuBuilder.idl @@ -11,7 +11,7 @@ interface nsIDOMHTMLMenuItemElement; * An interface used to construct native toolbar or context menus from */ -[scriptable, uuid(12724737-f7db-43b4-94ab-708a7b86e115)] +[scriptable, uuid(93F4A48F-D043-4F45-97FD-9771EA1AF976)] interface nsIMenuBuilder : nsISupports { @@ -49,4 +49,28 @@ interface nsIMenuBuilder : nsISupports */ void closeContainer(); + /** + * Returns a JSON string representing the menu hierarchy. For a context menu, + * it will be of the form: + * { + * type: "menu", + * children: [ + * { + * type: "menuitem", + * label: "label", + * icon: "image.png" + * }, + * { + * type: "separator", + * }, + * ]; + */ + AString toJSONString(); + + /** + * Invoke the action of the menuitem with assigned id aGeneratedItemId. + * + * @param aGeneratedItemId the menuitem id + */ + void click(in DOMString aGeneratedItemId); }; diff --git a/dom/webidl/HTMLMenuElement.webidl b/dom/webidl/HTMLMenuElement.webidl index 5ee2e66e3790..ff81a7c80d23 100644 --- a/dom/webidl/HTMLMenuElement.webidl +++ b/dom/webidl/HTMLMenuElement.webidl @@ -40,11 +40,11 @@ partial interface HTMLMenuElement { /** * Creates a native menu builder. The builder type is dependent on menu type. - * Currently, it returns nsXULContextMenuBuilder for context menus. - * Toolbar menus are not yet supported (the method returns null). + * Currently, it returns the @mozilla.org/content/html-menu-builder;1 + * component. Toolbar menus are not yet supported (the method returns null). */ [ChromeOnly] - MenuBuilder createBuilder(); + MenuBuilder? createBuilder(); /* * Builds a menu by iterating over menu children. diff --git a/dom/xul/moz.build b/dom/xul/moz.build index 62315cd7cfc5..a316ca9397ec 100644 --- a/dom/xul/moz.build +++ b/dom/xul/moz.build @@ -12,7 +12,6 @@ if CONFIG['MOZ_XUL']: DIRS += ['templates'] XPIDL_SOURCES += [ - 'nsIXULContextMenuBuilder.idl', 'nsIXULOverlayProvider.idl', ] @@ -23,7 +22,6 @@ if CONFIG['MOZ_XUL']: UNIFIED_SOURCES += [ 'nsXULCommandDispatcher.cpp', 'nsXULContentSink.cpp', - 'nsXULContextMenuBuilder.cpp', 'nsXULElement.cpp', 'nsXULPopupListener.cpp', 'nsXULPrototypeCache.cpp', diff --git a/dom/xul/nsIXULContextMenuBuilder.idl b/dom/xul/nsIXULContextMenuBuilder.idl deleted file mode 100644 index 1f5070393f6f..000000000000 --- a/dom/xul/nsIXULContextMenuBuilder.idl +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "nsISupports.idl" - -interface nsIDOMDocumentFragment; - -/** - * An interface for initialization of XUL context menu builder - * and for triggering of menuitem actions with assigned identifiers. - */ - -[scriptable, uuid(eb6b42c0-2f1c-4760-b5ca-bdc9b3ec77d4)] -interface nsIXULContextMenuBuilder : nsISupports -{ - - /** - * Initialize builder before building. - * - * @param aDocumentFragment the fragment that will be used to append top - * level elements - * - * @param aGeneratedItemIdAttrName the name of the attribute that will be - * used to mark elements as generated and for menuitem identification - */ - void init(in nsIDOMDocumentFragment aDocumentFragment, - in AString aGeneratedItemIdAttrName); - - /** - * Invoke the action of the menuitem with assigned id aGeneratedItemId. - * - * @param aGeneratedItemId the menuitem id - */ - void click(in DOMString aGeneratedItemId); - -}; diff --git a/dom/xul/nsXULContextMenuBuilder.cpp b/dom/xul/nsXULContextMenuBuilder.cpp deleted file mode 100644 index e6d9d5602c9e..000000000000 --- a/dom/xul/nsXULContextMenuBuilder.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "nsContentCreatorFunctions.h" -#include "nsIContent.h" -#include "nsIDOMDocumentFragment.h" -#include "nsIDOMHTMLElement.h" -#include "nsIDOMHTMLMenuItemElement.h" -#include "nsXULContextMenuBuilder.h" -#include "nsIDocument.h" -#include "mozilla/dom/Element.h" - -using namespace mozilla; -using namespace mozilla::dom; - -nsXULContextMenuBuilder::nsXULContextMenuBuilder() - : mCurrentGeneratedItemId(0) -{ -} - -nsXULContextMenuBuilder::~nsXULContextMenuBuilder() -{ -} - -NS_IMPL_CYCLE_COLLECTION(nsXULContextMenuBuilder, mFragment, mDocument, - mCurrentNode, mElements) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULContextMenuBuilder) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULContextMenuBuilder) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULContextMenuBuilder) - NS_INTERFACE_MAP_ENTRY(nsIMenuBuilder) - NS_INTERFACE_MAP_ENTRY(nsIXULContextMenuBuilder) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMenuBuilder) -NS_INTERFACE_MAP_END - - -NS_IMETHODIMP -nsXULContextMenuBuilder::OpenContainer(const nsAString& aLabel) -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - if (!mCurrentNode) { - mCurrentNode = mFragment; - } else { - nsCOMPtr menu; - nsresult rv = CreateElement(nsGkAtoms::menu, nullptr, getter_AddRefs(menu)); - NS_ENSURE_SUCCESS(rv, rv); - - menu->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aLabel, false); - - nsCOMPtr menuPopup; - rv = CreateElement(nsGkAtoms::menupopup, nullptr, - getter_AddRefs(menuPopup)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = menu->AppendChildTo(menuPopup, false); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mCurrentNode->AppendChildTo(menu, false); - NS_ENSURE_SUCCESS(rv, rv); - - mCurrentNode = menuPopup; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::AddItemFor(nsIDOMHTMLMenuItemElement* aElement, - bool aCanLoadIcon) -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - nsCOMPtr menuitem; - nsCOMPtr element = do_QueryInterface(aElement); - nsresult rv = CreateElement(nsGkAtoms::menuitem, element, - getter_AddRefs(menuitem)); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString type; - aElement->GetType(type); - if (type.EqualsLiteral("checkbox") || type.EqualsLiteral("radio")) { - // The menu is only temporary, so we don't need to handle - // the radio type precisely. - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::type, - NS_LITERAL_STRING("checkbox"), false); - bool checked; - aElement->GetChecked(&checked); - if (checked) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, - NS_LITERAL_STRING("true"), false); - } - } - - nsAutoString label; - aElement->GetLabel(label); - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::label, label, false); - - nsAutoString icon; - aElement->GetIcon(icon); - if (!icon.IsEmpty()) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, - NS_LITERAL_STRING("menuitem-iconic"), false); - if (aCanLoadIcon) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::image, icon, false); - } - } - - bool disabled; - aElement->GetDisabled(&disabled); - if (disabled) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, - NS_LITERAL_STRING("true"), false); - } - - return mCurrentNode->AppendChildTo(menuitem, false); -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::AddSeparator() -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - nsCOMPtr menuseparator; - nsresult rv = CreateElement(nsGkAtoms::menuseparator, nullptr, - getter_AddRefs(menuseparator)); - NS_ENSURE_SUCCESS(rv, rv); - - return mCurrentNode->AppendChildTo(menuseparator, false); -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::UndoAddSeparator() -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - uint32_t count = mCurrentNode->GetChildCount(); - if (!count || - mCurrentNode->GetChildAt(count - 1)->Tag() != nsGkAtoms::menuseparator) { - return NS_OK; - } - - mCurrentNode->RemoveChildAt(count - 1, false); - return NS_OK; -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::CloseContainer() -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - if (mCurrentNode == mFragment) { - mCurrentNode = nullptr; - } else { - nsIContent* parent = mCurrentNode->GetParent(); - mCurrentNode = parent->GetParent(); - } - - return NS_OK; -} - - -NS_IMETHODIMP -nsXULContextMenuBuilder::Init(nsIDOMDocumentFragment* aDocumentFragment, - const nsAString& aGeneratedItemIdAttrName) -{ - NS_ENSURE_ARG_POINTER(aDocumentFragment); - - mFragment = do_QueryInterface(aDocumentFragment); - mDocument = mFragment->GetOwnerDocument(); - mGeneratedItemIdAttr = do_GetAtom(aGeneratedItemIdAttrName); - - return NS_OK; -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::Click(const nsAString& aGeneratedItemId) -{ - nsresult rv; - int32_t idx = nsString(aGeneratedItemId).ToInteger(&rv); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr element = mElements.SafeObjectAt(idx); - if (element) { - element->DOMClick(); - } - } - - return NS_OK; -} - -nsresult -nsXULContextMenuBuilder::CreateElement(nsIAtom* aTag, - nsIDOMHTMLElement* aHTMLElement, - Element** aResult) -{ - *aResult = nullptr; - - nsRefPtr nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo( - aTag, nullptr, kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE); - - nsresult rv = NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER); - if (NS_FAILED(rv)) { - return rv; - } - - nsAutoString generateditemid; - - if (aHTMLElement) { - mElements.AppendObject(aHTMLElement); - generateditemid.AppendInt(mCurrentGeneratedItemId++); - } - - (*aResult)->SetAttr(kNameSpaceID_None, mGeneratedItemIdAttr, generateditemid, - false); - - return NS_OK; -} diff --git a/dom/xul/nsXULContextMenuBuilder.h b/dom/xul/nsXULContextMenuBuilder.h deleted file mode 100644 index 83e19cb99dab..000000000000 --- a/dom/xul/nsXULContextMenuBuilder.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "nsCOMPtr.h" -#include "nsCOMArray.h" -#include "nsIMenuBuilder.h" -#include "nsIXULContextMenuBuilder.h" -#include "nsCycleCollectionParticipant.h" - -class nsIAtom; -class nsIContent; -class nsIDocument; -class nsIDOMHTMLElement; - -namespace mozilla { -namespace dom { -class Element; -} // namespace dom -} // namespace mozilla - -class nsXULContextMenuBuilder : public nsIMenuBuilder, - public nsIXULContextMenuBuilder -{ -public: - nsXULContextMenuBuilder(); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULContextMenuBuilder, - nsIMenuBuilder) - NS_DECL_NSIMENUBUILDER - - NS_DECL_NSIXULCONTEXTMENUBUILDER - -protected: - virtual ~nsXULContextMenuBuilder(); - - nsresult CreateElement(nsIAtom* aTag, - nsIDOMHTMLElement* aHTMLElement, - mozilla::dom::Element** aResult); - - nsCOMPtr mFragment; - nsCOMPtr mDocument; - nsCOMPtr mGeneratedItemIdAttr; - - nsCOMPtr mCurrentNode; - int32_t mCurrentGeneratedItemId; - - nsCOMArray mElements; -}; diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index bccdc4c56b66..ec9eb81e8a74 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -408,6 +408,8 @@ @BINPATH@/components/Webapps.manifest @BINPATH@/components/AppsService.js @BINPATH@/components/AppsService.manifest +@RESPATH@/components/htmlMenuBuilder.js +@RESPATH@/components/htmlMenuBuilder.manifest @BINPATH@/components/Activities.manifest @BINPATH@/components/ActivitiesGlue.js diff --git a/toolkit/modules/PageMenu.jsm b/toolkit/modules/PageMenu.jsm index 7d5823f8557b..d36120b6b0fe 100644 --- a/toolkit/modules/PageMenu.jsm +++ b/toolkit/modules/PageMenu.jsm @@ -2,7 +2,7 @@ * 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/. */ -this.EXPORTED_SYMBOLS = ["PageMenu"]; +this.EXPORTED_SYMBOLS = ["PageMenuParent", "PageMenuChild"]; this.PageMenu = function PageMenu() { } @@ -11,46 +11,71 @@ PageMenu.prototype = { PAGEMENU_ATTR: "pagemenu", GENERATEDITEMID_ATTR: "generateditemid", - popup: null, - builder: null, + _popup: null, - maybeBuildAndAttachMenu: function(aTarget, aPopup) { - var pageMenu = null; - var target = aTarget; + // Only one of builder or browser will end up getting set. + _builder: null, + _browser: null, + + // Given a target node, get the context menu for it or its ancestor. + getContextMenu: function(aTarget) { + let pageMenu = null; + let target = aTarget; while (target) { - var contextMenu = target.contextMenu; + let contextMenu = target.contextMenu; if (contextMenu) { - pageMenu = contextMenu; - break; + return contextMenu; } target = target.parentNode; } - if (!pageMenu) { - return false; - } + return null; + }, - var insertionPoint = this.getInsertionPoint(aPopup); - if (!insertionPoint) { - return false; + // Given a target node, generate a JSON object for any context menu + // associated with it, or null if there is no context menu. + maybeBuild: function(aTarget) { + let pageMenu = this.getContextMenu(aTarget); + if (!pageMenu) { + return null; } pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu); pageMenu.sendShowEvent(); // the show event is not cancelable, so no need to check a result here - var fragment = aPopup.ownerDocument.createDocumentFragment(); + this._builder = pageMenu.createBuilder(); + if (!this._builder) { + return null; + } - var builder = pageMenu.createBuilder(); - if (!builder) { + pageMenu.build(this._builder); + + // This serializes then parses again, however this could be avoided in + // the single-process case with further improvement. + let menuString = this._builder.toJSONString(); + if (!menuString) { + return null; + } + + return JSON.parse(menuString); + }, + + // Given a JSON menu object and popup, add the context menu to the popup. + buildAndAttachMenuWithObject: function(aMenu, aBrowser, aPopup) { + if (!aMenu) { return false; } - builder.QueryInterface(Components.interfaces.nsIXULContextMenuBuilder); - builder.init(fragment, this.GENERATEDITEMID_ATTR); - pageMenu.build(builder); + let insertionPoint = this.getInsertionPoint(aPopup); + if (!insertionPoint) { + return false; + } - var pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR); + let fragment = aPopup.ownerDocument.createDocumentFragment(); + this.buildXULMenu(aMenu, fragment); + + let pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR); if (pos == "start") { insertionPoint.insertBefore(fragment, insertionPoint.firstChild); @@ -60,33 +85,101 @@ PageMenu.prototype = { insertionPoint.appendChild(fragment); } - this.builder = builder; - this.popup = aPopup; + this._browser = aBrowser; + this._popup = aPopup; - this.popup.addEventListener("command", this); - this.popup.addEventListener("popuphidden", this); + this._popup.addEventListener("command", this); + this._popup.addEventListener("popuphidden", this); return true; }, - handleEvent: function(event) { - var type = event.type; - var target = event.target; - if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) { - this.builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR)); - } else if (type == "popuphidden" && this.popup == target) { - this.removeGeneratedContent(this.popup); + // Construct the XUL menu structure for a given JSON object. + buildXULMenu: function(aNode, aElementForAppending) { + let document = aElementForAppending.ownerDocument; - this.popup.removeEventListener("popuphidden", this); - this.popup.removeEventListener("command", this); + let children = aNode.children; + for (let child of children) { + let menuitem; + switch (child.type) { + case "menuitem": + if (!child.id) { + continue; // Ignore children without ids + } - this.popup = null; - this.builder = null; + menuitem = document.createElement("menuitem"); + if (child.checkbox) { + menuitem.setAttribute("type", "checkbox"); + if (child.checked) { + menuitem.setAttribute("checked", "true"); + } + } + + if (child.label) { + menuitem.setAttribute("label", child.label); + } + if (child.icon) { + menuitem.setAttribute("image", child.icon); + menuitem.className = "menuitem-iconic"; + } + if (child.disabled) { + menuitem.setAttribute("disabled", true); + } + + break; + + case "separator": + menuitem = document.createElement("menuseparator"); + break; + + case "menu": + menuitem = document.createElement("menu"); + if (child.label) { + menuitem.setAttribute("label", child.label); + } + + let menupopup = document.createElement("menupopup"); + menuitem.appendChild(menupopup); + + this.buildXULMenu(child, menupopup); + break; + } + + menuitem.setAttribute(this.GENERATEDITEMID_ATTR, child.id ? child.id : 0); + aElementForAppending.appendChild(menuitem); } }, + // Called when the generated menuitem is executed. + handleEvent: function(event) { + let type = event.type; + let target = event.target; + if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) { + // If a builder is assigned, call click on it directly. Otherwise, this is + // likely a menu with data from another process, so send a message to the + // browser to execute the menuitem. + if (this._builder) { + this._builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR)); + } + else if (this._browser) { + this._browser.messageManager.sendAsyncMessage("ContextMenu:DoCustomCommand", + target.getAttribute(this.GENERATEDITEMID_ATTR)); + } + } else if (type == "popuphidden" && this._popup == target) { + this.removeGeneratedContent(this._popup); + + this._popup.removeEventListener("popuphidden", this); + this._popup.removeEventListener("command", this); + + this._popup = null; + this._builder = null; + this._browser = null; + } + }, + + // Get the first child of the given element with the given tag name. getImmediateChild: function(element, tag) { - var child = element.firstChild; + let child = element.firstChild; while (child) { if (child.localName == tag) { return child; @@ -96,16 +189,19 @@ PageMenu.prototype = { return null; }, + // Return the location where the generated items should be inserted into the + // given popup. They should be inserted as the next sibling of the returned + // element. getInsertionPoint: function(aPopup) { if (aPopup.hasAttribute(this.PAGEMENU_ATTR)) return aPopup; - var element = aPopup.firstChild; + let element = aPopup.firstChild; while (element) { if (element.localName == "menu") { - var popup = this.getImmediateChild(element, "menupopup"); + let popup = this.getImmediateChild(element, "menupopup"); if (popup) { - var result = this.getInsertionPoint(popup); + let result = this.getInsertionPoint(popup); if (result) { return result; } @@ -117,19 +213,20 @@ PageMenu.prototype = { return null; }, + // Remove the generated content from the given popup. removeGeneratedContent: function(aPopup) { - var ungenerated = []; + let ungenerated = []; ungenerated.push(aPopup); - var count; + let count; while (0 != (count = ungenerated.length)) { - var last = count - 1; - var element = ungenerated[last]; + let last = count - 1; + let element = ungenerated[last]; ungenerated.splice(last, 1); - var i = element.childNodes.length; + let i = element.childNodes.length; while (i-- > 0) { - var child = element.childNodes[i]; + let child = element.childNodes[i]; if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) { ungenerated.push(child); continue; @@ -139,3 +236,78 @@ PageMenu.prototype = { } } } + +// This object is expected to be used from a parent process. +this.PageMenuParent = function PageMenuParent() { +} + +PageMenuParent.prototype = { + __proto__ : PageMenu.prototype, + + /* + * Given a target node and popup, add the context menu to the popup. This is + * intended to be called when a single process is used. This is equivalent to + * calling PageMenuChild.build and PageMenuParent.addToPopup in sequence. + * + * Returns true if custom menu items were present. + */ + buildAndAddToPopup: function(aTarget, aPopup) { + let menuObject = this.maybeBuild(aTarget); + if (!menuObject) { + return false; + } + + return this.buildAndAttachMenuWithObject(menuObject, null, aPopup); + }, + + /* + * Given a JSON menu object and popup, add the context menu to the popup. This + * is intended to be called when the child page is in a different process. + * aBrowser should be the browser containing the page the context menu is + * displayed for, which may be null. + * + * Returns true if custom menu items were present. + */ + addToPopup: function(aMenu, aBrowser, aPopup) { + return this.buildAndAttachMenuWithObject(aMenu, aBrowser, aPopup); + } +} + +// This object is expected to be used from a child process. +this.PageMenuChild = function PageMenuChild() { +} + +PageMenuChild.prototype = { + __proto__ : PageMenu.prototype, + + /* + * Given a target node, return a JSON object for the custom menu commands. The + * object will consist of a hierarchical structure of menus, menuitems or + * separators. Supported properties of each are: + * Menu: children, label, type="menu" + * Menuitems: checkbox, checked, disabled, icon, label, type="menuitem" + * Separators: type="separator" + * + * In addition, the id of each item will be used to identify the item + * when it is executed. The type will either be 'menu', 'menuitem' or + * 'separator'. The toplevel node will be a menu with a children property. The + * children property of a menu is an array of zero or more other items. + * + * If there is no menu associated with aTarget, null will be returned. + */ + build: function(aTarget) { + return this.maybeBuild(aTarget); + }, + + /* + * Given the id of a menu, execute the command associated with that menu. It + * is assumed that only one command will be executed so the builder is + * cleared afterwards. + */ + executeMenu: function(aId) { + if (this._builder) { + this._builder.click(aId); + this._builder = null; + } + } +} From 7bccfba59f5c76508d2c41a2f8add31cfe52b438 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Mon, 22 Dec 2014 14:36:02 +0100 Subject: [PATCH 04/64] Backed out changeset 8455b9eef8f8 (bug 1066383) for bustage on a CLOSED TREE --- b2g/installer/package-manifest.in | 2 - browser/base/content/browser.js | 4 +- browser/base/content/content.js | 12 +- browser/base/content/nsContextMenu.js | 15 +- browser/base/content/tabbrowser.xml | 1 - browser/base/content/test/general/browser.ini | 2 - .../browser_contextmenu_childprocess.js | 87 ------ .../test/general/test_contextmenu.html | 2 +- browser/installer/package-manifest.in | 2 - dom/html/HTMLMenuElement.cpp | 17 +- dom/html/htmlMenuBuilder.js | 132 --------- dom/html/htmlMenuBuilder.manifest | 3 - dom/html/moz.build | 5 - dom/html/nsIMenuBuilder.idl | 26 +- dom/webidl/HTMLMenuElement.webidl | 6 +- dom/xul/moz.build | 2 + dom/xul/nsIXULContextMenuBuilder.idl | 38 +++ dom/xul/nsXULContextMenuBuilder.cpp | 230 +++++++++++++++ dom/xul/nsXULContextMenuBuilder.h | 51 ++++ mobile/android/installer/package-manifest.in | 2 - toolkit/modules/PageMenu.jsm | 262 +++--------------- 21 files changed, 388 insertions(+), 513 deletions(-) delete mode 100644 browser/base/content/test/general/browser_contextmenu_childprocess.js delete mode 100644 dom/html/htmlMenuBuilder.js delete mode 100644 dom/html/htmlMenuBuilder.manifest create mode 100644 dom/xul/nsIXULContextMenuBuilder.idl create mode 100644 dom/xul/nsXULContextMenuBuilder.cpp create mode 100644 dom/xul/nsXULContextMenuBuilder.h diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index f2e0b172b9e8..59ace3c21438 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -401,8 +401,6 @@ @BINPATH@/components/nsSidebar.js @BINPATH@/components/nsAsyncShutdown.manifest @BINPATH@/components/nsAsyncShutdown.js -@RESPATH@/components/htmlMenuBuilder.js -@RESPATH@/components/htmlMenuBuilder.manifest ; WiFi, NetworkManager, NetworkStats #ifdef MOZ_WIDGET_GONK diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index c886033e57ed..d6e4b1de03a3 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -259,10 +259,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter", "nsICrashReporter"); #endif -XPCOMUtils.defineLazyGetter(this, "PageMenuParent", function() { +XPCOMUtils.defineLazyGetter(this, "PageMenu", function() { let tmp = {}; Cu.import("resource://gre/modules/PageMenu.jsm", tmp); - return new tmp.PageMenuParent(); + return new tmp.PageMenu(); }); /** diff --git a/browser/base/content/content.js b/browser/base/content/content.js index 9fc0fd64847e..b2356a6fe4e7 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -43,11 +43,6 @@ XPCOMUtils.defineLazyGetter(this, "SimpleServiceDiscovery", function() { }); return ssdp; }); -XPCOMUtils.defineLazyGetter(this, "PageMenuChild", function() { - let tmp = {}; - Cu.import("resource://gre/modules/PageMenu.jsm", tmp); - return new tmp.PageMenuChild(); -}); // TabChildGlobal var global = this; @@ -107,10 +102,6 @@ addMessageListener("SecondScreen:tab-mirror", function(message) { } }); -addMessageListener("ContextMenu:DoCustomCommand", function(message) { - PageMenuChild.executeMenu(message.data); -}); - addEventListener("DOMFormHasPassword", function(event) { InsecurePasswordUtils.checkForInsecurePasswords(event.target); LoginManagerContent.onFormPassword(event); @@ -157,8 +148,7 @@ let handleContentContextMenu = function (event) { InlineSpellCheckerContent.initContextMenu(event, editFlags, this); } - let customMenuItems = PageMenuChild.build(event.target); - sendSyncMessage("contextmenu", { editFlags, spellInfo, customMenuItems, addonInfo }, { event, popupNode: event.target }); + sendSyncMessage("contextmenu", { editFlags, spellInfo, addonInfo }, { event, popupNode: event.target }); } else { // Break out to the parent window and pass the add-on info along diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 196882fd942f..4dc54af0cdcc 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -24,15 +24,10 @@ nsContextMenu.prototype = { return; this.hasPageMenu = false; - if (!aIsShift) { - if (this.isRemote) { - this.hasPageMenu = - PageMenuParent.addToPopup(gContextMenuContentData.customMenuItems, - this.browser, aXulMenu); - } - else { - this.hasPageMenu = PageMenuParent.buildAndAddToPopup(this.target, aXulMenu); - } + // FIXME (bug 1047751) - The page menu is disabled in e10s. + if (!aIsShift && !this.isRemote) { + this.hasPageMenu = PageMenu.maybeBuildAndAttachMenu(this.target, + aXulMenu); } this.isFrameImage = document.getElementById("isFrameImage"); @@ -1771,7 +1766,7 @@ nsContextMenu.prototype = { } // Check if this is a page menu item: - if (e.target.hasAttribute(PageMenuParent.GENERATEDITEMID_ATTR)) { + if (e.target.hasAttribute(PageMenu.GENERATEDITEMID_ATTR)) { this._telemetryClickID = "custom-page-item"; } else { this._telemetryClickID = (e.target.id || "unknown").replace(/^context-/i, ""); diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 87d36f9722f0..b081551681c6 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3175,7 +3175,6 @@ browser: browser, editFlags: aMessage.data.editFlags, spellInfo: spellInfo, - customMenuItems: aMessage.data.customMenuItems, addonInfo: aMessage.data.addonInfo }; let popup = browser.ownerDocument.getElementById("contentAreaContextMenu"); let event = gContextMenuContentData.event; diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index a1232ad10570..7322e5b95d66 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -72,7 +72,6 @@ support-files = redirect_bug623155.sjs searchSuggestionEngine.sjs searchSuggestionEngine.xml - subtst_contextmenu.html test-mixedcontent-securityerrors.html test_bug435035.html test_bug462673.html @@ -487,5 +486,4 @@ skip-if = e10s # bug 1100687 - test directly manipulates content (content.docume [browser_mcb_redirect.js] skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account [browser_windowactivation.js] -[browser_contextmenu_childprocess.js] [browser_bug963945.js] diff --git a/browser/base/content/test/general/browser_contextmenu_childprocess.js b/browser/base/content/test/general/browser_contextmenu_childprocess.js deleted file mode 100644 index c967137919ff..000000000000 --- a/browser/base/content/test/general/browser_contextmenu_childprocess.js +++ /dev/null @@ -1,87 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -const gBaseURL = "https://example.com/browser/browser/base/content/test/general/"; - -add_task(function *() { - let tab = gBrowser.addTab(); - let browser = gBrowser.getBrowserForTab(tab); - - gBrowser.selectedTab = tab; - yield promiseTabLoadEvent(tab, gBaseURL + "subtst_contextmenu.html"); - - let popupShownPromise = promiseWaitForEvent(window, "popupshown", true); - - // Get the point of the element with the page menu (test-pagemenu) and - // synthesize a right mouse click there. - let eventDetails = { type : "contextmenu", button : 2 }; - let rect = browser.contentWindow.document.getElementById("test-pagemenu").getBoundingClientRect(); - EventUtils.synthesizeMouse(browser, rect.x + rect.width / 2, rect.y + rect.height / 2, eventDetails, window); - - let event = yield popupShownPromise; - - let contextMenu = document.getElementById("contentAreaContextMenu"); - checkMenu(contextMenu); - contextMenu.hidePopup(); - gBrowser.removeCurrentTab(); -}); - -function checkItems(menuitem, arr) -{ - for (let i = 0; i < arr.length; i += 2) { - let str = arr[i]; - let details = arr[i + 1]; - if (str == "---") { - is(menuitem.localName, "menuseparator", "menuseparator"); - } - else if ("children" in details) { - is(menuitem.localName, "menu", "submenu"); - is(menuitem.getAttribute("label"), str, str + " label"); - checkItems(menuitem.firstChild.firstChild, details.children); - } - else { - is(menuitem.localName, "menuitem", str + " menuitem"); - - is(menuitem.getAttribute("label"), str, str + " label"); - is(menuitem.getAttribute("type"), details.type, str + " type"); - is(menuitem.getAttribute("image"), details.icon ? gBaseURL + details.icon : "", str + " icon"); - - if (details.checked) - is(menuitem.getAttribute("checked"), "true", str + " checked"); - else - ok(!menuitem.hasAttribute("checked"), str + " checked"); - - if (details.disabled) - is(menuitem.getAttribute("disabled"), "true", str + " disabled"); - else - ok(!menuitem.hasAttribute("disabled"), str + " disabled"); - } - - menuitem = menuitem.nextSibling; - } -} - -function checkMenu(contextMenu) -{ - let items = [ "Plain item", {type: "", icon: "", checked: false, disabled: false}, - "Disabled item", {type: "", icon: "", checked: false, disabled: true}, - "Item w/ textContent", {type: "", icon: "", checked: false, disabled: false}, - "---", null, - "Checkbox", {type: "checkbox", icon: "", checked: true, disabled: false}, - "---", null, - "Radio1", {type: "checkbox", icon: "", checked: true, disabled: false}, - "Radio2", {type: "checkbox", icon: "", checked: false, disabled: false}, - "Radio3", {type: "checkbox", icon: "", checked: false, disabled: false}, - "---", null, - "Item w/ icon", {type: "", icon: "favicon.ico", checked: false, disabled: false}, - "Item w/ bad icon", {type: "", icon: "", checked: false, disabled: false}, - "---", null, - "Submenu", { children: - ["Radio1", {type: "checkbox", icon: "", checked: false, disabled: false}, - "Radio2", {type: "checkbox", icon: "", checked: true, disabled: false}, - "Radio3", {type: "checkbox", icon: "", checked: false, disabled: false}, - "---", null, - "Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}] } - ]; - checkItems(contextMenu.childNodes[2], items); -} diff --git a/browser/base/content/test/general/test_contextmenu.html b/browser/base/content/test/general/test_contextmenu.html index c87ae2b5c40e..edb7c705d502 100644 --- a/browser/base/content/test/general/test_contextmenu.html +++ b/browser/base/content/test/general/test_contextmenu.html @@ -495,7 +495,7 @@ function runTest(testNum) { "context-viewinfo", true ].concat(inspectItems)); - invokeItemAction("1"); + invokeItemAction("0"); closeContextMenu(); // run mozRequestFullScreen on the element we're testing diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index a2f944bb616d..0feaf0fe704f 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -542,8 +542,6 @@ @RESPATH@/components/Identity.manifest @RESPATH@/components/recording-cmdline.js @RESPATH@/components/recording-cmdline.manifest -@RESPATH@/components/htmlMenuBuilder.js -@RESPATH@/components/htmlMenuBuilder.manifest @RESPATH@/components/PermissionSettings.js @RESPATH@/components/PermissionSettings.manifest diff --git a/dom/html/HTMLMenuElement.cpp b/dom/html/HTMLMenuElement.cpp index a15e7d0ea79f..8553534119f5 100644 --- a/dom/html/HTMLMenuElement.cpp +++ b/dom/html/HTMLMenuElement.cpp @@ -9,13 +9,11 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/dom/HTMLMenuElementBinding.h" #include "mozilla/dom/HTMLMenuItemElement.h" -#include "nsIMenuBuilder.h" #include "nsAttrValueInlines.h" #include "nsContentUtils.h" +#include "nsXULContextMenuBuilder.h" #include "nsIURI.h" -#define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1" - NS_IMPL_NS_NEW_HTML_ELEMENT(Menu) namespace mozilla { @@ -99,8 +97,12 @@ HTMLMenuElement::CreateBuilder(nsIMenuBuilder** _retval) { NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR); - nsCOMPtr builder = CreateBuilder(); - builder.swap(*_retval); + *_retval = nullptr; + + if (mType == MENU_TYPE_CONTEXT) { + NS_ADDREF(*_retval = new nsXULContextMenuBuilder()); + } + return NS_OK; } @@ -111,9 +113,8 @@ HTMLMenuElement::CreateBuilder() return nullptr; } - nsCOMPtr builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID); - NS_WARN_IF(!builder); - return builder.forget(); + nsCOMPtr ret = new nsXULContextMenuBuilder(); + return ret.forget(); } NS_IMETHODIMP diff --git a/dom/html/htmlMenuBuilder.js b/dom/html/htmlMenuBuilder.js deleted file mode 100644 index 863fc4d74b13..000000000000 --- a/dom/html/htmlMenuBuilder.js +++ /dev/null @@ -1,132 +0,0 @@ -/* 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/. */ - -// This component is used to build the menus for the HTML contextmenu attribute. - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); - -const Cc = Components.classes; -const Ci = Components.interfaces; - -// A global value that is used to identify each menu item. It is -// incremented with each one that is found. -var gGeneratedId = 1; - -function HTMLMenuBuilder() { - this.currentNode = null; - this.root = null; - this.items = {}; - this.nestedStack = []; -}; - -// Building is done in two steps: -// The first generates a hierarchical JS object that contains the menu structure. -// This object is returned by toJSONString. -// -// The second step can take this structure and generate a XUL menu hierarchy or -// other UI from this object. The default UI is done in PageMenu.jsm. -// -// When a multi-process browser is used, the first step is performed by the child -// process and the second step is performed by the parent process. - -HTMLMenuBuilder.prototype = -{ - classID: Components.ID("{51c65f5d-0de5-4edc-9058-60e50cef77f8}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIMenuBuilder]), - - currentNode: null, - root: null, - items: {}, - nestedStack: [], - - toJSONString: function() { - return JSON.stringify(this.root); - }, - - openContainer: function(aLabel) { - if (!this.currentNode) { - this.root = { - type: "menu", - children: [] - }; - this.currentNode = this.root; - } - else { - let parent = this.currentNode; - this.currentNode = { - type: "menu", - label: aLabel, - children: [] - }; - parent.children.push(this.currentNode); - this.nestedStack.push(parent); - } - }, - - addItemFor: function(aElement, aCanLoadIcon) { - if (!("children" in this.currentNode)) { - return; - } - - let item = { - type: "menuitem", - label: aElement.label - }; - - let elementType = aElement.type; - if (elementType == "checkbox" || elementType == "radio") { - item.checkbox = true; - - if (aElement.checked) { - item.checked = true; - } - } - - let icon = aElement.icon; - if (icon.length > 0 && aCanLoadIcon) { - item.icon = icon; - } - - if (aElement.disabled) { - item.disabled = true; - } - - item.id = gGeneratedId++; - this.currentNode.children.push(item); - - this.items[item.id] = aElement; - }, - - addSeparator: function() { - if (!("children" in this.currentNode)) { - return; - } - - this.currentNode.children.push({ type: "separator"}); - }, - - undoAddSeparator: function() { - if (!("children" in this.currentNode)) { - return; - } - - let children = this.currentNode.children; - if (children.length && children[children.length - 1].type == "separator") { - children.pop(); - } - }, - - closeContainer: function() { - this.currentNode = this.nestedStack.length ? this.nestedStack.pop() : this.root; - }, - - click: function(id) { - let item = this.items[id]; - if (item) { - item.click(); - } - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HTMLMenuBuilder]); diff --git a/dom/html/htmlMenuBuilder.manifest b/dom/html/htmlMenuBuilder.manifest deleted file mode 100644 index b245f8fe2de5..000000000000 --- a/dom/html/htmlMenuBuilder.manifest +++ /dev/null @@ -1,3 +0,0 @@ -component {51c65f5d-0de5-4edc-9058-60e50cef77f8} htmlMenuBuilder.js -contract @mozilla.org/content/html-menu-builder;1 {51c65f5d-0de5-4edc-9058-60e50cef77f8} - diff --git a/dom/html/moz.build b/dom/html/moz.build index 97f6d1799026..cd725e70d2a4 100644 --- a/dom/html/moz.build +++ b/dom/html/moz.build @@ -215,11 +215,6 @@ SOURCES += [ 'PluginDocument.cpp', ] -EXTRA_COMPONENTS += [ - 'htmlMenuBuilder.js', - 'htmlMenuBuilder.manifest' -] - FAIL_ON_WARNINGS = True MSVC_ENABLE_PGO = True diff --git a/dom/html/nsIMenuBuilder.idl b/dom/html/nsIMenuBuilder.idl index 02664480fa46..a925fbcb709e 100644 --- a/dom/html/nsIMenuBuilder.idl +++ b/dom/html/nsIMenuBuilder.idl @@ -11,7 +11,7 @@ interface nsIDOMHTMLMenuItemElement; * An interface used to construct native toolbar or context menus from */ -[scriptable, uuid(93F4A48F-D043-4F45-97FD-9771EA1AF976)] +[scriptable, uuid(12724737-f7db-43b4-94ab-708a7b86e115)] interface nsIMenuBuilder : nsISupports { @@ -49,28 +49,4 @@ interface nsIMenuBuilder : nsISupports */ void closeContainer(); - /** - * Returns a JSON string representing the menu hierarchy. For a context menu, - * it will be of the form: - * { - * type: "menu", - * children: [ - * { - * type: "menuitem", - * label: "label", - * icon: "image.png" - * }, - * { - * type: "separator", - * }, - * ]; - */ - AString toJSONString(); - - /** - * Invoke the action of the menuitem with assigned id aGeneratedItemId. - * - * @param aGeneratedItemId the menuitem id - */ - void click(in DOMString aGeneratedItemId); }; diff --git a/dom/webidl/HTMLMenuElement.webidl b/dom/webidl/HTMLMenuElement.webidl index ff81a7c80d23..5ee2e66e3790 100644 --- a/dom/webidl/HTMLMenuElement.webidl +++ b/dom/webidl/HTMLMenuElement.webidl @@ -40,11 +40,11 @@ partial interface HTMLMenuElement { /** * Creates a native menu builder. The builder type is dependent on menu type. - * Currently, it returns the @mozilla.org/content/html-menu-builder;1 - * component. Toolbar menus are not yet supported (the method returns null). + * Currently, it returns nsXULContextMenuBuilder for context menus. + * Toolbar menus are not yet supported (the method returns null). */ [ChromeOnly] - MenuBuilder? createBuilder(); + MenuBuilder createBuilder(); /* * Builds a menu by iterating over menu children. diff --git a/dom/xul/moz.build b/dom/xul/moz.build index a316ca9397ec..62315cd7cfc5 100644 --- a/dom/xul/moz.build +++ b/dom/xul/moz.build @@ -12,6 +12,7 @@ if CONFIG['MOZ_XUL']: DIRS += ['templates'] XPIDL_SOURCES += [ + 'nsIXULContextMenuBuilder.idl', 'nsIXULOverlayProvider.idl', ] @@ -22,6 +23,7 @@ if CONFIG['MOZ_XUL']: UNIFIED_SOURCES += [ 'nsXULCommandDispatcher.cpp', 'nsXULContentSink.cpp', + 'nsXULContextMenuBuilder.cpp', 'nsXULElement.cpp', 'nsXULPopupListener.cpp', 'nsXULPrototypeCache.cpp', diff --git a/dom/xul/nsIXULContextMenuBuilder.idl b/dom/xul/nsIXULContextMenuBuilder.idl new file mode 100644 index 000000000000..1f5070393f6f --- /dev/null +++ b/dom/xul/nsIXULContextMenuBuilder.idl @@ -0,0 +1,38 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsISupports.idl" + +interface nsIDOMDocumentFragment; + +/** + * An interface for initialization of XUL context menu builder + * and for triggering of menuitem actions with assigned identifiers. + */ + +[scriptable, uuid(eb6b42c0-2f1c-4760-b5ca-bdc9b3ec77d4)] +interface nsIXULContextMenuBuilder : nsISupports +{ + + /** + * Initialize builder before building. + * + * @param aDocumentFragment the fragment that will be used to append top + * level elements + * + * @param aGeneratedItemIdAttrName the name of the attribute that will be + * used to mark elements as generated and for menuitem identification + */ + void init(in nsIDOMDocumentFragment aDocumentFragment, + in AString aGeneratedItemIdAttrName); + + /** + * Invoke the action of the menuitem with assigned id aGeneratedItemId. + * + * @param aGeneratedItemId the menuitem id + */ + void click(in DOMString aGeneratedItemId); + +}; diff --git a/dom/xul/nsXULContextMenuBuilder.cpp b/dom/xul/nsXULContextMenuBuilder.cpp new file mode 100644 index 000000000000..e6d9d5602c9e --- /dev/null +++ b/dom/xul/nsXULContextMenuBuilder.cpp @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsContentCreatorFunctions.h" +#include "nsIContent.h" +#include "nsIDOMDocumentFragment.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMHTMLMenuItemElement.h" +#include "nsXULContextMenuBuilder.h" +#include "nsIDocument.h" +#include "mozilla/dom/Element.h" + +using namespace mozilla; +using namespace mozilla::dom; + +nsXULContextMenuBuilder::nsXULContextMenuBuilder() + : mCurrentGeneratedItemId(0) +{ +} + +nsXULContextMenuBuilder::~nsXULContextMenuBuilder() +{ +} + +NS_IMPL_CYCLE_COLLECTION(nsXULContextMenuBuilder, mFragment, mDocument, + mCurrentNode, mElements) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULContextMenuBuilder) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULContextMenuBuilder) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULContextMenuBuilder) + NS_INTERFACE_MAP_ENTRY(nsIMenuBuilder) + NS_INTERFACE_MAP_ENTRY(nsIXULContextMenuBuilder) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMenuBuilder) +NS_INTERFACE_MAP_END + + +NS_IMETHODIMP +nsXULContextMenuBuilder::OpenContainer(const nsAString& aLabel) +{ + if (!mFragment) { + return NS_ERROR_NOT_INITIALIZED; + } + + if (!mCurrentNode) { + mCurrentNode = mFragment; + } else { + nsCOMPtr menu; + nsresult rv = CreateElement(nsGkAtoms::menu, nullptr, getter_AddRefs(menu)); + NS_ENSURE_SUCCESS(rv, rv); + + menu->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aLabel, false); + + nsCOMPtr menuPopup; + rv = CreateElement(nsGkAtoms::menupopup, nullptr, + getter_AddRefs(menuPopup)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = menu->AppendChildTo(menuPopup, false); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mCurrentNode->AppendChildTo(menu, false); + NS_ENSURE_SUCCESS(rv, rv); + + mCurrentNode = menuPopup; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXULContextMenuBuilder::AddItemFor(nsIDOMHTMLMenuItemElement* aElement, + bool aCanLoadIcon) +{ + if (!mFragment) { + return NS_ERROR_NOT_INITIALIZED; + } + + nsCOMPtr menuitem; + nsCOMPtr element = do_QueryInterface(aElement); + nsresult rv = CreateElement(nsGkAtoms::menuitem, element, + getter_AddRefs(menuitem)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString type; + aElement->GetType(type); + if (type.EqualsLiteral("checkbox") || type.EqualsLiteral("radio")) { + // The menu is only temporary, so we don't need to handle + // the radio type precisely. + menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::type, + NS_LITERAL_STRING("checkbox"), false); + bool checked; + aElement->GetChecked(&checked); + if (checked) { + menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, + NS_LITERAL_STRING("true"), false); + } + } + + nsAutoString label; + aElement->GetLabel(label); + menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::label, label, false); + + nsAutoString icon; + aElement->GetIcon(icon); + if (!icon.IsEmpty()) { + menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, + NS_LITERAL_STRING("menuitem-iconic"), false); + if (aCanLoadIcon) { + menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::image, icon, false); + } + } + + bool disabled; + aElement->GetDisabled(&disabled); + if (disabled) { + menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, + NS_LITERAL_STRING("true"), false); + } + + return mCurrentNode->AppendChildTo(menuitem, false); +} + +NS_IMETHODIMP +nsXULContextMenuBuilder::AddSeparator() +{ + if (!mFragment) { + return NS_ERROR_NOT_INITIALIZED; + } + + nsCOMPtr menuseparator; + nsresult rv = CreateElement(nsGkAtoms::menuseparator, nullptr, + getter_AddRefs(menuseparator)); + NS_ENSURE_SUCCESS(rv, rv); + + return mCurrentNode->AppendChildTo(menuseparator, false); +} + +NS_IMETHODIMP +nsXULContextMenuBuilder::UndoAddSeparator() +{ + if (!mFragment) { + return NS_ERROR_NOT_INITIALIZED; + } + + uint32_t count = mCurrentNode->GetChildCount(); + if (!count || + mCurrentNode->GetChildAt(count - 1)->Tag() != nsGkAtoms::menuseparator) { + return NS_OK; + } + + mCurrentNode->RemoveChildAt(count - 1, false); + return NS_OK; +} + +NS_IMETHODIMP +nsXULContextMenuBuilder::CloseContainer() +{ + if (!mFragment) { + return NS_ERROR_NOT_INITIALIZED; + } + + if (mCurrentNode == mFragment) { + mCurrentNode = nullptr; + } else { + nsIContent* parent = mCurrentNode->GetParent(); + mCurrentNode = parent->GetParent(); + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsXULContextMenuBuilder::Init(nsIDOMDocumentFragment* aDocumentFragment, + const nsAString& aGeneratedItemIdAttrName) +{ + NS_ENSURE_ARG_POINTER(aDocumentFragment); + + mFragment = do_QueryInterface(aDocumentFragment); + mDocument = mFragment->GetOwnerDocument(); + mGeneratedItemIdAttr = do_GetAtom(aGeneratedItemIdAttrName); + + return NS_OK; +} + +NS_IMETHODIMP +nsXULContextMenuBuilder::Click(const nsAString& aGeneratedItemId) +{ + nsresult rv; + int32_t idx = nsString(aGeneratedItemId).ToInteger(&rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr element = mElements.SafeObjectAt(idx); + if (element) { + element->DOMClick(); + } + } + + return NS_OK; +} + +nsresult +nsXULContextMenuBuilder::CreateElement(nsIAtom* aTag, + nsIDOMHTMLElement* aHTMLElement, + Element** aResult) +{ + *aResult = nullptr; + + nsRefPtr nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo( + aTag, nullptr, kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE); + + nsresult rv = NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER); + if (NS_FAILED(rv)) { + return rv; + } + + nsAutoString generateditemid; + + if (aHTMLElement) { + mElements.AppendObject(aHTMLElement); + generateditemid.AppendInt(mCurrentGeneratedItemId++); + } + + (*aResult)->SetAttr(kNameSpaceID_None, mGeneratedItemIdAttr, generateditemid, + false); + + return NS_OK; +} diff --git a/dom/xul/nsXULContextMenuBuilder.h b/dom/xul/nsXULContextMenuBuilder.h new file mode 100644 index 000000000000..83e19cb99dab --- /dev/null +++ b/dom/xul/nsXULContextMenuBuilder.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsIMenuBuilder.h" +#include "nsIXULContextMenuBuilder.h" +#include "nsCycleCollectionParticipant.h" + +class nsIAtom; +class nsIContent; +class nsIDocument; +class nsIDOMHTMLElement; + +namespace mozilla { +namespace dom { +class Element; +} // namespace dom +} // namespace mozilla + +class nsXULContextMenuBuilder : public nsIMenuBuilder, + public nsIXULContextMenuBuilder +{ +public: + nsXULContextMenuBuilder(); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULContextMenuBuilder, + nsIMenuBuilder) + NS_DECL_NSIMENUBUILDER + + NS_DECL_NSIXULCONTEXTMENUBUILDER + +protected: + virtual ~nsXULContextMenuBuilder(); + + nsresult CreateElement(nsIAtom* aTag, + nsIDOMHTMLElement* aHTMLElement, + mozilla::dom::Element** aResult); + + nsCOMPtr mFragment; + nsCOMPtr mDocument; + nsCOMPtr mGeneratedItemIdAttr; + + nsCOMPtr mCurrentNode; + int32_t mCurrentGeneratedItemId; + + nsCOMArray mElements; +}; diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index ec9eb81e8a74..bccdc4c56b66 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -408,8 +408,6 @@ @BINPATH@/components/Webapps.manifest @BINPATH@/components/AppsService.js @BINPATH@/components/AppsService.manifest -@RESPATH@/components/htmlMenuBuilder.js -@RESPATH@/components/htmlMenuBuilder.manifest @BINPATH@/components/Activities.manifest @BINPATH@/components/ActivitiesGlue.js diff --git a/toolkit/modules/PageMenu.jsm b/toolkit/modules/PageMenu.jsm index d36120b6b0fe..7d5823f8557b 100644 --- a/toolkit/modules/PageMenu.jsm +++ b/toolkit/modules/PageMenu.jsm @@ -2,7 +2,7 @@ * 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/. */ -this.EXPORTED_SYMBOLS = ["PageMenuParent", "PageMenuChild"]; +this.EXPORTED_SYMBOLS = ["PageMenu"]; this.PageMenu = function PageMenu() { } @@ -11,71 +11,46 @@ PageMenu.prototype = { PAGEMENU_ATTR: "pagemenu", GENERATEDITEMID_ATTR: "generateditemid", - _popup: null, + popup: null, + builder: null, - // Only one of builder or browser will end up getting set. - _builder: null, - _browser: null, - - // Given a target node, get the context menu for it or its ancestor. - getContextMenu: function(aTarget) { - let pageMenu = null; - let target = aTarget; + maybeBuildAndAttachMenu: function(aTarget, aPopup) { + var pageMenu = null; + var target = aTarget; while (target) { - let contextMenu = target.contextMenu; + var contextMenu = target.contextMenu; if (contextMenu) { - return contextMenu; + pageMenu = contextMenu; + break; } target = target.parentNode; } - return null; - }, - - // Given a target node, generate a JSON object for any context menu - // associated with it, or null if there is no context menu. - maybeBuild: function(aTarget) { - let pageMenu = this.getContextMenu(aTarget); if (!pageMenu) { - return null; + return false; + } + + var insertionPoint = this.getInsertionPoint(aPopup); + if (!insertionPoint) { + return false; } pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu); pageMenu.sendShowEvent(); // the show event is not cancelable, so no need to check a result here - this._builder = pageMenu.createBuilder(); - if (!this._builder) { - return null; - } + var fragment = aPopup.ownerDocument.createDocumentFragment(); - pageMenu.build(this._builder); - - // This serializes then parses again, however this could be avoided in - // the single-process case with further improvement. - let menuString = this._builder.toJSONString(); - if (!menuString) { - return null; - } - - return JSON.parse(menuString); - }, - - // Given a JSON menu object and popup, add the context menu to the popup. - buildAndAttachMenuWithObject: function(aMenu, aBrowser, aPopup) { - if (!aMenu) { + var builder = pageMenu.createBuilder(); + if (!builder) { return false; } + builder.QueryInterface(Components.interfaces.nsIXULContextMenuBuilder); + builder.init(fragment, this.GENERATEDITEMID_ATTR); - let insertionPoint = this.getInsertionPoint(aPopup); - if (!insertionPoint) { - return false; - } + pageMenu.build(builder); - let fragment = aPopup.ownerDocument.createDocumentFragment(); - this.buildXULMenu(aMenu, fragment); - - let pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR); + var pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR); if (pos == "start") { insertionPoint.insertBefore(fragment, insertionPoint.firstChild); @@ -85,101 +60,33 @@ PageMenu.prototype = { insertionPoint.appendChild(fragment); } - this._browser = aBrowser; - this._popup = aPopup; + this.builder = builder; + this.popup = aPopup; - this._popup.addEventListener("command", this); - this._popup.addEventListener("popuphidden", this); + this.popup.addEventListener("command", this); + this.popup.addEventListener("popuphidden", this); return true; }, - // Construct the XUL menu structure for a given JSON object. - buildXULMenu: function(aNode, aElementForAppending) { - let document = aElementForAppending.ownerDocument; - - let children = aNode.children; - for (let child of children) { - let menuitem; - switch (child.type) { - case "menuitem": - if (!child.id) { - continue; // Ignore children without ids - } - - menuitem = document.createElement("menuitem"); - if (child.checkbox) { - menuitem.setAttribute("type", "checkbox"); - if (child.checked) { - menuitem.setAttribute("checked", "true"); - } - } - - if (child.label) { - menuitem.setAttribute("label", child.label); - } - if (child.icon) { - menuitem.setAttribute("image", child.icon); - menuitem.className = "menuitem-iconic"; - } - if (child.disabled) { - menuitem.setAttribute("disabled", true); - } - - break; - - case "separator": - menuitem = document.createElement("menuseparator"); - break; - - case "menu": - menuitem = document.createElement("menu"); - if (child.label) { - menuitem.setAttribute("label", child.label); - } - - let menupopup = document.createElement("menupopup"); - menuitem.appendChild(menupopup); - - this.buildXULMenu(child, menupopup); - break; - } - - menuitem.setAttribute(this.GENERATEDITEMID_ATTR, child.id ? child.id : 0); - aElementForAppending.appendChild(menuitem); - } - }, - - // Called when the generated menuitem is executed. handleEvent: function(event) { - let type = event.type; - let target = event.target; + var type = event.type; + var target = event.target; if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) { - // If a builder is assigned, call click on it directly. Otherwise, this is - // likely a menu with data from another process, so send a message to the - // browser to execute the menuitem. - if (this._builder) { - this._builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR)); - } - else if (this._browser) { - this._browser.messageManager.sendAsyncMessage("ContextMenu:DoCustomCommand", - target.getAttribute(this.GENERATEDITEMID_ATTR)); - } - } else if (type == "popuphidden" && this._popup == target) { - this.removeGeneratedContent(this._popup); + this.builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR)); + } else if (type == "popuphidden" && this.popup == target) { + this.removeGeneratedContent(this.popup); - this._popup.removeEventListener("popuphidden", this); - this._popup.removeEventListener("command", this); + this.popup.removeEventListener("popuphidden", this); + this.popup.removeEventListener("command", this); - this._popup = null; - this._builder = null; - this._browser = null; + this.popup = null; + this.builder = null; } }, - // Get the first child of the given element with the given tag name. getImmediateChild: function(element, tag) { - let child = element.firstChild; + var child = element.firstChild; while (child) { if (child.localName == tag) { return child; @@ -189,19 +96,16 @@ PageMenu.prototype = { return null; }, - // Return the location where the generated items should be inserted into the - // given popup. They should be inserted as the next sibling of the returned - // element. getInsertionPoint: function(aPopup) { if (aPopup.hasAttribute(this.PAGEMENU_ATTR)) return aPopup; - let element = aPopup.firstChild; + var element = aPopup.firstChild; while (element) { if (element.localName == "menu") { - let popup = this.getImmediateChild(element, "menupopup"); + var popup = this.getImmediateChild(element, "menupopup"); if (popup) { - let result = this.getInsertionPoint(popup); + var result = this.getInsertionPoint(popup); if (result) { return result; } @@ -213,20 +117,19 @@ PageMenu.prototype = { return null; }, - // Remove the generated content from the given popup. removeGeneratedContent: function(aPopup) { - let ungenerated = []; + var ungenerated = []; ungenerated.push(aPopup); - let count; + var count; while (0 != (count = ungenerated.length)) { - let last = count - 1; - let element = ungenerated[last]; + var last = count - 1; + var element = ungenerated[last]; ungenerated.splice(last, 1); - let i = element.childNodes.length; + var i = element.childNodes.length; while (i-- > 0) { - let child = element.childNodes[i]; + var child = element.childNodes[i]; if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) { ungenerated.push(child); continue; @@ -236,78 +139,3 @@ PageMenu.prototype = { } } } - -// This object is expected to be used from a parent process. -this.PageMenuParent = function PageMenuParent() { -} - -PageMenuParent.prototype = { - __proto__ : PageMenu.prototype, - - /* - * Given a target node and popup, add the context menu to the popup. This is - * intended to be called when a single process is used. This is equivalent to - * calling PageMenuChild.build and PageMenuParent.addToPopup in sequence. - * - * Returns true if custom menu items were present. - */ - buildAndAddToPopup: function(aTarget, aPopup) { - let menuObject = this.maybeBuild(aTarget); - if (!menuObject) { - return false; - } - - return this.buildAndAttachMenuWithObject(menuObject, null, aPopup); - }, - - /* - * Given a JSON menu object and popup, add the context menu to the popup. This - * is intended to be called when the child page is in a different process. - * aBrowser should be the browser containing the page the context menu is - * displayed for, which may be null. - * - * Returns true if custom menu items were present. - */ - addToPopup: function(aMenu, aBrowser, aPopup) { - return this.buildAndAttachMenuWithObject(aMenu, aBrowser, aPopup); - } -} - -// This object is expected to be used from a child process. -this.PageMenuChild = function PageMenuChild() { -} - -PageMenuChild.prototype = { - __proto__ : PageMenu.prototype, - - /* - * Given a target node, return a JSON object for the custom menu commands. The - * object will consist of a hierarchical structure of menus, menuitems or - * separators. Supported properties of each are: - * Menu: children, label, type="menu" - * Menuitems: checkbox, checked, disabled, icon, label, type="menuitem" - * Separators: type="separator" - * - * In addition, the id of each item will be used to identify the item - * when it is executed. The type will either be 'menu', 'menuitem' or - * 'separator'. The toplevel node will be a menu with a children property. The - * children property of a menu is an array of zero or more other items. - * - * If there is no menu associated with aTarget, null will be returned. - */ - build: function(aTarget) { - return this.maybeBuild(aTarget); - }, - - /* - * Given the id of a menu, execute the command associated with that menu. It - * is assumed that only one command will be executed so the builder is - * cleared afterwards. - */ - executeMenu: function(aId) { - if (this._builder) { - this._builder.click(aId); - this._builder = null; - } - } -} From 69fa19c8705a3829f158a808175b56ed421e1985 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Mon, 22 Dec 2014 14:53:52 +0100 Subject: [PATCH 05/64] Backed out changeset 458cfe948a05 (bug 1107328) for js test failures on a CLOSED TREE --- js/src/jit/EffectiveAddressAnalysis.cpp | 12 +- js/src/jit/IonAnalysis.cpp | 14 +- js/src/jit/IonBuilder.cpp | 29 ++-- js/src/jit/Lowering.cpp | 12 +- js/src/jit/MCallOptimize.cpp | 34 ++--- js/src/jit/MIR.cpp | 167 +++++++++--------------- js/src/jit/MIR.h | 7 - js/src/jit/RangeAnalysis.cpp | 38 +++--- js/src/jit/ScalarReplacement.cpp | 6 +- js/src/jit/arm/Lowering-arm.cpp | 12 +- js/src/jit/mips/Lowering-mips.cpp | 12 +- 11 files changed, 149 insertions(+), 194 deletions(-) diff --git a/js/src/jit/EffectiveAddressAnalysis.cpp b/js/src/jit/EffectiveAddressAnalysis.cpp index 04552edcea9e..34559a3620bf 100644 --- a/js/src/jit/EffectiveAddressAnalysis.cpp +++ b/js/src/jit/EffectiveAddressAnalysis.cpp @@ -21,10 +21,10 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MOZ_ASSERT(index->type() == MIRType_Int32); MDefinition *shift = lsh->rhs(); - if (!shift->isConstantValue()) + if (!shift->isConstant()) return; - Value shiftValue = shift->constantValue(); + Value shiftValue = shift->toConstant()->value(); if (!shiftValue.isInt32() || !IsShiftInScaleRange(shiftValue.toInt32())) return; @@ -47,8 +47,8 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MDefinition *other = add->getOperand(1 - add->indexOf(*use)); - if (other->isConstantValue()) { - displacement += other->constantValue().toInt32(); + if (other->isConstant()) { + displacement += other->toConstant()->value().toInt32(); } else { if (base) break; @@ -72,11 +72,11 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) MBitAnd *bitAnd = use->consumer()->toDefinition()->toBitAnd(); MDefinition *other = bitAnd->getOperand(1 - bitAnd->indexOf(*use)); - if (!other->isConstantValue() || !other->constantValue().isInt32()) + if (!other->isConstant() || !other->toConstant()->value().isInt32()) return; uint32_t bitsClearedByShift = elemSize - 1; - uint32_t bitsClearedByMask = ~uint32_t(other->constantValue().toInt32()); + uint32_t bitsClearedByMask = ~uint32_t(other->toConstant()->value().toInt32()); if ((bitsClearedByShift & bitsClearedByMask) != bitsClearedByMask) return; diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 3a8caf552756..a19b39d5d84c 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -260,7 +260,7 @@ MaybeFoldConditionBlock(MIRGraph &graph, MBasicBlock *initialBlock) MBasicBlock *trueTarget = trueBranch; if (BlockComputesConstant(trueBranch, trueResult)) { - trueTarget = trueResult->constantToBoolean() + trueTarget = trueResult->toConstant()->valueToBoolean() ? finalTest->ifTrue() : finalTest->ifFalse(); testBlock->removePredecessor(trueBranch); @@ -272,7 +272,7 @@ MaybeFoldConditionBlock(MIRGraph &graph, MBasicBlock *initialBlock) MBasicBlock *falseTarget = falseBranch; if (BlockComputesConstant(falseBranch, falseResult)) { - falseTarget = falseResult->constantToBoolean() + falseTarget = falseResult->toConstant()->valueToBoolean() ? finalTest->ifTrue() : finalTest->ifFalse(); testBlock->removePredecessor(falseBranch); @@ -2270,8 +2270,8 @@ jit::ExtractLinearSum(MDefinition *ins) if (ins->type() != MIRType_Int32) return SimpleLinearSum(ins, 0); - if (ins->isConstantValue()) { - const Value &v = ins->constantValue(); + if (ins->isConstant()) { + const Value &v = ins->toConstant()->value(); MOZ_ASSERT(v.isInt32()); return SimpleLinearSum(nullptr, v.toInt32()); } else if (ins->isAdd() || ins->isSub()) { @@ -2672,8 +2672,8 @@ LinearSum::add(MDefinition *term, int32_t scale) if (scale == 0) return true; - if (term->isConstantValue()) { - int32_t constant = term->constantValue().toInt32(); + if (term->isConstant()) { + int32_t constant = term->toConstant()->value().toInt32(); if (!SafeMul(constant, scale, &constant)) return false; return add(constant); @@ -2751,7 +2751,7 @@ jit::ConvertLinearSum(TempAllocator &alloc, MBasicBlock *block, const LinearSum for (size_t i = 0; i < sum.numTerms(); i++) { LinearTerm term = sum.term(i); - MOZ_ASSERT(!term.term->isConstantValue()); + MOZ_ASSERT(!term.term->isConstant()); if (term.scale == 1) { if (def) { def = MAdd::New(alloc, def, term.term); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 7be54d2071f5..af82e4fec42f 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -2261,8 +2261,9 @@ IonBuilder::processDoWhileCondEnd(CFGState &state) return ControlStatus_Error; // Test for do {} while(false) and don't create a loop in that case. - if (vins->isConstantValue() && !vins->constantValue().isMagic()) { - if (!vins->constantToBoolean()) { + if (vins->isConstant()) { + MConstant *cte = vins->toConstant(); + if (cte->value().isBoolean() && !cte->value().toBoolean()) { current->end(MGoto::New(alloc(), successor)); current = nullptr; @@ -4567,7 +4568,7 @@ IonBuilder::makeInliningDecision(JSObject *targetArg, CallInfo &callInfo) bool hasOpportunities = false; for (size_t i = 0, e = callInfo.argv().length(); !hasOpportunities && i < e; i++) { MDefinition *arg = callInfo.argv()[i]; - hasOpportunities = arg->isLambda() || arg->isConstantValue(); + hasOpportunities = arg->isLambda() || arg->isConstant(); } if (!hasOpportunities) @@ -5929,10 +5930,10 @@ IonBuilder::jsop_eval(uint32_t argc) // name on the scope chain and the eval is performing a call on that // value. Use a dynamic scope chain lookup rather than a full eval. if (string->isConcat() && - string->getOperand(1)->isConstantValue() && - string->getOperand(1)->constantValue().isString()) + string->getOperand(1)->isConstant() && + string->getOperand(1)->toConstant()->value().isString()) { - JSAtom *atom = &string->getOperand(1)->constantValue().toString()->asAtom(); + JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom(); if (StringEqualsAscii(atom, "()")) { MDefinition *name = string->getOperand(0); @@ -7845,10 +7846,10 @@ IonBuilder::getElemTryArgumentsInlined(bool *emitted, MDefinition *obj, MDefinit MOZ_ASSERT(!info().argsObjAliasesFormals()); // When the id is constant, we can just return the corresponding inlined argument - if (index->isConstantValue() && index->constantValue().isInt32()) { + if (index->isConstant() && index->toConstant()->value().isInt32()) { MOZ_ASSERT(inliningDepth_ > 0); - int32_t id = index->constantValue().toInt32(); + int32_t id = index->toConstant()->value().toInt32(); index->setImplicitlyUsedUnchecked(); if (id < (int32_t)inlineCallInfo_->argc() && id >= 0) @@ -8064,8 +8065,8 @@ IonBuilder::addTypedArrayLengthAndData(MDefinition *obj, MOZ_ASSERT((index != nullptr) == (elements != nullptr)); JSObject *tarr = nullptr; - if (obj->isConstantValue() && obj->constantValue().isObject()) - tarr = &obj->constantValue().toObject(); + if (obj->isConstant() && obj->toConstant()->value().isObject()) + tarr = &obj->toConstant()->value().toObject(); else if (obj->resultTypeSet()) tarr = obj->resultTypeSet()->getSingleton(); @@ -8122,8 +8123,8 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id, // If the index is an already shifted constant, undo the shift to get the // absolute offset being accessed. - if (id->isConstantValue() && id->constantValue().isInt32()) { - int32_t index = id->constantValue().toInt32(); + if (id->isConstant() && id->toConstant()->value().isInt32()) { + int32_t index = id->toConstant()->value().toInt32(); MConstant *offset = MConstant::New(alloc(), Int32Value(index << TypedArrayShift(viewType))); current->add(offset); return offset; @@ -8131,9 +8132,9 @@ IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition *id, if (!id->isRsh() || id->isEffectful()) return nullptr; - if (!id->getOperand(1)->isConstantValue()) + if (!id->getOperand(1)->isConstant()) return nullptr; - const Value &value = id->getOperand(1)->constantValue(); + const Value &value = id->getOperand(1)->toConstant()->value(); if (!value.isInt32() || uint32_t(value.toInt32()) != TypedArrayShift(viewType)) return nullptr; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 96d7179ea46a..1d724cf4fc9b 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -623,7 +623,7 @@ ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp) MDefinition *lhs = *lhsp; MDefinition *rhs = *rhsp; - if (lhs->isConstantValue()) { + if (lhs->isConstant()) { *rhsp = lhs; *lhsp = rhs; return ReverseCompareOp(op); @@ -643,8 +643,8 @@ LIRGenerator::visitTest(MTest *test) MOZ_ASSERT(opd->type() != MIRType_String); // Testing a constant. - if (opd->isConstantValue() && !opd->constantValue().isMagic()) { - bool result = opd->constantToBoolean(); + if (opd->isConstant()) { + bool result = opd->toConstant()->valueToBoolean(); add(new(alloc()) LGoto(result ? ifTrue : ifFalse)); return; } @@ -1491,7 +1491,7 @@ LIRGenerator::visitMul(MMul *ins) // If our RHS is a constant -1 and we don't have to worry about // overflow, we can optimize to an LNegI. - if (!ins->fallible() && rhs->isConstantValue() && rhs->constantValue() == Int32Value(-1)) + if (!ins->fallible() && rhs->isConstant() && rhs->toConstant()->value() == Int32Value(-1)) defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(lhs)), ins, 0); else lowerMulI(ins, lhs, rhs); @@ -1500,7 +1500,7 @@ LIRGenerator::visitMul(MMul *ins) ReorderCommutative(&lhs, &rhs, ins); // If our RHS is a constant -1.0, we can optimize to an LNegD. - if (rhs->isConstantValue() && rhs->constantValue() == DoubleValue(-1.0)) + if (rhs->isConstant() && rhs->toConstant()->value() == DoubleValue(-1.0)) defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0); else lowerForFPU(new(alloc()) LMathD(JSOP_MUL), ins, lhs, rhs); @@ -1509,7 +1509,7 @@ LIRGenerator::visitMul(MMul *ins) ReorderCommutative(&lhs, &rhs, ins); // We apply the same optimizations as for doubles - if (rhs->isConstantValue() && rhs->constantValue() == Float32Value(-1.0f)) + if (rhs->isConstant() && rhs->toConstant()->value() == Float32Value(-1.0f)) defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0); else lowerForFPU(new(alloc()) LMathF(JSOP_MUL), ins, lhs, rhs); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 73d2413b7b78..c422f9a07a0a 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -378,7 +378,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) return InliningStatus_NotInlined; MDefinition *arg = callInfo.getArg(0); - if (!arg->isConstantValue()) { + if (!arg->isConstant()) { callInfo.setImplicitlyUsedUnchecked(); ArrayObject *templateArray = &templateObject->as(); MNewArrayDynamicLength *ins = @@ -391,7 +391,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) } // Negative lengths generate a RangeError, unhandled by the inline path. - initLength = arg->constantValue().toInt32(); + initLength = arg->toConstant()->value().toInt32(); if (initLength >= NativeObject::NELEMENTS_LIMIT) return InliningStatus_NotInlined; @@ -1038,10 +1038,10 @@ IonBuilder::inlineMathPow(CallInfo &callInfo) MDefinition *output = nullptr; // Optimize some constant powers. - if (callInfo.getArg(1)->isConstantValue() && - callInfo.getArg(1)->constantValue().isNumber()) + if (callInfo.getArg(1)->isConstant() && + callInfo.getArg(1)->toConstant()->value().isNumber()) { - double pow = callInfo.getArg(1)->constantValue().toNumber(); + double pow = callInfo.getArg(1)->toConstant()->value().toNumber(); // Math.pow(x, 0.5) is a sqrt with edge-case detection. if (pow == 0.5) { @@ -1216,8 +1216,8 @@ IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max) case MIRType_Float32: // Don't force a double MMinMax for arguments that would be a NOP // when doing an integer MMinMax. - if (arg->isConstantValue()) { - double cte = arg->constantValue().toDouble(); + if (arg->isConstant()) { + double cte = arg->toConstant()->value().toDouble(); // min(int32, cte >= INT32_MAX) = int32 if (cte >= INT32_MAX && !max) break; @@ -1368,14 +1368,14 @@ IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo) IonBuilder::InliningStatus IonBuilder::inlineConstantCharCodeAt(CallInfo &callInfo) { - if (!callInfo.thisArg()->isConstantValue()) + if (!callInfo.thisArg()->isConstant()) return InliningStatus_NotInlined; - if (!callInfo.getArg(0)->isConstantValue()) + if (!callInfo.getArg(0)->isConstant()) return InliningStatus_NotInlined; - const js::Value *strval = callInfo.thisArg()->constantVp(); - const js::Value *idxval = callInfo.getArg(0)->constantVp(); + const js::Value *strval = callInfo.thisArg()->toConstant()->vp(); + const js::Value *idxval = callInfo.getArg(0)->toConstant()->vp(); if (!strval->isString() || !idxval->isInt32()) return InliningStatus_NotInlined; @@ -2033,9 +2033,9 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo) // Don't inline if we don't have a constant slot. MDefinition *arg = callInfo.getArg(1); - if (!arg->isConstantValue()) + if (!arg->isConstant()) return InliningStatus_NotInlined; - uint32_t slot = arg->constantValue().toPrivateUint32(); + uint32_t slot = arg->toConstant()->value().toPrivateUint32(); callInfo.setImplicitlyUsedUnchecked(); @@ -2061,9 +2061,9 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo) // Don't inline if we don't have a constant slot. MDefinition *arg = callInfo.getArg(1); - if (!arg->isConstantValue()) + if (!arg->isConstant()) return InliningStatus_NotInlined; - uint32_t slot = arg->constantValue().toPrivateUint32(); + uint32_t slot = arg->toConstant()->value().toPrivateUint32(); callInfo.setImplicitlyUsedUnchecked(); @@ -2259,9 +2259,9 @@ IonBuilder::inlineAssertFloat32(CallInfo &callInfo) MDefinition *secondArg = callInfo.getArg(1); MOZ_ASSERT(secondArg->type() == MIRType_Boolean); - MOZ_ASSERT(secondArg->isConstantValue()); + MOZ_ASSERT(secondArg->isConstant()); - bool mustBeFloat32 = secondArg->constantValue().toBoolean(); + bool mustBeFloat32 = secondArg->toConstant()->value().toBoolean(); current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32)); MConstant *undefined = MConstant::New(alloc(), UndefinedValue()); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index bf8895fa1821..ca19104a0798 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -71,45 +71,17 @@ MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op) fprintf(fp, "%c", tolower(name[i])); } -const Value & -MDefinition::constantValue() -{ - MOZ_ASSERT(isConstantValue()); - - if (isBox()) - return getOperand(0)->constantValue(); - return toConstant()->value(); -} - -const Value * -MDefinition::constantVp() -{ - MOZ_ASSERT(isConstantValue()); - if (isBox()) - return getOperand(0)->constantVp(); - return toConstant()->vp(); -} - -bool -MDefinition::constantToBoolean() -{ - MOZ_ASSERT(isConstantValue()); - if (isBox()) - return getOperand(0)->constantToBoolean(); - return toConstant()->valueToBoolean(); -} - static MConstant * EvaluateConstantOperands(TempAllocator &alloc, MBinaryInstruction *ins, bool *ptypeChange = nullptr) { MDefinition *left = ins->getOperand(0); MDefinition *right = ins->getOperand(1); - if (!left->isConstantValue() || !right->isConstantValue()) + if (!left->isConstant() || !right->isConstant()) return nullptr; - Value lhs = left->constantValue(); - Value rhs = right->constantValue(); + Value lhs = left->toConstant()->value(); + Value rhs = right->toConstant()->value(); Value ret = UndefinedValue(); switch (ins->op()) { @@ -174,10 +146,10 @@ EvaluateExactReciprocal(TempAllocator &alloc, MDiv *ins) MDefinition *left = ins->getOperand(0); MDefinition *right = ins->getOperand(1); - if (!right->isConstantValue()) + if (!right->isConstant()) return nullptr; - Value rhs = right->constantValue(); + Value rhs = right->toConstant()->value(); int32_t num; if (!mozilla::NumberIsInt32(rhs.toNumber(), &num)) @@ -383,8 +355,8 @@ MTest::foldsTo(TempAllocator &alloc) return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue()); } - if (op->isConstantValue() && !op->constantValue().isMagic()) - return MGoto::New(alloc, op->constantToBoolean() ? ifTrue() : ifFalse()); + if (op->isConstant()) + return MGoto::New(alloc, op->toConstant()->valueToBoolean() ? ifTrue() : ifFalse()); switch (op->type()) { case MIRType_Undefined: @@ -796,7 +768,7 @@ MSimdValueX4::foldsTo(TempAllocator &alloc) for (size_t i = 0; i < 4; ++i) { MDefinition *op = getOperand(i); MOZ_ASSERT(op->type() == scalarType); - if (!op->isConstantValue()) + if (!op->isConstant()) allConstants = false; if (i > 0 && op != getOperand(i - 1)) allSame = false; @@ -811,14 +783,14 @@ MSimdValueX4::foldsTo(TempAllocator &alloc) case MIRType_Int32x4: { int32_t a[4]; for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->constantValue().toInt32(); + a[i] = getOperand(i)->toConstant()->value().toInt32(); cst = SimdConstant::CreateX4(a); break; } case MIRType_Float32x4: { float a[4]; for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->constantValue().toNumber(); + a[i] = getOperand(i)->toConstant()->value().toNumber(); cst = SimdConstant::CreateX4(a); break; } @@ -837,7 +809,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) { DebugOnly scalarType = SimdTypeToScalarType(type()); MDefinition *op = getOperand(0); - if (!op->isConstantValue()) + if (!op->isConstant()) return this; MOZ_ASSERT(op->type() == scalarType); @@ -845,7 +817,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) switch (type()) { case MIRType_Int32x4: { int32_t a[4]; - int32_t v = getOperand(0)->constantValue().toInt32(); + int32_t v = getOperand(0)->toConstant()->value().toInt32(); for (size_t i = 0; i < 4; ++i) a[i] = v; cst = SimdConstant::CreateX4(a); @@ -853,7 +825,7 @@ MSimdSplatX4::foldsTo(TempAllocator &alloc) } case MIRType_Float32x4: { float a[4]; - float v = getOperand(0)->constantValue().toNumber(); + float v = getOperand(0)->toConstant()->value().toNumber(); for (size_t i = 0; i < 4; ++i) a[i] = v; cst = SimdConstant::CreateX4(a); @@ -1124,8 +1096,8 @@ MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDef MDefinition* MStringLength::foldsTo(TempAllocator &alloc) { - if ((type() == MIRType_Int32) && (string()->isConstantValue())) { - Value value = string()->constantValue(); + if ((type() == MIRType_Int32) && (string()->isConstant())) { + Value value = string()->toConstant()->value(); JSAtom *atom = &value.toString()->asAtom(); return MConstant::New(alloc, Int32Value(atom->length())); } @@ -1912,10 +1884,12 @@ MMinMax::foldsTo(TempAllocator &alloc) if (!lhs()->isConstant() && !rhs()->isConstant()) return this; - MDefinition *operand = lhs()->isConstantValue() ? rhs() : lhs(); - const js::Value &val = lhs()->isConstantValue() ? lhs()->constantValue() : rhs()->constantValue(); + MDefinition *operand = lhs()->isConstant() ? rhs() : lhs(); + MConstant *constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant(); if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) { + const js::Value &val = constant->value(); + // min(int32, cte >= INT32_MAX) = int32 if (val.isDouble() && val.toDouble() >= INT32_MAX && !isMax()) { MLimitedTruncate *limit = @@ -1985,25 +1959,25 @@ MDiv::analyzeEdgeCasesForward() return; // Try removing divide by zero check - if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0)) + if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0)) canBeDivideByZero_ = false; // If lhs is a constant int != INT32_MIN, then // negative overflow check can be skipped. - if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(INT32_MIN)) + if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(INT32_MIN)) canBeNegativeOverflow_ = false; // If rhs is a constant int != -1, likewise. - if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(-1)) + if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(-1)) canBeNegativeOverflow_ = false; // If lhs is != 0, then negative zero check can be skipped. - if (lhs()->isConstantValue() && !lhs()->constantValue().isInt32(0)) + if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(0)) setCanBeNegativeZero(false); // If rhs is >= 0, likewise. - if (rhs()->isConstantValue()) { - const js::Value &val = rhs()->constantValue(); + if (rhs()->isConstant()) { + const js::Value &val = rhs()->toConstant()->value(); if (val.isInt32() && val.toInt32() >= 0) setCanBeNegativeZero(false); } @@ -2041,11 +2015,11 @@ MMod::analyzeEdgeCasesForward() if (specialization_ != MIRType_Int32) return; - if (rhs()->isConstantValue() && !rhs()->constantValue().isInt32(0)) + if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0)) canBeDivideByZero_ = false; - if (rhs()->isConstantValue()) { - int32_t n = rhs()->constantValue().toInt32(); + if (rhs()->isConstant()) { + int32_t n = rhs()->toConstant()->value().toInt32(); if (n > 0 && !IsPowerOfTwo(n)) canBePowerOfTwoDivisor_ = false; } @@ -2119,15 +2093,15 @@ MMul::analyzeEdgeCasesForward() return; // If lhs is > 0, no need for negative zero check. - if (lhs()->isConstantValue()) { - const js::Value &val = lhs()->constantValue(); + if (lhs()->isConstant()) { + const js::Value &val = lhs()->toConstant()->value(); if (val.isInt32() && val.toInt32() > 0) setCanBeNegativeZero(false); } // If rhs is > 0, likewise. - if (rhs()->isConstantValue()) { - const js::Value &val = rhs()->constantValue(); + if (rhs()->isConstant()) { + const js::Value &val = rhs()->toConstant()->value(); if (val.isInt32() && val.toInt32() > 0) setCanBeNegativeZero(false); } @@ -2396,15 +2370,15 @@ MustBeUInt32(MDefinition *def, MDefinition **pwrapped) *pwrapped = def->toUrsh()->getOperand(0); MDefinition *rhs = def->toUrsh()->getOperand(1); return !def->toUrsh()->bailoutsDisabled() - && rhs->isConstantValue() - && rhs->constantValue().isInt32() - && rhs->constantValue().toInt32() == 0; + && rhs->isConstant() + && rhs->toConstant()->value().isInt32() + && rhs->toConstant()->value().toInt32() == 0; } - if (def->isConstantValue()) { + if (def->isConstant()) { *pwrapped = def; - return def->constantValue().isInt32() - && def->constantValue().toInt32() >= 0; + return def->toConstant()->value().isInt32() + && def->toConstant()->value().toInt32() >= 0; } return false; @@ -2579,7 +2553,7 @@ MBitNot::foldsTo(TempAllocator &alloc) MDefinition *input = getOperand(0); if (input->isConstant()) { - js::Value v = Int32Value(~(input->constantValue().toInt32())); + js::Value v = Int32Value(~(input->toConstant()->value().toInt32())); return MConstant::New(alloc, v); } @@ -2904,14 +2878,11 @@ MDefinition * MTruncateToInt32::foldsTo(TempAllocator &alloc) { MDefinition *input = getOperand(0); - if (input->isBox()) - input = input->getOperand(0); - if (input->type() == MIRType_Int32) return input; if (input->type() == MIRType_Double && input->isConstant()) { - const Value &v = input->constantValue(); + const Value &v = input->toConstant()->value(); int32_t ret = ToInt32(v.toDouble()); return MConstant::New(alloc, Int32Value(ret)); } @@ -2922,15 +2893,12 @@ MTruncateToInt32::foldsTo(TempAllocator &alloc) MDefinition * MToDouble::foldsTo(TempAllocator &alloc) { - MDefinition *input = getOperand(0); - if (input->isBox()) - input = input->getOperand(0); + MDefinition *in = input(); + if (in->type() == MIRType_Double) + return in; - if (input->type() == MIRType_Double) - return input; - - if (input->isConstant()) { - const Value &v = input->toConstant()->value(); + if (in->isConstant()) { + const Value &v = in->toConstant()->value(); if (v.isNumber()) { double out = v.toNumber(); return MConstant::New(alloc, DoubleValue(out)); @@ -2943,19 +2911,15 @@ MToDouble::foldsTo(TempAllocator &alloc) MDefinition * MToFloat32::foldsTo(TempAllocator &alloc) { - MDefinition *input = getOperand(0); - if (input->isBox()) - input = input->getOperand(0); - - if (input->type() == MIRType_Float32) - return input; + if (input()->type() == MIRType_Float32) + return input(); // If x is a Float32, Float32(Double(x)) == x - if (input->isToDouble() && input->toToDouble()->input()->type() == MIRType_Float32) - return input->toToDouble()->input(); + if (input()->isToDouble() && input()->toToDouble()->input()->type() == MIRType_Float32) + return input()->toToDouble()->input(); - if (input->isConstant()) { - const Value &v = input->toConstant()->value(); + if (input()->isConstant()) { + const Value &v = input()->toConstant()->value(); if (v.isNumber()) { float out = v.toNumber(); MConstant *c = MConstant::New(alloc, DoubleValue(out)); @@ -2970,9 +2934,6 @@ MDefinition * MToString::foldsTo(TempAllocator &alloc) { MDefinition *in = input(); - if (in->isBox()) - in = in->getOperand(0); - if (in->type() == MIRType_String) return in; return this; @@ -2981,8 +2942,8 @@ MToString::foldsTo(TempAllocator &alloc) MDefinition * MClampToUint8::foldsTo(TempAllocator &alloc) { - if (input()->isConstantValue()) { - const Value &v = input()->constantValue(); + if (input()->isConstant()) { + const Value &v = input()->toConstant()->value(); if (v.isDouble()) { int32_t clamped = ClampDoubleToUint8(v.toDouble()); return MConstant::New(alloc, Int32Value(clamped)); @@ -3397,8 +3358,8 @@ MDefinition * MNot::foldsTo(TempAllocator &alloc) { // Fold if the input is constant - if (input()->isConstantValue() && !input()->constantValue().isMagic()) { - bool result = input()->constantToBoolean(); + if (input()->isConstant()) { + bool result = input()->toConstant()->valueToBoolean(); if (type() == MIRType_Int32) return MConstant::New(alloc, Int32Value(!result)); @@ -3964,8 +3925,8 @@ MGetPropertyCache::updateForReplacement(MDefinition *ins) { MDefinition * MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc) { - if (input()->isConstantValue()) { - const Value &v = input()->constantValue(); + if (input()->isConstant()) { + const Value &v = input()->toConstant()->value(); if (v.isInt32()) return MConstant::New(alloc, DoubleValue(uint32_t(v.toInt32()))); } @@ -3976,8 +3937,8 @@ MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc) MDefinition * MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc) { - if (input()->isConstantValue()) { - const Value &v = input()->constantValue(); + if (input()->isConstant()) { + const Value &v = input()->toConstant()->value(); if (v.isInt32()) { double dval = double(uint32_t(v.toInt32())); if (IsFloat32Representable(dval)) @@ -4026,8 +3987,8 @@ MSqrt::trySpecializeFloat32(TempAllocator &alloc) { MDefinition * MClz::foldsTo(TempAllocator &alloc) { - if (num()->isConstantValue()) { - int32_t n = num()->constantValue().toInt32(); + if (num()->isConstant()) { + int32_t n = num()->toConstant()->value().toInt32(); if (n == 0) return MConstant::New(alloc, Int32Value(32)); return MConstant::New(alloc, Int32Value(mozilla::CountLeadingZeroes32(n))); @@ -4039,9 +4000,9 @@ MClz::foldsTo(TempAllocator &alloc) MDefinition * MBoundsCheck::foldsTo(TempAllocator &alloc) { - if (index()->isConstantValue() && length()->isConstantValue()) { - uint32_t len = length()->constantValue().toInt32(); - uint32_t idx = index()->constantValue().toInt32(); + if (index()->isConstant() && length()->isConstant()) { + uint32_t len = length()->toConstant()->value().toInt32(); + uint32_t idx = index()->toConstant()->value().toInt32(); if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) return index(); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index cdd30ce3f2d9..909e114f04a0 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -752,13 +752,6 @@ class MDefinition : public MNode MIR_OPCODE_LIST(OPCODE_CASTS) # undef OPCODE_CASTS - bool isConstantValue() { - return isConstant() || (isBox() && getOperand(0)->isConstant()); - } - const Value &constantValue(); - const Value *constantVp(); - bool constantToBoolean(); - inline MInstruction *toInstruction(); inline const MInstruction *toInstruction() const; bool isInstruction() const { diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 73956c675497..4f7bf6c108bb 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -174,12 +174,12 @@ RangeAnalysis::addBetaNodes() conservativeUpper = GenericNaN(); } - if (left->isConstantValue() && left->constantValue().isNumber()) { - bound = left->constantValue().toNumber(); + if (left->isConstant() && left->toConstant()->value().isNumber()) { + bound = left->toConstant()->value().toNumber(); val = right; jsop = ReverseCompareOp(jsop); - } else if (right->isConstantValue() && right->constantValue().isNumber()) { - bound = right->constantValue().toNumber(); + } else if (right->isConstant() && right->toConstant()->value().isNumber()) { + bound = right->toConstant()->value().toNumber(); val = left; } else if (left->type() == MIRType_Int32 && right->type() == MIRType_Int32) { MDefinition *smaller = nullptr; @@ -1310,14 +1310,14 @@ MLsh::computeRange(TempAllocator &alloc) left.wrapAroundToInt32(); MDefinition *rhs = getOperand(1); - if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { - int32_t c = rhs->constantValue().toInt32(); - setRange(Range::lsh(alloc, &left, c)); + if (!rhs->isConstant()) { + right.wrapAroundToShiftCount(); + setRange(Range::lsh(alloc, &left, &right)); return; } - right.wrapAroundToShiftCount(); - setRange(Range::lsh(alloc, &left, &right)); + int32_t c = rhs->toConstant()->value().toInt32(); + setRange(Range::lsh(alloc, &left, c)); } void @@ -1328,14 +1328,14 @@ MRsh::computeRange(TempAllocator &alloc) left.wrapAroundToInt32(); MDefinition *rhs = getOperand(1); - if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { - int32_t c = rhs->constantValue().toInt32(); - setRange(Range::rsh(alloc, &left, c)); + if (!rhs->isConstant()) { + right.wrapAroundToShiftCount(); + setRange(Range::rsh(alloc, &left, &right)); return; } - right.wrapAroundToShiftCount(); - setRange(Range::rsh(alloc, &left, &right)); + int32_t c = rhs->toConstant()->value().toInt32(); + setRange(Range::rsh(alloc, &left, c)); } void @@ -1353,11 +1353,11 @@ MUrsh::computeRange(TempAllocator &alloc) right.wrapAroundToShiftCount(); MDefinition *rhs = getOperand(1); - if (rhs->isConstantValue() && rhs->constantValue().isInt32()) { - int32_t c = rhs->constantValue().toInt32(); - setRange(Range::ursh(alloc, &left, c)); - } else { + if (!rhs->isConstant()) { setRange(Range::ursh(alloc, &left, &right)); + } else { + int32_t c = rhs->toConstant()->value().toInt32(); + setRange(Range::ursh(alloc, &left, c)); } MOZ_ASSERT(range()->lower() >= 0); @@ -2734,7 +2734,7 @@ CloneForDeadBranches(TempAllocator &alloc, MInstruction *candidate) candidate->block()->insertBefore(candidate, clone); - if (!candidate->isConstantValue()) { + if (!candidate->isConstant()) { MOZ_ASSERT(clone->canRecoverOnBailout()); clone->setRecoveredOnBailout(); } diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index c96ba425751b..2900fc54f0d4 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -533,10 +533,10 @@ IndexOf(MDefinition *ins, int32_t *res) indexDef = indexDef->toBoundsCheck()->index(); if (indexDef->isToInt32()) indexDef = indexDef->toToInt32()->getOperand(0); - if (!indexDef->isConstantValue()) + if (!indexDef->isConstant()) return false; - Value index = indexDef->constantValue(); + Value index = indexDef->toConstant()->value(); if (!index.isInt32()) return false; *res = index.toInt32(); @@ -966,7 +966,7 @@ ArrayMemoryView::visitSetInitializedLength(MSetInitializedLength *ins) // To obtain the length, we need to add 1 to it, and thus we need to create // a new constant that we register in the ArrayState. state_ = BlockState::Copy(alloc_, state_); - int32_t initLengthValue = ins->index()->constantValue().toInt32() + 1; + int32_t initLengthValue = ins->index()->toConstant()->value().toInt32() + 1; MConstant *initLength = MConstant::New(alloc_, Int32Value(initLengthValue)); ins->block()->insertBefore(ins, initLength); ins->block()->insertBefore(ins, state_); diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index b75169543a74..04327f229870 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -492,10 +492,10 @@ LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins) LAllocation ptrAlloc; // For the ARM it is best to keep the 'ptr' in a register if a bounds check is needed. - if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { + if (ptr->isConstant() && !ins->needsBoundsCheck()) { // A bounds check is only skipped for a positive index. - MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->constantVp()); + MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->toConstant()->vp()); } else { ptrAlloc = useRegisterAtStart(ptr); } @@ -510,9 +510,9 @@ LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) MOZ_ASSERT(ptr->type() == MIRType_Int32); LAllocation ptrAlloc; - if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { - MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->constantVp()); + if (ptr->isConstant() && !ins->needsBoundsCheck()) { + MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->toConstant()->vp()); } else { ptrAlloc = useRegisterAtStart(ptr); } diff --git a/js/src/jit/mips/Lowering-mips.cpp b/js/src/jit/mips/Lowering-mips.cpp index 60364bad6101..68c59be55f81 100644 --- a/js/src/jit/mips/Lowering-mips.cpp +++ b/js/src/jit/mips/Lowering-mips.cpp @@ -470,11 +470,11 @@ LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins) // For MIPS it is best to keep the 'ptr' in a register if a bounds check // is needed. - if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { - int32_t ptrValue = ptr->constantValue().toInt32(); + if (ptr->isConstant() && !ins->needsBoundsCheck()) { + int32_t ptrValue = ptr->toConstant()->value().toInt32(); // A bounds check is only skipped for a positive index. MOZ_ASSERT(ptrValue >= 0); - ptrAlloc = LAllocation(ptr->constantVp()); + ptrAlloc = LAllocation(ptr->toConstant()->vp()); } else ptrAlloc = useRegisterAtStart(ptr); @@ -488,9 +488,9 @@ LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) MOZ_ASSERT(ptr->type() == MIRType_Int32); LAllocation ptrAlloc; - if (ptr->isConstantValue() && !ins->needsBoundsCheck()) { - MOZ_ASSERT(ptr->constantValue().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->constantVp()); + if (ptr->isConstant() && !ins->needsBoundsCheck()) { + MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); + ptrAlloc = LAllocation(ptr->toConstant()->vp()); } else ptrAlloc = useRegisterAtStart(ptr); From 838a07863b67c341b833b51595c77a16d2bbe11c Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 22 Dec 2014 15:12:30 +0100 Subject: [PATCH 06/64] Bug 1112563 part 2 - Don't use useRegisterAtStart on x64 in cases where it could lead to worse codegen. r=sunfish --- js/src/jit/Lowering.cpp | 13 ++++++++----- js/src/jit/shared/Lowering-shared-inl.h | 17 +++++++++++++++++ js/src/jit/shared/Lowering-shared.h | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 1d724cf4fc9b..5ef521d52188 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2242,7 +2242,7 @@ LIRGenerator::visitLoadSlot(MLoadSlot *ins) MOZ_CRASH("typed load must have a payload"); default: - define(new(alloc()) LLoadSlotT(useRegisterAtStart(ins->slots())), ins); + define(new(alloc()) LLoadSlotT(useRegisterForTypedLoad(ins->slots(), ins->type())), ins); break; } } @@ -3088,13 +3088,16 @@ LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole *ins) void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot *ins) { - MOZ_ASSERT(ins->object()->type() == MIRType_Object); + MDefinition *obj = ins->object(); + MOZ_ASSERT(obj->type() == MIRType_Object); - if (ins->type() == MIRType_Value) { - LLoadFixedSlotV *lir = new(alloc()) LLoadFixedSlotV(useRegisterAtStart(ins->object())); + MIRType type = ins->type(); + + if (type == MIRType_Value) { + LLoadFixedSlotV *lir = new(alloc()) LLoadFixedSlotV(useRegisterAtStart(obj)); defineBox(lir, ins); } else { - LLoadFixedSlotT *lir = new(alloc()) LLoadFixedSlotT(useRegisterAtStart(ins->object())); + LLoadFixedSlotT *lir = new(alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type)); define(lir, ins); } } diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index 38aa8c398d8f..e2ba7f10cc1c 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -482,6 +482,23 @@ LIRGeneratorShared::fillBoxUses(LInstruction *lir, size_t n, MDefinition *mir) } #endif +LUse +LIRGeneratorShared::useRegisterForTypedLoad(MDefinition *mir, MIRType type) +{ + MOZ_ASSERT(type != MIRType_Value && type != MIRType_None); + MOZ_ASSERT(mir->type() == MIRType_Object || mir->type() == MIRType_Slots); + +#ifdef JS_PUNBOX64 + // On x64, masm.loadUnboxedValue emits slightly less efficient code when + // the input and output use the same register and we're not loading an + // int32/bool/double, so we just call useRegister in this case. + if (type != MIRType_Int32 && type != MIRType_Boolean && type != MIRType_Double) + return useRegister(mir); +#endif + + return useRegisterAtStart(mir); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h index f22b81864f51..98e86fda0834 100644 --- a/js/src/jit/shared/Lowering-shared.h +++ b/js/src/jit/shared/Lowering-shared.h @@ -111,6 +111,8 @@ class LIRGeneratorShared : public MDefinitionVisitor inline LAllocation useRegisterOrNonNegativeConstantAtStart(MDefinition *mir); inline LAllocation useRegisterOrNonDoubleConstant(MDefinition *mir); + inline LUse useRegisterForTypedLoad(MDefinition *mir, MIRType type); + #ifdef JS_NUNBOX32 inline LUse useType(MDefinition *mir, LUse::Policy policy); inline LUse usePayload(MDefinition *mir, LUse::Policy policy); From 56f126bbf220a7cd7800eb684916facd2252cce8 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Mon, 22 Dec 2014 06:28:07 -0800 Subject: [PATCH 07/64] Bug 1113789 - Remove GrallocTextureSourceOGL r=nical --- gfx/layers/opengl/GrallocTextureHost.cpp | 223 +---------------------- gfx/layers/opengl/GrallocTextureHost.h | 70 ------- 2 files changed, 5 insertions(+), 288 deletions(-) diff --git a/gfx/layers/opengl/GrallocTextureHost.cpp b/gfx/layers/opengl/GrallocTextureHost.cpp index 3df82b18a710..ee1f60822f9c 100644 --- a/gfx/layers/opengl/GrallocTextureHost.cpp +++ b/gfx/layers/opengl/GrallocTextureHost.cpp @@ -96,150 +96,6 @@ TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat) } } -GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor, - GrallocTextureHostOGL* aTextureHost, - android::GraphicBuffer* aGraphicBuffer, - gfx::SurfaceFormat aFormat) - : mCompositor(aCompositor) - , mTextureHost(aTextureHost) - , mGraphicBuffer(aGraphicBuffer) - , mEGLImage(0) - , mFormat(aFormat) - , mNeedsReset(true) -{ - MOZ_ASSERT(mGraphicBuffer.get()); -} - -GrallocTextureSourceOGL::~GrallocTextureSourceOGL() -{ - DeallocateDeviceData(); - mCompositor = nullptr; -} - -void -GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) -{ - /* - * The job of this function is to ensure that the texture is tied to the - * android::GraphicBuffer, so that texturing will source the GraphicBuffer. - * - * To this effect we create an EGLImage wrapping this GraphicBuffer, - * using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our - * texture using fEGLImageTargetTexture2D. - */ - MOZ_ASSERT(gl()); - if (!IsValid() || !gl()->MakeCurrent()) { - return; - } - - GLuint tex = GetGLTexture(); - GLuint textureTarget = GetTextureTarget(); - - gl()->fActiveTexture(aTextureUnit); - gl()->fBindTexture(textureTarget, tex); - - ApplyFilterToBoundTexture(gl(), aFilter, textureTarget); - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 - if (mTextureHost) { - // Wait until it's ready. - mTextureHost->WaitAcquireFenceSyncComplete(); - } -#endif -} - -bool GrallocTextureSourceOGL::Lock() -{ - MOZ_ASSERT(IsValid()); - if (!IsValid()) { - return false; - } - if (!gl()->MakeCurrent()) { - NS_WARNING("Failed to make the gl context current"); - return false; - } - - mTexture = mCompositor->GetTemporaryTexture(GetTextureTarget(), LOCAL_GL_TEXTURE0); - - GLuint textureTarget = GetTextureTarget(); - - gl()->fActiveTexture(LOCAL_GL_TEXTURE0); - gl()->fBindTexture(textureTarget, mTexture); - if (!mEGLImage) { - mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); - } - gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); - return true; -} - -bool -GrallocTextureSourceOGL::IsValid() const -{ - return !!gl() && !!mGraphicBuffer.get() && !!mCompositor; -} - -gl::GLContext* -GrallocTextureSourceOGL::gl() const -{ - return mCompositor ? mCompositor->gl() : nullptr; -} - -void -GrallocTextureSourceOGL::SetCompositor(Compositor* aCompositor) -{ - if (mCompositor && !aCompositor) { - DeallocateDeviceData(); - } - mCompositor = static_cast(aCompositor); -} - - -GLenum -GrallocTextureSourceOGL::GetTextureTarget() const -{ - MOZ_ASSERT(gl()); - MOZ_ASSERT(mGraphicBuffer.get()); - - if (!gl() || !mGraphicBuffer.get()) { - return LOCAL_GL_TEXTURE_EXTERNAL; - } - - // SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will - // result in black pixels when trying to draw from bound textures. - // Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on - // performance. - // See Bug 950050. - if (gl()->Renderer() == gl::GLRenderer::SGX530 || - gl()->Renderer() == gl::GLRenderer::SGX540) { - return LOCAL_GL_TEXTURE_EXTERNAL; - } - - return TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat()); -} - -gfx::IntSize -GrallocTextureSourceOGL::GetSize() const -{ - if (!IsValid()) { - NS_WARNING("Trying to access the size of an invalid GrallocTextureSourceOGL"); - return gfx::IntSize(0, 0); - } - return gfx::IntSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight()); -} - -void -GrallocTextureSourceOGL::DeallocateDeviceData() -{ - if (mEGLImage) { - MOZ_ASSERT(mCompositor); - if (!gl() || !gl()->MakeCurrent()) { - return; - } - EGLImageDestroy(gl(), mEGLImage); - mEGLImage = EGL_NO_IMAGE; - } -} - GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags, const NewSurfaceDescriptorGralloc& aDescriptor) : TextureHost(aFlags) @@ -272,9 +128,6 @@ void GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor) { mCompositor = static_cast(aCompositor); - if (mTilingTextureSource) { - mTilingTextureSource->SetCompositor(mCompositor); - } if (mGLTextureSource) { mGLTextureSource->SetCompositor(mCompositor); } @@ -312,10 +165,6 @@ GrallocTextureHostOGL::GetFormat() const void GrallocTextureHostOGL::DeallocateSharedData() { - if (mTilingTextureSource) { - mTilingTextureSource->ForgetBuffer(); - mTilingTextureSource = nullptr; - } if (mGLTextureSource) { mGLTextureSource = nullptr; } @@ -339,10 +188,6 @@ GrallocTextureHostOGL::DeallocateSharedData() void GrallocTextureHostOGL::ForgetSharedData() { - if (mTilingTextureSource) { - mTilingTextureSource->ForgetBuffer(); - mTilingTextureSource = nullptr; - } if (mGLTextureSource) { mGLTextureSource = nullptr; } @@ -351,9 +196,6 @@ GrallocTextureHostOGL::ForgetSharedData() void GrallocTextureHostOGL::DeallocateDeviceData() { - if (mTilingTextureSource) { - mTilingTextureSource->DeallocateDeviceData(); - } if (mGLTextureSource) { mGLTextureSource = nullptr; } @@ -387,77 +229,24 @@ GrallocTextureHostOGL::GetRenderState() TemporaryRef GrallocTextureHostOGL::GetAsSurface() { - if (mTilingTextureSource) { - return mTilingTextureSource->GetAsSurface(); - } else { - android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get(); - uint8_t* grallocData; - int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast(&grallocData)); - RefPtr grallocTempSurf = - gfx::Factory::CreateWrappingDataSourceSurface(grallocData, - graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()), - GetSize(), GetFormat()); - RefPtr surf = CreateDataSourceSurfaceByCloning(grallocTempSurf); - - graphicBuffer->unlock(); - - return surf.forget(); - } -} - -TemporaryRef -GrallocTextureSourceOGL::GetAsSurface() { - if (!IsValid()) { - return nullptr; - } - + android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get(); uint8_t* grallocData; - int32_t rv = mGraphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast(&grallocData)); - if (rv) { - return nullptr; - } - + int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast(&grallocData)); RefPtr grallocTempSurf = gfx::Factory::CreateWrappingDataSourceSurface(grallocData, - mGraphicBuffer->getStride() * android::bytesPerPixel(mGraphicBuffer->getPixelFormat()), + graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()), GetSize(), GetFormat()); - RefPtr surf = CreateDataSourceSurfaceByCloning(grallocTempSurf); - mGraphicBuffer->unlock(); + graphicBuffer->unlock(); return surf.forget(); } -GLuint -GrallocTextureSourceOGL::GetGLTexture() -{ - return mTexture; -} - -void -GrallocTextureSourceOGL::BindEGLImage() -{ - gl()->fEGLImageTargetTexture2D(GetTextureTarget(), mEGLImage); -} - TextureSource* GrallocTextureHostOGL::GetTextureSources() { - // This is now only used with tiled layers, and will eventually be removed. - // Other layer types use BindTextureSource instead. - MOZ_ASSERT(!mGLTextureSource); - if (!mTilingTextureSource) { - android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get(); - MOZ_ASSERT(graphicBuffer); - if (!graphicBuffer) { - return nullptr; - } - mTilingTextureSource = new GrallocTextureSourceOGL(mCompositor, this, - graphicBuffer, mFormat); - } - mTilingTextureSource->Lock(); - return mTilingTextureSource; + return nullptr; } void @@ -529,8 +318,6 @@ GrallocTextureHostOGL::PrepareTextureSource(CompositableTextureSourceRef& aTextu // because otherwise we would be modifying the content of every layer that uses // the TextureSource in question, even thoug they don't use this TextureHost. - MOZ_ASSERT(!mTilingTextureSource); - android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get(); MOZ_ASSERT(graphicBuffer); diff --git a/gfx/layers/opengl/GrallocTextureHost.h b/gfx/layers/opengl/GrallocTextureHost.h index 56290658f8d3..24565ff7d816 100644 --- a/gfx/layers/opengl/GrallocTextureHost.h +++ b/gfx/layers/opengl/GrallocTextureHost.h @@ -15,74 +15,6 @@ namespace mozilla { namespace layers { -class GrallocTextureHostOGL; - -// Progressively getting replaced by GLTextureSource -class GrallocTextureSourceOGL : public TextureSource - , public TextureSourceOGL -{ -public: - friend class GrallocTextureHostOGL; - - GrallocTextureSourceOGL(CompositorOGL* aCompositor, - GrallocTextureHostOGL* aTextureHost, - android::GraphicBuffer* aGraphicBuffer, - gfx::SurfaceFormat aFormat); - - virtual ~GrallocTextureSourceOGL(); - - virtual bool IsValid() const MOZ_OVERRIDE; - - virtual void BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) MOZ_OVERRIDE; - - virtual gfx::IntSize GetSize() const MOZ_OVERRIDE; - - virtual TextureSourceOGL* AsSourceOGL() MOZ_OVERRIDE { return this; } - - virtual GLenum GetTextureTarget() const MOZ_OVERRIDE; - - virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; } - - virtual GLenum GetWrapMode() const MOZ_OVERRIDE - { - return LOCAL_GL_CLAMP_TO_EDGE; - } - - void DeallocateDeviceData(); - - gl::GLContext* gl() const; - - virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; - - void ForgetBuffer() - { - mGraphicBuffer = nullptr; - mTextureHost = nullptr; - } - - TemporaryRef GetAsSurface(); - - GLuint GetGLTexture(); - - void BindEGLImage(); - - EGLImage GetEGLImage() - { - return mEGLImage; - } - - bool Lock(); - -protected: - RefPtr mCompositor; - GrallocTextureHostOGL* mTextureHost; - android::sp mGraphicBuffer; - EGLImage mEGLImage; - GLuint mTexture; - gfx::SurfaceFormat mFormat; - bool mNeedsReset; -}; - class GrallocTextureHostOGL : public TextureHost #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 , public TextureHostOGL @@ -144,8 +76,6 @@ private: NewSurfaceDescriptorGralloc mGrallocHandle; RefPtr mGLTextureSource; RefPtr mCompositor; - // only used for tiling, will be removed. - RefPtr mTilingTextureSource; // Size reported by the GraphicBuffer gfx::IntSize mSize; // Size reported by TextureClient, can be different in some cases (video?), From 5c4fa9cdc7ed75ae4f42993613c45e2de318a944 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Mon, 22 Dec 2014 09:43:23 -0500 Subject: [PATCH 08/64] Bug 1109540 - Improve GStreamerReader duration handling. r=k17e --- dom/media/gstreamer/GStreamerReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dom/media/gstreamer/GStreamerReader.cpp b/dom/media/gstreamer/GStreamerReader.cpp index d80901ec3e08..4fdd44b4c4e3 100644 --- a/dom/media/gstreamer/GStreamerReader.cpp +++ b/dom/media/gstreamer/GStreamerReader.cpp @@ -70,6 +70,7 @@ GStreamerReader::GStreamerReader(AbstractMediaDecoder* aDecoder) mMP3FrameParser(aDecoder->GetResource()->GetLength()), mDataOffset(0), mUseParserDuration(false), + mLastParserDuration(-1), #if GST_VERSION_MAJOR >= 1 mAllocator(nullptr), mBufferPool(nullptr), From 2603fcc13f54f5d7c3b509493ab9ea4e88b25644 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 19 Dec 2014 18:16:17 -0800 Subject: [PATCH 09/64] Bug 1111737. r=smaug --- dom/base/nsScriptLoader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 5fe40e37cd7a..f1f66db2f044 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -819,7 +819,12 @@ NotifyOffThreadScriptLoadCompletedRunnable::Run() { MOZ_ASSERT(NS_IsMainThread()); - nsresult rv = mLoader->ProcessOffThreadRequest(mRequest, &mToken); + // We want these to be dropped on the main thread, once we return from this + // function. + nsRefPtr request = mRequest.forget(); + nsRefPtr loader = mLoader.forget(); + + nsresult rv = loader->ProcessOffThreadRequest(request, &mToken); if (mToken) { // The result of the off thread parse was not actually needed to process From a7beaba91a911089eee2a4bc8296b7d91b81753d Mon Sep 17 00:00:00 2001 From: Brian O'Keefe Date: Wed, 21 May 2014 08:25:57 -0400 Subject: [PATCH 10/64] Bug 923080 - Generate xpt files into final location. r=glandium Now that the mozbuild backend knows about FINAL_TARGET, we are able to install generated xpt files into their final location. This saves us from copying xpt files into their final location on every build. Original patch by gps, rebased and comments addressed by Ms2ger --HG-- extra : transplant_source : %E2%DC%0F%E0%AD%C2%25%A1%B8%A9%FE%B0%8C%60%FF%CB%02G%25%E5 --- config/makefiles/xpidl/Makefile.in | 37 +++++------ config/rules.mk | 5 -- js/xpconnect/tests/idl/Makefile.in | 11 ---- js/xpconnect/tests/idl/moz.build | 8 +++ python/mozbuild/mozbuild/backend/common.py | 8 ++- .../mozbuild/backend/recursivemake.py | 63 +++++++++++-------- python/mozbuild/mozbuild/frontend/context.py | 2 +- python/mozbuild/mozbuild/frontend/data.py | 3 + python/mozbuild/mozbuild/frontend/emitter.py | 18 +++--- .../test/backend/test_recursivemake.py | 4 +- 10 files changed, 82 insertions(+), 77 deletions(-) delete mode 100644 js/xpconnect/tests/idl/Makefile.in diff --git a/config/makefiles/xpidl/Makefile.in b/config/makefiles/xpidl/Makefile.in index 178b7f2168f9..2c2b1b76627b 100644 --- a/config/makefiles/xpidl/Makefile.in +++ b/config/makefiles/xpidl/Makefile.in @@ -22,48 +22,39 @@ include $(topsrcdir)/config/rules.mk # As an optimization to reduce overall CPU usage, we process all .idl # belonging to a module with a single command invocation. This prevents # redundant parsing of .idl files and significantly reduces CPU cycles. -# -# Future improvement: Headers are currently written to a local directory then -# installed in the distribution directory. It is preferable to write headers -# directly into the distribution directory. However, PGO builds remove the dist -# directory via rm -rf (with no regards to manifests). Since the cost of -# processing XPIDL files is not trivial, it is preferrable to cache the headers -# and reinstall them rather than regenerate them. Ideally the dist pruning is -# performed with manifests. At that time we can write headers directly to the -# dist directory. # For dependency files. idl_deps_dir := .deps -# Where we put our final, linked .xpt files. -idl_xpt_dir := xpt - dist_idl_dir := $(DIST)/idl dist_include_dir := $(DIST)/include process_py := $(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py -# TODO we should use py_action, but that would require extra directories to be -# in the virtualenv. -idlprocess := $(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_CACHE_DIR) \ - $(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \ - $(dist_include_dir) $(idl_xpt_dir) $(idl_deps_dir) - ifdef LIBXUL_SDK -idlprocess += -I$(LIBXUL_SDK)/idl +libxul_sdk_includes := -I$(LIBXUL_SDK)/idl endif +# TODO we should use py_action, but that would require extra directories to be +# in the virtualenv. +%.xpt: + @echo "$(@F)" + $(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_CACHE_DIR) \ + $(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \ + $(dist_include_dir) $(@D) $(idl_deps_dir) $(libxul_sdk_includes) \ + $(basename $(notdir $@ $(filter %.idl,$^))) + xpidl_modules := @xpidl_modules@ +xpt_files := @xpt_files@ @xpidl_rules@ -linked_xpt_files := $(addprefix $(idl_xpt_dir)/,$(addsuffix .xpt,$(xpidl_modules))) depends_files := $(foreach root,$(xpidl_modules),$(idl_deps_dir)/$(root).pp) -GARBAGE += $(linked_xpt_files) $(depends_files) +GARBAGE += $(xpt_files) $(depends_files) -xpidl:: $(linked_xpt_files) +xpidl:: $(xpt_files) -$(linked_xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir) $(idl_xpt_dir)) +$(xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir)) $(call include_deps,$(depends_files)) diff --git a/config/rules.mk b/config/rules.mk index cec5deec5eeb..f5f21f5a13a4 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1157,11 +1157,6 @@ endif ifdef XPT_NAME #{ ifndef NO_DIST_INSTALL -_XPT_NAME_FILES := $(DEPTH)/config/makefiles/xpidl/xpt/$(XPT_NAME) -_XPT_NAME_DEST := $(FINAL_TARGET)/components -_XPT_NAME_TARGET := misc -INSTALL_TARGETS += _XPT_NAME - ifndef NO_INTERFACES_MANIFEST misc:: $(call mkdir_deps,$(FINAL_TARGET)/components) $(call py_action,buildlist,$(FINAL_TARGET)/components/interfaces.manifest 'interfaces $(XPT_NAME)') diff --git a/js/xpconnect/tests/idl/Makefile.in b/js/xpconnect/tests/idl/Makefile.in deleted file mode 100644 index 5603df2a1320..000000000000 --- a/js/xpconnect/tests/idl/Makefile.in +++ /dev/null @@ -1,11 +0,0 @@ -# -# 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 $(topsrcdir)/config/rules.mk - -componentdir = js/xpconnect/tests/components -libs:: $(DEPTH)/config/makefiles/xpidl/xpt/$(XPT_NAME) - $(INSTALL) $^ $(testxpcobjdir)/$(componentdir)/native - $(INSTALL) $^ $(testxpcobjdir)/$(componentdir)/js diff --git a/js/xpconnect/tests/idl/moz.build b/js/xpconnect/tests/idl/moz.build index 1b55e03ae1e3..71aee0d47b0e 100644 --- a/js/xpconnect/tests/idl/moz.build +++ b/js/xpconnect/tests/idl/moz.build @@ -14,3 +14,11 @@ XPIDL_SOURCES += [ XPIDL_MODULE = 'xpctest' +# XXX: This relies on xpctest.xpt being created in dist/bin/components/ during +# the export tier AND TEST_HARNESS_FILES being processed after that. +TEST_HARNESS_FILES.xpcshell.js.xpconnect.tests.components.native += [ + '!/dist/bin/components/xpctest.xpt', +] +TEST_HARNESS_FILES.xpcshell.js.xpconnect.tests.components.js += [ + '!/dist/bin/components/xpctest.xpt', +] diff --git a/python/mozbuild/mozbuild/backend/common.py b/python/mozbuild/mozbuild/backend/common.py index e2be49b0b7ee..4f8d0ee50eb3 100644 --- a/python/mozbuild/mozbuild/backend/common.py +++ b/python/mozbuild/mozbuild/backend/common.py @@ -39,7 +39,7 @@ class XPIDLManager(object): self.idls = {} self.modules = {} - def register_idl(self, source, module, allow_existing=False): + def register_idl(self, source, module, install_target, allow_existing=False): """Registers an IDL file with this instance. The IDL file will be built, installed, etc. @@ -58,7 +58,8 @@ class XPIDLManager(object): raise Exception('IDL already registered: %' % entry['basename']) self.idls[entry['basename']] = entry - self.modules.setdefault(entry['module'], set()).add(entry['root']) + t = self.modules.setdefault(entry['module'], (install_target, set())) + t[1].add(entry['root']) class WebIDLCollection(object): @@ -181,7 +182,8 @@ class CommonBackend(BuildBackend): topsrcdir=obj.topsrcdir) elif isinstance(obj, XPIDLFile): - self._idl_manager.register_idl(obj.source_path, obj.module) + self._idl_manager.register_idl(obj.source_path, obj.module, + obj.install_target) elif isinstance(obj, ConfigFileSubstitution): # Do not handle ConfigFileSubstitution for Makefiles. Leave that diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 809407badb59..39c2f7b985ad 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals +import errno import itertools import json import logging @@ -15,11 +16,11 @@ from collections import ( defaultdict, namedtuple, ) +from StringIO import StringIO import mozwebidlcodegen from reftest import ReftestManifest -import mozbuild.makeutil as mozmakeutil from mozpack.copier import FilePurger from mozpack.manifests import ( InstallManifest, @@ -751,7 +752,7 @@ class RecursiveMakeBackend(CommonBackend): # Write out a master list of all IPDL source files. ipdl_dir = mozpath.join(self.environment.topobjdir, 'ipc', 'ipdl') - mk = mozmakeutil.Makefile() + mk = Makefile() sorted_ipdl_sources = list(sorted(self._ipdl_sources)) mk.add_statement('ALL_IPDLSRCS := %s' % ' '.join(sorted_ipdl_sources)) @@ -983,8 +984,7 @@ INSTALL_TARGETS += %(prefix)s def _handle_idl_manager(self, manager): build_files = self._install_manifests['xpidl'] - for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done', - 'xpt/.mkdir.done'): + for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done'): build_files.add_optional_exists(p) for idl in manager.idls.values(): @@ -994,34 +994,44 @@ INSTALL_TARGETS += %(prefix)s % idl['root']) for module in manager.modules: - build_files.add_optional_exists(mozpath.join('xpt', - '%s.xpt' % module)) build_files.add_optional_exists(mozpath.join('.deps', '%s.pp' % module)) modules = manager.modules xpt_modules = sorted(modules.keys()) - rules = [] + xpt_files = set() + + mk = Makefile() for module in xpt_modules: - deps = sorted(modules[module]) - idl_deps = ['$(dist_idl_dir)/%s.idl' % dep for dep in deps] - rules.extend([ - # It may seem strange to have the .idl files listed as - # prerequisites both here and in the auto-generated .pp files. - # It is necessary to list them here to handle the case where a - # new .idl is added to an xpt. If we add a new .idl and nothing - # else has changed, the new .idl won't be referenced anywhere - # except in the command invocation. Therefore, the .xpt won't - # be rebuilt because the dependencies say it is up to date. By - # listing the .idls here, we ensure the make file has a - # reference to the new .idl. Since the new .idl presumably has - # an mtime newer than the .xpt, it will trigger xpt generation. - '$(idl_xpt_dir)/%s.xpt: %s' % (module, ' '.join(idl_deps)), - '\t@echo "$(notdir $@)"', - '\t$(idlprocess) $(basename $(notdir $@)) %s' % ' '.join(deps), - '', - ]) + install_target, sources = modules[module] + deps = sorted(sources) + + # It may seem strange to have the .idl files listed as + # prerequisites both here and in the auto-generated .pp files. + # It is necessary to list them here to handle the case where a + # new .idl is added to an xpt. If we add a new .idl and nothing + # else has changed, the new .idl won't be referenced anywhere + # except in the command invocation. Therefore, the .xpt won't + # be rebuilt because the dependencies say it is up to date. By + # listing the .idls here, we ensure the make file has a + # reference to the new .idl. Since the new .idl presumably has + # an mtime newer than the .xpt, it will trigger xpt generation. + xpt_path = '$(DEPTH)/%s/components/%s.xpt' % (install_target, module) + xpt_files.add(xpt_path) + rule = mk.create_rule([xpt_path]) + rule.add_dependencies(['$(call mkdir_deps,%s)' % mozpath.dirname(xpt_path)]) + rule.add_dependencies(manager.idls['%s.idl' % dep]['source'] for dep in deps) + + if install_target.startswith('dist/'): + path = mozpath.relpath(xpt_path, '$(DEPTH)/dist') + prefix, subpath = path.split('/', 1) + key = 'dist_%s' % prefix + + self._install_manifests[key].add_optional_exists(subpath) + + rules = StringIO() + mk.dump(rules, removal_guard=False) # Create dependency for output header so we force regeneration if the # header was deleted. This ideally should not be necessary. However, @@ -1037,8 +1047,9 @@ INSTALL_TARGETS += %(prefix)s obj.topobjdir = self.environment.topobjdir obj.config = self.environment self._create_makefile(obj, extra=dict( - xpidl_rules='\n'.join(rules), + xpidl_rules=rules.getvalue(), xpidl_modules=' '.join(xpt_modules), + xpt_files=' '.join(sorted(xpt_files)), )) def _process_program(self, program, backend_file): diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index e0cd58fb3acf..9b99dbba20ed 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -1161,7 +1161,7 @@ VARIABLES = { Files from topsrcdir and the objdir can also be installed by prefixing the path(s) with a '/' character and a '!' character, respectively:: TEST_HARNESS_FILES.path += ['/build/bar.py', '!quux.py'] - """, None), + """, 'libs'), } # Sanity check: we don't want any variable above to have a list as storage type. diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index ddb17920e548..3c88785c1127 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -157,6 +157,7 @@ class XPIDLFile(ContextDerived): __slots__ = ( 'basename', + 'install_target', 'source_path', ) @@ -167,6 +168,8 @@ class XPIDLFile(ContextDerived): self.basename = mozpath.basename(source) self.module = module + self.install_target = context['FINAL_TARGET'] + class Defines(ContextDerived): """Context derived container object for DEFINES, which is an OrderedDict. """ diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index f3f087e31dcc..6a7604c10278 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -345,6 +345,14 @@ class TreeMetadataEmitter(LoggingMixin): This is a generator of mozbuild.frontend.data.ContextDerived instances. """ + + # We only want to emit an InstallationTarget if one of the consulted + # variables is defined. Later on, we look up FINAL_TARGET, which has + # the side-effect of populating it. So, we need to do this lookup + # early. + if any(k in context for k in ('FINAL_TARGET', 'XPI_NAME', 'DIST_SUBDIR')): + yield InstallationTarget(context) + # We always emit a directory traversal descriptor. This is needed by # the recursive make backend. for o in self._emit_directory_traversal_from_context(context): yield o @@ -523,9 +531,9 @@ class TreeMetadataEmitter(LoggingMixin): for s in strings: if context.is_objdir_path(s): if s.startswith('!/'): - raise SandboxValidationError( - 'Topobjdir-relative file not allowed in TEST_HARNESS_FILES: %s' % s, context) - objdir_files[path].append(s[1:]) + objdir_files[path].append('$(DEPTH)/%s' % s[2:]) + else: + objdir_files[path].append(s[1:]) else: resolved = context.resolve_path(s) if '*' in s: @@ -616,10 +624,6 @@ class TreeMetadataEmitter(LoggingMixin): 'does not exist: %s (resolved to %s)' % (local_include, actual_include), context) yield LocalInclude(context, local_include) - if context.get('FINAL_TARGET') or context.get('XPI_NAME') or \ - context.get('DIST_SUBDIR'): - yield InstallationTarget(context) - final_target_files = context.get('FINAL_TARGET_FILES') if final_target_files: yield FinalTargetFiles(context, final_target_files, context['FINAL_TARGET']) diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py index 08dada9a8803..8d045c85bfdc 100644 --- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py +++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py @@ -443,7 +443,9 @@ class TestRecursiveMakeBackend(BackendTester): m = InstallManifest(path=mozpath.join(install_dir, 'xpidl')) self.assertIn('.deps/my_module.pp', m) - self.assertIn('xpt/my_module.xpt', m) + + m = InstallManifest(path=os.path.join(install_dir, 'dist_bin')) + self.assertIn('components/my_module.xpt', m) m = InstallManifest(path=mozpath.join(install_dir, 'dist_include')) self.assertIn('foo.h', m) From c9f7bd7b3dbb2453c36480004d409a3069aa8929 Mon Sep 17 00:00:00 2001 From: "Szu-Yu Chen [:aknow]" Date: Mon, 22 Dec 2014 16:31:05 +0800 Subject: [PATCH 11/64] Bug 1102677 - Part 1: Support change barring password. r=hsinyi --- dom/system/gonk/ril_consts.js | 8 +++++ dom/system/gonk/ril_worker.js | 45 ++++++++++++++++++++++++++ dom/telephony/gonk/TelephonyService.js | 2 ++ 3 files changed, 55 insertions(+) diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index 8eb042953bbd..e46d9c0bc177 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -2999,6 +2999,10 @@ this.MMI_SC_CLIR = "31"; // MMI call waiting service code this.MMI_SC_CALL_WAITING = "43"; +// MMI service code for registration new password as defined in TS 22.030 6.5.4 +this.MMI_SC_CHANGE_PASSWORD = "03"; +this.MMI_ZZ_BARRING_SERVICE = "330"; + // MMI call barring service codes this.MMI_SC_BAOC = "33"; this.MMI_SC_BAOIC = "331"; @@ -3031,6 +3035,7 @@ this.MMI_KS_SC_PIN = "scPin"; this.MMI_KS_SC_PIN2 = "scPin2"; this.MMI_KS_SC_PUK = "scPuk"; this.MMI_KS_SC_PUK2 = "scPuk2"; +this.MMI_KS_SC_CHANGE_PASSWORD = "scChangePassword" this.MMI_KS_SC_IMEI = "scImei"; this.MMI_KS_SC_USSD = "scUssd"; this.MMI_KS_SC_CALL = "scCall"; @@ -3040,13 +3045,16 @@ this.MMI_ERROR_KS_ERROR = "emMmiError"; this.MMI_ERROR_KS_NOT_SUPPORTED = "emMmiErrorNotSupported"; this.MMI_ERROR_KS_INVALID_ACTION = "emMmiErrorInvalidAction"; this.MMI_ERROR_KS_MISMATCH_PIN = "emMmiErrorMismatchPin"; +this.MMI_ERROR_KS_MISMATCH_PASSWORD = "emMmiErrorMismatchPassword"; this.MMI_ERROR_KS_BAD_PIN = "emMmiErrorBadPin"; this.MMI_ERROR_KS_BAD_PUK = "emMmiErrorBadPuk"; this.MMI_ERROR_KS_INVALID_PIN = "emMmiErrorInvalidPin"; +this.MMI_ERROR_KS_INVALID_PASSWORD = "emMmiErrorInvalidPassword"; this.MMI_ERROR_KS_NEEDS_PUK = "emMmiErrorNeedsPuk"; this.MMI_ERROR_KS_SIM_BLOCKED = "emMmiErrorSimBlocked"; // MMI status message. +this.MMI_SM_KS_PASSWORD_CHANGED = "smPasswordChanged"; this.MMI_SM_KS_PIN_CHANGED = "smPinChanged"; this.MMI_SM_KS_PIN2_CHANGED = "smPin2Changed"; this.MMI_SM_KS_PIN_UNBLOCKED = "smPinUnblocked"; diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index a09fbe2ea630..33e3c4e2b010 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -2409,6 +2409,33 @@ RilObject.prototype = { return true; } + function _isValidChangePasswordRequest() { + if (mmi.procedure !== MMI_PROCEDURE_REGISTRATION && + mmi.procedure !== MMI_PROCEDURE_ACTIVATION) { + _sendMMIError(MMI_ERROR_KS_INVALID_ACTION); + return false; + } + + if (mmi.sia !== "" && mmi.sia !== MMI_ZZ_BARRING_SERVICE) { + _sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED); + return false; + } + + let validPassword = si => /^[0-9]{4}$/.test(si); + if (!validPassword(mmi.sib) || !validPassword(mmi.sic) || + !validPassword(mmi.pwd)) { + _sendMMIError(MMI_ERROR_KS_INVALID_PASSWORD); + return false; + } + + if (mmi.sic != mmi.pwd) { + _sendMMIError(MMI_ERROR_KS_MISMATCH_PASSWORD); + return false; + } + + return true; + } + let _isRadioAvailable = (function() { if (this.radioState !== GECKO_RADIOSTATE_ENABLED) { _sendMMIError(GECKO_ERROR_RADIO_NOT_AVAILABLE); @@ -2556,6 +2583,17 @@ RilObject.prototype = { this.setCLIR(options); return; + // Change call barring password + case MMI_SC_CHANGE_PASSWORD: + if (!_isRadioAvailable() || !_isValidChangePasswordRequest()) { + return; + } + + options.pin = mmi.sib; + options.newPin = mmi.sic; + this.changeCallBarringPassword(options); + return; + // Call barring case MMI_SC_BAOC: case MMI_SC_BAOIC: @@ -5986,6 +6024,13 @@ RilObject.prototype[REQUEST_CHANGE_BARRING_PASSWORD] = if (options.rilRequestError) { options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]; } + + if (options.rilMessageType != "sendMMI") { + this.sendChromeMessage(options); + return; + } + + options.statusMessage = MMI_SM_KS_PASSWORD_CHANGED; this.sendChromeMessage(options); }; RilObject.prototype[REQUEST_SIM_OPEN_CHANNEL] = function REQUEST_SIM_OPEN_CHANNEL(length, options) { diff --git a/dom/telephony/gonk/TelephonyService.js b/dom/telephony/gonk/TelephonyService.js index 20cfe648a1a4..77d3e4684bc0 100644 --- a/dom/telephony/gonk/TelephonyService.js +++ b/dom/telephony/gonk/TelephonyService.js @@ -907,6 +907,8 @@ TelephonyService.prototype = { return RIL.MMI_KS_SC_CALL_BARRING; case RIL.MMI_SC_CALL_WAITING: return RIL.MMI_KS_SC_CALL_WAITING; + case RIL.MMI_SC_CHANGE_PASSWORD: + return RIL.MMI_KS_SC_CHANGE_PASSWORD; default: return RIL.MMI_KS_SC_USSD; } From aab6c1e727057394985eb5e725729317b8720353 Mon Sep 17 00:00:00 2001 From: "Szu-Yu Chen [:aknow]" Date: Mon, 22 Dec 2014 16:31:05 +0800 Subject: [PATCH 12/64] Bug 1102677 - Part 2: Test change barring password. r=hsinyi --- dom/telephony/test/marionette/manifest.ini | 1 + .../test_mmi_change_barring_password.js | 99 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 dom/telephony/test/marionette/test_mmi_change_barring_password.js diff --git a/dom/telephony/test/marionette/manifest.ini b/dom/telephony/test/marionette/manifest.ini index afba3a7744ba..370115850ae4 100644 --- a/dom/telephony/test/marionette/manifest.ini +++ b/dom/telephony/test/marionette/manifest.ini @@ -33,6 +33,7 @@ qemu = true [test_incoming_onstatechange.js] [test_mmi.js] [test_mmi_call_forwarding.js] +[test_mmi_change_barring_password.js] [test_mmi_change_pin.js] [test_mmi_unlock_puk.js] [test_multiple_hold.js] diff --git a/dom/telephony/test/marionette/test_mmi_change_barring_password.js b/dom/telephony/test/marionette/test_mmi_change_barring_password.js new file mode 100644 index 000000000000..688cca936941 --- /dev/null +++ b/dom/telephony/test/marionette/test_mmi_change_barring_password.js @@ -0,0 +1,99 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = "head.js"; + +const TEST_DATA = [ + // Test passing no password. + { + password: "", + newPassword: "0000", + newPasswordAgain: "1111", + expectedError: { + name: "emMmiErrorInvalidPassword" + } + }, + // Test passing no newPassword. + { + password: "0000", + newPassword: "", + newPasswordAgain: "", + expectedError: { + name: "emMmiErrorInvalidPassword" + } + }, + // Test passing mismatched newPassword. + { + password: "0000", + newPassword: "0000", + newPasswordAgain: "1111", + expectedError: { + name: "emMmiErrorMismatchPassword" + } + }, + // Test passing invalid password (not 4 digits). + { + password: "000", + newPassword: "0000", + newPasswordAgain: "0000", + expectedError: { + name: "emMmiErrorInvalidPassword" + } + }, + // TODO: Bug 906603 - B2G RIL: Support Change Call Barring Password on Emulator. + // Currently emulator doesn't support REQUEST_CHANGE_BARRING_PASSWORD, so we + // expect to get a 'RequestNotSupported' error here. + { + password: "0000", + newPassword: "1234", + newPasswordAgain: "1234", + expectedError: { + name: "RequestNotSupported" + } + } +]; + +let MMI_PREFIX = [ + "*03*330*", + "**03*330*", + "*03**", + "**03**", +]; + +function testChangeCallBarringPassword(aMMIPrefix, aPassword, aNewPassword, + aNewPasswordAgain, aExpectedError) { + let MMI_CODE = aMMIPrefix + aPassword + "*" + aNewPassword + "*" + aNewPasswordAgain + "#"; + log("Test " + MMI_CODE); + + return gSendMMI(MMI_CODE).then(aResult => { + is(aResult.success, !aExpectedError, "check success"); + is(aResult.serviceCode, "scChangePassword", "Check service code"); + + if (aResult.success) { + is(aResult.statusMessage, "smPasswordChanged", "Check status message"); + } else { + is(aResult.statusMessage, aExpectedError.name, "Check name"); + } + }); +} + +// Start test +startTest(function() { + let promise = Promise.resolve(); + + for (let prefix of MMI_PREFIX) { + for (let i = 0; i < TEST_DATA.length; i++) { + let data = TEST_DATA[i]; + promise = promise.then(() => testChangeCallBarringPassword(prefix, + data.password, + data.newPassword, + data.newPasswordAgain, + data.expectedError)); + } + } + + return promise + .catch(error => ok(false, "Promise reject: " + error)) + .then(finish); +}); From 5bfbc0bf59f924ed0cd722ee5249e50269906d4a Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 00:47:21 -0800 Subject: [PATCH 13/64] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/5ef8d3325421 Author: Carsten Book Desc: Merge pull request #25154 from kumarrishav/Bug-1018111 Bug 1018111 - [Flame][v1.4][MMS] Edit text messages, add video no size limit tips. r=schung ======== https://hg.mozilla.org/integration/gaia-central/rev/657a8ccf694e Author: kumarrishav Desc: Bug 1018111 - [Flame][v1.4][MMS] Edit text messages, add video no size limit tips. r=schung --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 268db5789540..2f4178c50a32 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "24f27472ae6ddb6c819227cb3b7d398a6925ef86", + "revision": "5ef8d3325421d3ba2daa9e0f65e440a9d246caed", "repo_path": "integration/gaia-central" } From b29f668dd2ad46ed270bda36c4fdc833dee4f68b Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 00:57:01 -0800 Subject: [PATCH 14/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 4d97b2b66713..7f27b9aef6a9 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index b8e313a63f1b..1be3265530ae 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 32afd2fa4ce0..fd8f0001fea1 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 6cf8daedb49d..04bc22fb6d7d 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index b8e313a63f1b..1be3265530ae 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 07b0daa266cc..e22251b2897c 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index c187faaddb84..5fcbde86fc73 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index c3ccf6c249a8..a216c624bd29 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 4befdd30e25e..8bdf064867cf 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 413f4e5dc31d..6e93ebb38b09 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 29a9290d3b16..818513804b2e 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From 9d3b59cc6d008c7c05b0fe740a756f68373cec0c Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 01:52:17 -0800 Subject: [PATCH 15/64] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/d6a5a6c41d8d Author: Tzu-Lin Huang Desc: Merge pull request #26735 from dwi2/bug1105976 Bug 1105976 - [Stingray][Home] Add Folder structure and its data access methods ======== https://hg.mozilla.org/integration/gaia-central/rev/21a1cae0e006 Author: Tzu-Lin Huang Desc: Bug 1105976 - [Stingray][Home] Add Folder structure and its data access methods --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 2f4178c50a32..41251327f784 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "5ef8d3325421d3ba2daa9e0f65e440a9d246caed", + "revision": "d6a5a6c41d8d4cf54513a1b4e73588b0e9f28a06", "repo_path": "integration/gaia-central" } From 59f02efbaf23327593e0c1c5157782d86ef5bbc9 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 01:56:56 -0800 Subject: [PATCH 16/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 7f27b9aef6a9..845022ec0379 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 1be3265530ae..d31146962cc4 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index fd8f0001fea1..a1fa7c4f979e 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 04bc22fb6d7d..d53c13effa39 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 1be3265530ae..d31146962cc4 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index e22251b2897c..8c26848e37b4 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 5fcbde86fc73..5ec10a35978d 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index a216c624bd29..ea4481c78c6f 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 8bdf064867cf..727e670ed23b 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 6e93ebb38b09..48dfeb3a4f3c 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 818513804b2e..e4665aab4096 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From a7a06d34199d110609e90f96db732d8f0c9da60a Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 02:07:16 -0800 Subject: [PATCH 17/64] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/864cabbeed24 Author: John Hu Desc: Merge pull request #26929 from huchengtw-moz/bug-1114399-button-group-is-still-opened Bug 1114399 - [Stingray][Home] check if the opening/closing is changed w..., r=dwi2 ======== https://hg.mozilla.org/integration/gaia-central/rev/24f81f71aa6b Author: John Hu Desc: Bug 1114399 - [Stingray][Home] check if the opening/closing is changed while moving to next state --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 41251327f784..bfbbbc6de702 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "d6a5a6c41d8d4cf54513a1b4e73588b0e9f28a06", + "revision": "864cabbeed248a7dbe6adb517c6dce2c256f2fdb", "repo_path": "integration/gaia-central" } From e06d4f878edf5bf81fb3100505a6575239d4f784 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 02:11:55 -0800 Subject: [PATCH 18/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 845022ec0379..d917d434fbfb 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index d31146962cc4..9e0d5b661030 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index a1fa7c4f979e..be56ead90dff 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index d53c13effa39..4ce6734a940f 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index d31146962cc4..9e0d5b661030 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 8c26848e37b4..7c13c2194d1f 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 5ec10a35978d..05c0f66ac972 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index ea4481c78c6f..12a14dfef534 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 727e670ed23b..39dc91c6bd91 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 48dfeb3a4f3c..5f7673e3a250 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index e4665aab4096..f1004b7e7306 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From e0d22892d7d2ad7c95cf08d88bac38cc6aa45a15 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 03:07:17 -0800 Subject: [PATCH 19/64] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ======== https://hg.mozilla.org/integration/gaia-central/rev/430c14631ade Author: Fernando Jiménez Moreno Desc: Merge pull request #26911 from ferjm/bug968917.simnumber Bug 968917 - [Contacts][l12y] Fix concatenated string simNumber with : c... ======== https://hg.mozilla.org/integration/gaia-central/rev/d968167b3493 Author: Fernando Jiménez Moreno Desc: Bug 968917 - [Contacts][l12y] Fix concatenated string simNumber with : character. r=francisco --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index bfbbbc6de702..d599ff86f79c 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "864cabbeed248a7dbe6adb517c6dce2c256f2fdb", + "revision": "430c14631adeb0a103a10699d965f8eceda128af", "repo_path": "integration/gaia-central" } From d65fc0b0436bb4900e97d6d17642f2f0b947acd8 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 03:17:03 -0800 Subject: [PATCH 20/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index d917d434fbfb..5590b55936da 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 9e0d5b661030..95d7bdd73f04 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index be56ead90dff..533b81ab9cab 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 4ce6734a940f..e2cf579fbb76 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 9e0d5b661030..95d7bdd73f04 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 7c13c2194d1f..72373807f8c9 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 05c0f66ac972..f84bb5e4dad6 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index 12a14dfef534..2c479ef7cf15 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 39dc91c6bd91..4fd87621f433 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 5f7673e3a250..e04110d10239 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index f1004b7e7306..0615969ee404 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From d9c0f0d53b69e3e97446719f9e47062030579f69 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 03:57:16 -0800 Subject: [PATCH 21/64] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ======== https://hg.mozilla.org/integration/gaia-central/rev/bc742f78bfbf Author: Salvador de la Puente González Desc: Merge pull request #26240 from lodr/bug-997547-text-to-email-from-contacts Bug 997547 - [MMS]Text to email from Contact details ======== https://hg.mozilla.org/integration/gaia-central/rev/e67293e80441 Author: na-matsumoto Desc: Bug 997547 - [MMS]Text to email from Contact details --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index d599ff86f79c..7bf1ded57d1a 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "430c14631adeb0a103a10699d965f8eceda128af", + "revision": "bc742f78bfbf6ac1e5a2ef1b452895fa701beceb", "repo_path": "integration/gaia-central" } From 558a82f1ccf99b413a6216d9c48f06a342197235 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 04:01:55 -0800 Subject: [PATCH 22/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 5590b55936da..f1abee77d888 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 95d7bdd73f04..ba572fcf01d0 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 533b81ab9cab..94ba2c8ddbb1 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index e2cf579fbb76..b2dcbd92f318 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 95d7bdd73f04..ba572fcf01d0 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 72373807f8c9..6b1b43fbd3e2 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index f84bb5e4dad6..7766ad5a6f49 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index 2c479ef7cf15..d44272520886 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 4fd87621f433..145591ac30d9 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index e04110d10239..afcb22921212 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 0615969ee404..e4040096c92c 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From ebbd33a63c592512b2d280366e608b03680fbb64 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 04:12:17 -0800 Subject: [PATCH 23/64] Bumping gaia.json for 3 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/644729ef0d87 Author: George Desc: Merge pull request #26049 from cctuan/1095774 Bug 1095774 - [Text Selection] Choosing "select all" when only 1 word is displayed dismisses the keyboard but not the menu ======== https://hg.mozilla.org/integration/gaia-central/rev/86af9b019e31 Author: cctuan Desc: Bug 1095774 - [Text Selection] raise zindex of text-selection bubble ======== https://hg.mozilla.org/integration/gaia-central/rev/f063700a6102 Author: Salvador de la Puente Desc: Revert "Merge pull request #26240 from lodr/bug-997547-text-to-email-from-contacts" This reverts commit 87e91a8c0ff44ff23c49d62c0d8f3827e0bccff9, reversing changes made to 17b0cf9691ff70ee02b1254691351d6b63086c03. --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 7bf1ded57d1a..96b6c17a3333 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "bc742f78bfbf6ac1e5a2ef1b452895fa701beceb", + "revision": "644729ef0d87bfd9994325f7ee8875e1df30c139", "repo_path": "integration/gaia-central" } From b9d040b1fd0a732bdf6151153f1e32b0a3fffab5 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 04:17:02 -0800 Subject: [PATCH 24/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index f1abee77d888..d569c43825fc 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index ba572fcf01d0..bdfd3808d737 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 94ba2c8ddbb1..31102ae37cf8 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index b2dcbd92f318..06d22c370d94 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index ba572fcf01d0..bdfd3808d737 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 6b1b43fbd3e2..13cdc8394db3 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 7766ad5a6f49..d997d3559dc9 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index d44272520886..a4dfd542999f 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 145591ac30d9..855755f93a26 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index afcb22921212..e99af6ffcab9 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index e4040096c92c..875f04294971 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From 5f8b12dcf8b47d348bb0d3ea7243d6e8dfb3bdee Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Sun, 21 Dec 2014 17:28:00 +0100 Subject: [PATCH 25/64] BUG 1070831 - Part 1: Clean up the WebIDL. r=hsinyi --- dom/webidl/MozMobileConnection.webidl | 49 --------------------------- dom/webidl/USSDReceivedEvent.webidl | 4 +-- 2 files changed, 1 insertion(+), 52 deletions(-) diff --git a/dom/webidl/MozMobileConnection.webidl b/dom/webidl/MozMobileConnection.webidl index 5c16958ad07f..c9ea38eb74d9 100644 --- a/dom/webidl/MozMobileConnection.webidl +++ b/dom/webidl/MozMobileConnection.webidl @@ -263,49 +263,6 @@ interface MozMobileConnection : EventTarget [Throws, CheckPermissions="mobileconnection"] DOMRequest getVoicePrivacyMode(); - /** - * Send a MMI message. - * - * @param mmi - * DOMString containing an MMI string that can be associated to a - * USSD request or other RIL functionality. - * - * @return a DOMRequest. - * - * If successful, the request's onsuccess will be called. And the request's - * result will be an object containing information about the operation. - * @see MozMMIResult for the detail of result. - * - * Otherwise, the request's onerror will be called, and the request's error - * will be a DOMMMIError. - * @see DOMMMIError for the detail of error. - * - * Note: In case that the MMI code requires sending an USSD request, the - * DOMrequest 'success' event means that the RIL has successfully processed - * and sent the USSD request to the network. The network reply will be - * reported via 'onussdreceived' event. If the MMI code is not associated to - * a USSD but to other RIL request its result, if one is needed, will be - * notified via the returned DOMRequest 'success' or 'error' event. - */ - [Throws, CheckPermissions="mobileconnection"] - DOMRequest sendMMI(DOMString mmi); - - /** - * Cancel the current MMI request if one exists. - * - * @return a DOMRequest. - * - * If successful, the request's onsuccess will be called. And the request's - * result will be an object containing information about the operation. - * @see MozMMIResult for the detail of result. - * - * Otherwise, the request's onerror will be called, and the request's error - * will be a DOMMMIError. - * @see DOMMMIError for the detail of error. - */ - [Throws, CheckPermissions="mobileconnection"] - DOMRequest cancelMMI(); - /** * Configures call forward options. * @@ -522,12 +479,6 @@ interface MozMobileConnection : EventTarget */ attribute EventHandler ondatachange; - /** - * The 'ussdreceived' event is notified whenever a new USSD message is - * received. - */ - attribute EventHandler onussdreceived; - /** * The 'dataerror' event is notified whenever the data connection object * receives an error from the RIL. diff --git a/dom/webidl/USSDReceivedEvent.webidl b/dom/webidl/USSDReceivedEvent.webidl index 627beb3712d4..5583ec795ee8 100644 --- a/dom/webidl/USSDReceivedEvent.webidl +++ b/dom/webidl/USSDReceivedEvent.webidl @@ -5,7 +5,7 @@ */ [Pref="dom.telephony.enabled", - CheckPermissions="telephony mobileconnection", + CheckPermissions="telephony", AvailableIn="CertifiedApps", Constructor(DOMString type, optional USSDReceivedEventInit eventInitDict)] interface USSDReceivedEvent : Event @@ -13,7 +13,6 @@ interface USSDReceivedEvent : Event readonly attribute unsigned long serviceId; readonly attribute DOMString? message; readonly attribute USSDSession? session; // null if session is ended. - readonly attribute boolean sessionEnded; // deprecated. Bug 1070831 }; dictionary USSDReceivedEventInit : EventInit @@ -21,5 +20,4 @@ dictionary USSDReceivedEventInit : EventInit unsigned long serviceId = 0; DOMString? message = null; USSDSession? session = null; - boolean sessionEnded = false; }; From f5ea5521535c027c37bc8df120070b69f8bc1c36 Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Sun, 21 Dec 2014 17:30:00 +0100 Subject: [PATCH 26/64] Bug 1070831 - Part 2: Clean up the DOM implementation. r=aknow --- dom/mobileconnection/MobileConnection.cpp | 63 ------- dom/mobileconnection/MobileConnection.h | 7 - .../MobileConnectionCallback.cpp | 175 +----------------- .../MobileConnectionCallback.h | 3 - 4 files changed, 2 insertions(+), 246 deletions(-) diff --git a/dom/mobileconnection/MobileConnection.cpp b/dom/mobileconnection/MobileConnection.cpp index 95b79d38973e..a94310893493 100644 --- a/dom/mobileconnection/MobileConnection.cpp +++ b/dom/mobileconnection/MobileConnection.cpp @@ -11,7 +11,6 @@ #include "mozilla/dom/MozEmergencyCbModeEvent.h" #include "mozilla/dom/MozOtaStatusEvent.h" #include "mozilla/dom/ToJSValue.h" -#include "mozilla/dom/USSDReceivedEvent.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsIDOMDOMRequest.h" @@ -592,48 +591,6 @@ MobileConnection::GetVoicePrivacyMode(ErrorResult& aRv) return request.forget(); } -already_AddRefed -MobileConnection::SendMMI(const nsAString& aMMIString, ErrorResult& aRv) -{ - if (!mMobileConnection) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - nsRefPtr request = new DOMRequest(GetOwner()); - nsRefPtr requestCallback = - new MobileConnectionCallback(GetOwner(), request); - - nsresult rv = mMobileConnection->SendMMI(aMMIString, requestCallback); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return nullptr; - } - - return request.forget(); -} - -already_AddRefed -MobileConnection::CancelMMI(ErrorResult& aRv) -{ - if (!mMobileConnection) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - nsRefPtr request = new DOMRequest(GetOwner()); - nsRefPtr requestCallback = - new MobileConnectionCallback(GetOwner(), request); - - nsresult rv = mMobileConnection->CancelMMI(requestCallback); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return nullptr; - } - - return request.forget(); -} - already_AddRefed MobileConnection::GetCallForwardingOption(uint16_t aReason, ErrorResult& aRv) { @@ -990,26 +947,6 @@ MobileConnection::NotifyDataChanged() return DispatchTrustedEvent(NS_LITERAL_STRING("datachange")); } -NS_IMETHODIMP -MobileConnection::NotifyUssdReceived(const nsAString& aMessage, - bool aSessionEnded) -{ - if (!CheckPermission("mobileconnection")) { - return NS_OK; - } - - USSDReceivedEventInit init; - init.mBubbles = false; - init.mCancelable = false; - init.mMessage = aMessage; - init.mSessionEnded = aSessionEnded; - - nsRefPtr event = - USSDReceivedEvent::Constructor(this, NS_LITERAL_STRING("ussdreceived"), init); - - return DispatchTrustedEvent(event); -} - NS_IMETHODIMP MobileConnection::NotifyDataError(const nsAString& aMessage) { diff --git a/dom/mobileconnection/MobileConnection.h b/dom/mobileconnection/MobileConnection.h index ba0aa1274d91..c639cc524f0d 100644 --- a/dom/mobileconnection/MobileConnection.h +++ b/dom/mobileconnection/MobileConnection.h @@ -107,12 +107,6 @@ public: already_AddRefed GetVoicePrivacyMode(ErrorResult& aRv); - already_AddRefed - SendMMI(const nsAString& aMmi, ErrorResult& aRv); - - already_AddRefed - CancelMMI(ErrorResult& aRv); - already_AddRefed SetCallForwardingOption(const MozCallForwardingOptions& aOptions, ErrorResult& aRv); @@ -150,7 +144,6 @@ public: IMPL_EVENT_HANDLER(voicechange) IMPL_EVENT_HANDLER(datachange) - IMPL_EVENT_HANDLER(ussdreceived) IMPL_EVENT_HANDLER(dataerror) IMPL_EVENT_HANDLER(cfstatechange) IMPL_EVENT_HANDLER(emergencycbmodechange) diff --git a/dom/mobileconnection/MobileConnectionCallback.cpp b/dom/mobileconnection/MobileConnectionCallback.cpp index d2ba2c1b938e..bc0d9cc9dd8f 100644 --- a/dom/mobileconnection/MobileConnectionCallback.cpp +++ b/dom/mobileconnection/MobileConnectionCallback.cpp @@ -4,7 +4,6 @@ #include "MobileConnectionCallback.h" -#include "mozilla/dom/DOMMMIError.h" #include "mozilla/dom/MobileNetworkInfo.h" #include "mozilla/dom/MozMobileConnectionBinding.h" #include "mozilla/dom/ToJSValue.h" @@ -31,28 +30,6 @@ MobileConnectionCallback::MobileConnectionCallback(nsPIDOMWindow* aWindow, { } -/** - * Notify Success for Send/CancelMmi. - */ -nsresult -MobileConnectionCallback::NotifySendCancelMmiSuccess(const MozMMIResult& aResult) -{ - AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(mWindow))) { - return NS_ERROR_FAILURE; - } - - JSContext* cx = jsapi.cx(); - JS::Rooted jsResult(cx); - - if (!ToJSValue(cx, aResult, &jsResult)) { - JS_ClearPendingException(cx); - return NS_ERROR_TYPE_ERR; - } - - return NotifySuccess(jsResult); -} - /** * Notify Success. */ @@ -130,131 +107,6 @@ MobileConnectionCallback::NotifyGetNetworksSuccess(uint32_t aCount, return NotifySuccess(jsResult); } -nsresult -MobileConnectionCallback::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, - const nsAString& aStatusMessage) -{ - MozMMIResult result; - result.mServiceCode.Assign(aServiceCode); - result.mStatusMessage.Assign(aStatusMessage); - - return NotifySendCancelMmiSuccess(result); -} - -nsresult -MobileConnectionCallback::NotifySendCancelMmiSuccessWithInteger(const nsAString& aServiceCode, - const nsAString& aStatusMessage, - uint16_t aAdditionalInformation) -{ - MozMMIResult result; - result.mServiceCode.Assign(aServiceCode); - result.mStatusMessage.Assign(aStatusMessage); - result.mAdditionalInformation.Construct().SetAsUnsignedShort() = aAdditionalInformation; - - return NotifySendCancelMmiSuccess(result); -} - -nsresult -MobileConnectionCallback::NotifySendCancelMmiSuccessWithStrings(const nsAString& aServiceCode, - const nsAString& aStatusMessage, - uint32_t aCount, - const char16_t** aAdditionalInformation) -{ - AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(mWindow))) { - return NS_ERROR_FAILURE; - } - - JSContext* cx = jsapi.cx(); - RootedDictionary result(cx); - - result.mServiceCode.Assign(aServiceCode); - result.mStatusMessage.Assign(aStatusMessage); - - nsTArray additionalInformation; - for (uint32_t i = 0; i < aCount; i++) { - additionalInformation.AppendElement(nsDependentString(aAdditionalInformation[i])); - } - - JS::Rooted jsAdditionalInformation(cx); - if (!ToJSValue(cx, additionalInformation, &jsAdditionalInformation)) { - JS_ClearPendingException(cx); - return NS_ERROR_TYPE_ERR; - } - - result.mAdditionalInformation.Construct().SetAsObject() = - &jsAdditionalInformation.toObject(); - - return NotifySendCancelMmiSuccess(result); -} - -nsresult -MobileConnectionCallback::NotifySendCancelMmiSuccessWithCallForwardingOptions( - const nsAString& aServiceCode, - const nsAString& aStatusMessage, - uint32_t aCount, - nsIMobileCallForwardingOptions** aResults) -{ - AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(mWindow))) { - return NS_ERROR_FAILURE; - } - - JSContext* cx = jsapi.cx(); - RootedDictionary result(cx); - - result.mServiceCode.Assign(aServiceCode); - result.mStatusMessage.Assign(aStatusMessage); - - nsTArray additionalInformation; - for (uint32_t i = 0; i < aCount; i++) - { - MozCallForwardingOptions options; - int16_t pShort; - nsString pString; - bool pBool; - - aResults[i]->GetActive(&pBool); - options.mActive.Construct(pBool); - - aResults[i]->GetAction(&pShort); - if (pShort != nsIMobileConnection::CALL_FORWARD_ACTION_UNKNOWN) { - options.mAction.Construct(pShort); - } - - aResults[i]->GetReason(&pShort); - if (pShort != nsIMobileConnection::CALL_FORWARD_REASON_UNKNOWN) { - options.mReason.Construct(pShort); - } - - aResults[i]->GetNumber(pString); - options.mNumber.Construct(pString.get()); - - aResults[i]->GetTimeSeconds(&pShort); - if (pShort >= 0) { - options.mTimeSeconds.Construct(pShort); - } - - aResults[i]->GetServiceClass(&pShort); - if (pShort != nsIMobileConnection::ICC_SERVICE_CLASS_NONE) { - options.mServiceClass.Construct(pShort); - } - - additionalInformation.AppendElement(options); - } - - JS::Rooted jsAdditionalInformation(cx); - if (!ToJSValue(cx, additionalInformation, &jsAdditionalInformation)) { - JS_ClearPendingException(cx); - return NS_ERROR_TYPE_ERR; - } - - result.mAdditionalInformation.Construct().SetAsObject() = - &jsAdditionalInformation.toObject(); - - return NotifySendCancelMmiSuccess(result); -} - NS_IMETHODIMP MobileConnectionCallback::NotifyGetCallForwardingSuccess(uint32_t aCount, nsIMobileCallForwardingOptions** aResults) @@ -384,34 +236,11 @@ MobileConnectionCallback::NotifyGetRoamingPreferenceSuccess(int32_t aMode) }; NS_IMETHODIMP -MobileConnectionCallback::NotifyError(const nsAString& aName, - const nsAString& aMessage, - const nsAString& aServiceCode, - uint16_t aInfo, - uint8_t aArgc) +MobileConnectionCallback::NotifyError(const nsAString& aName) { nsCOMPtr rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID); NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE); - - nsRefPtr error; - switch (aArgc) { - case 0: - return rs->FireErrorAsync(mRequest, aName); - case 1: - error = new DOMMMIError(mWindow, aName, aMessage, EmptyString(), - Nullable()); - return rs->FireDetailedError(mRequest, error); - case 2: - error = new DOMMMIError(mWindow, aName, aMessage, aServiceCode, - Nullable()); - return rs->FireDetailedError(mRequest, error); - case 3: - error = new DOMMMIError(mWindow, aName, aMessage, aServiceCode, - Nullable(int16_t(aInfo))); - return rs->FireDetailedError(mRequest, error); - } - - return NS_ERROR_FAILURE; + return rs->FireErrorAsync(mRequest, aName); } } // namespace mobileconnection diff --git a/dom/mobileconnection/MobileConnectionCallback.h b/dom/mobileconnection/MobileConnectionCallback.h index 739c04f278d9..33f5eedcfd26 100644 --- a/dom/mobileconnection/MobileConnectionCallback.h +++ b/dom/mobileconnection/MobileConnectionCallback.h @@ -41,9 +41,6 @@ private: nsresult NotifySuccessWithString(const nsAString& aResult); - nsresult - NotifySendCancelMmiSuccess(const MozMMIResult& aResult); - nsCOMPtr mWindow; nsRefPtr mRequest; }; From f44de82087701f8ccea511071d9d8e2e679423e5 Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Sun, 21 Dec 2014 17:31:00 +0100 Subject: [PATCH 27/64] Bug 1070831 - Part 3: Internal interface changes. r=aknow --- .../gonk/nsIGonkMobileConnectionService.idl | 6 +- .../gonk/nsIMobileConnectionMessenger.idl | 16 +-- .../interfaces/nsIMobileConnectionService.idl | 105 +----------------- dom/telephony/nsIGonkTelephonyService.idl | 5 +- dom/telephony/nsITelephonyMessenger.idl | 16 ++- 5 files changed, 22 insertions(+), 126 deletions(-) diff --git a/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl b/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl index 017f506b4563..6bc9002523b5 100644 --- a/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl +++ b/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl @@ -9,7 +9,7 @@ "@mozilla.org/mobileconnection/gonkmobileconnectionservice;1" %} -[scriptable, uuid(eae40ffe-394a-4355-8e0b-07170d3e70f4)] +[scriptable, uuid(ef49b866-85a0-11e4-b023-f73e02752840)] interface nsIGonkMobileConnectionService : nsIMobileConnectionService { void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo); @@ -29,10 +29,6 @@ interface nsIGonkMobileConnectionService : nsIMobileConnectionService void notifyRadioStateChanged(in unsigned long clientId, in long radioState); - void notifyUssdReceived(in unsigned long clientId, - in DOMString message, - in boolean sessionEnded); - void notifyEmergencyCallbackModeChanged(in unsigned long clientId, in boolean active, in unsigned long timeoutMs); diff --git a/dom/mobileconnection/gonk/nsIMobileConnectionMessenger.idl b/dom/mobileconnection/gonk/nsIMobileConnectionMessenger.idl index 7337771a69b2..9fb7d5a52716 100644 --- a/dom/mobileconnection/gonk/nsIMobileConnectionMessenger.idl +++ b/dom/mobileconnection/gonk/nsIMobileConnectionMessenger.idl @@ -4,23 +4,9 @@ #include "nsISupports.idl" -[scriptable, uuid(fd2fa95c-5b54-11e4-bc6b-6f3bffb681cd)] +[scriptable, uuid(b9ec941e-8504-11e4-810e-7b62c60e8261)] interface nsIMobileConnectionMessenger : nsISupports { - /** - * 'ussd-received' system message - * - * @param aServiceId - * The ID of Service where this info is notified from. - * @param aMessage - * USSD Message to be displayed. - * @param aSessionEnded - * True if USSD session is ended. - */ - void notifyUssdReceived(in unsigned long aServiceId, - in DOMString aMessage, - in boolean aSessionEnded); - /** * 'cdma-info-rec-received' system message with Display Info * diff --git a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl index 1fc169404974..31cd17c0e890 100644 --- a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl +++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl @@ -12,7 +12,7 @@ interface nsIMobileNetworkInfo; interface nsINeighboringCellIdsCallback; interface nsIVariant; -[scriptable, uuid(c00abd30-5b2e-11e4-8ed6-0800200c9a66)] +[scriptable, uuid(6e6468a4-84fb-11e4-9b66-17dbe13c059e)] interface nsIMobileConnectionListener : nsISupports { /** @@ -25,17 +25,6 @@ interface nsIMobileConnectionListener : nsISupports */ void notifyDataChanged(); - /** - * Notify when ussd is received. - * - * @param message - * The ussd request in string format. - * @param sessionEnded - * Indicates whether the session is ended. - */ - void notifyUssdReceived(in DOMString message, - in boolean sessionEnded); - /** * Notify when data call is failed to establish. * @@ -124,7 +113,7 @@ interface nsIMobileConnectionListener : nsISupports #define NO_ADDITIONAL_INFORMATION 0 %} -[scriptable, builtinclass, uuid(16e77f19-0298-46de-ae49-9b2fb92a28c0)] +[scriptable, builtinclass, uuid(14d66926-8434-11e4-8c3f-f724194bb5f1)] interface nsIMobileConnectionCallback : nsISupports { /** @@ -137,27 +126,9 @@ interface nsIMobileConnectionCallback : nsISupports void notifyGetNetworksSuccess(in uint32_t count, [array, size_is(count)] in nsIMobileNetworkInfo networks); - void notifySendCancelMmiSuccess(in DOMString aServiceCode, - in DOMString aStatusMessage); - - void notifySendCancelMmiSuccessWithInteger(in DOMString aServiceCode, - in DOMString aStatusMessage, - in unsigned short aAdditionalInformation); - - void notifySendCancelMmiSuccessWithStrings(in DOMString aServiceCode, - in DOMString aStatusMessage, - in unsigned long aLength, - [array, size_is(aLength)] in wstring aAdditionalInformation); - - void notifySendCancelMmiSuccessWithCallForwardingOptions(in DOMString aServiceCode, - in DOMString aStatusMessage, - in unsigned long aLength, - [array, size_is(aLength)] in nsIMobileCallForwardingOptions aAdditionalInformation); - void notifyGetCallForwardingSuccess(in uint32_t count, [array, size_is(count)] in nsIMobileCallForwardingOptions results); - void notifyGetCallBarringSuccess(in unsigned short program, in boolean enabled, in unsigned short serviceClass); @@ -171,45 +142,7 @@ interface nsIMobileConnectionCallback : nsISupports /** * notifyError() will be called, when request is failed. */ - [optional_argc] - void notifyError(in DOMString name, - [optional] in DOMString message, - [optional] in DOMString serviceCode, - [optional] in unsigned short additionalInformation); - -%{C++ - // non-virtual so it won't affect the vtable - inline nsresult NotifyError(const nsAString& aName) - { - return NotifyError(aName, EmptyString(), EmptyString(), - NO_ADDITIONAL_INFORMATION, 0 /* ARGC = 0 */); - } - // non-virtual so it won't affect the vtable - inline nsresult NotifyError(const nsAString& aName, - const nsAString& aMessage) - { - return NotifyError(aName, aMessage, EmptyString(), NO_ADDITIONAL_INFORMATION, - 1 /* ARGC = 1 */); - } - // non-virtual so it won't affect the vtable - inline nsresult NotifyError(const nsAString& aName, - const nsAString& aMessage, - const nsAString& aServiceCode) - { - return NotifyError(aName, aMessage, aServiceCode, NO_ADDITIONAL_INFORMATION, - 2 /* ARGC = 2 */); - } - // non-virtual so it won't affect the vtable - inline nsresult NotifyError(const nsAString& aName, - const nsAString& aMessage, - const nsAString& aServiceCode, - uint16_t aAdditionInformation) - { - return NotifyError(aName, aMessage, aServiceCode, aAdditionInformation, - 3 /* ARGC = 3 */); - } -%} - + void notifyError(in DOMString name); }; %{C++ @@ -235,7 +168,7 @@ already_AddRefed NS_CreateMobileConnectionService(); %} -[scriptable, uuid(99e43353-5fc4-497e-88a2-5fa6862ee64c)] +[scriptable, uuid(2b3d0122-8054-11e4-964e-c727f38fd7e6)] interface nsIMobileConnection : nsISupports { /* @@ -549,36 +482,6 @@ interface nsIMobileConnection : nsISupports */ void getVoicePrivacyMode(in nsIMobileConnectionCallback requestCallback); - /** - * Send a MMI message. - * - * @param mmi - * DOMString containing an MMI string that can be associated to a - * USSD request or other RIL functionality. - * @param requestCallback - * Called when request is finished. - * - * If successful, the notifySendCancelMmiSuccess*() will be called. And the - * result will contain the information about the mmi operation. - * - * Otherwise, the notifyError() will be called. - */ - void sendMMI(in DOMString mmi, - in nsIMobileConnectionCallback requestCallback); - - /** - * Cancel the current MMI request if one exists. - * - * @param requestCallback - * Called when request is finished. - * - * If successful, the notifySendCancelMmiSuccess*() will be called. And the - * result will contain the information about the mmi operation. - * - * Otherwise, the notifyError() will be called. - */ - void cancelMMI(in nsIMobileConnectionCallback requestCallback); - /** * Queries current call forwarding options. * diff --git a/dom/telephony/nsIGonkTelephonyService.idl b/dom/telephony/nsIGonkTelephonyService.idl index 7dd72d481647..269f8304ed11 100644 --- a/dom/telephony/nsIGonkTelephonyService.idl +++ b/dom/telephony/nsIGonkTelephonyService.idl @@ -10,7 +10,7 @@ "@mozilla.org/telephony/gonktelephonyservice;1" %} -[scriptable, uuid(068d7bf2-1773-48ef-95f8-bd835115fed7)] +[scriptable, uuid(cbbe66d8-865b-11e4-94f1-ab441e55905b)] interface nsIGonkTelephonyService : nsITelephonyService { void notifyAudioStateChanged(in unsigned long clientId, in short state); @@ -31,7 +31,4 @@ interface nsIGonkTelephonyService : nsITelephonyService void notifyUssdReceived(in unsigned long clientId, in DOMString message, in boolean sessionEnded); - - void dialMMI(in unsigned long clientId, in AString mmiString, - in nsITelephonyDialCallback callback); }; diff --git a/dom/telephony/nsITelephonyMessenger.idl b/dom/telephony/nsITelephonyMessenger.idl index 1ce9d2440415..a7b269af4402 100644 --- a/dom/telephony/nsITelephonyMessenger.idl +++ b/dom/telephony/nsITelephonyMessenger.idl @@ -4,7 +4,7 @@ #include "nsISupports.idl" -[scriptable, uuid(998a48b2-5b54-11e4-833e-6b17c1427d49)] +[scriptable, uuid(84045b7e-84fb-11e4-a94c-5ba58d0d5932)] interface nsITelephonyMessenger : nsISupports { /** @@ -37,4 +37,18 @@ interface nsITelephonyMessenger : nsISupports in unsigned long aDuration, in boolean aOutgoing, in boolean aHangUpLocal); + + /** + * 'ussd-received' system message + * + * @param aServiceId + * The ID of Service where this info is notified from. + * @param aMessage + * USSD Message to be displayed. + * @param aSessionEnded + * True if USSD session is ended. + */ + void notifyUssdReceived(in unsigned long aServiceId, + in DOMString aMessage, + in boolean aSessionEnded); }; \ No newline at end of file From 7aee759ba2b3e72a4ee7a49d4c2a91a917b321be Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Sun, 21 Dec 2014 17:35:00 +0100 Subject: [PATCH 28/64] Bug 1070831 - Part 4: Internal architecture changes. r=aknow --- .../gonk/MobileConnectionService.js | 88 ------------------- dom/system/gonk/RILSystemMessengerHelper.js | 8 +- dom/system/gonk/ril_worker.js | 2 +- dom/telephony/gonk/TelephonyService.js | 16 +--- 4 files changed, 9 insertions(+), 105 deletions(-) diff --git a/dom/mobileconnection/gonk/MobileConnectionService.js b/dom/mobileconnection/gonk/MobileConnectionService.js index 726d3b898104..7e99be187e16 100644 --- a/dom/mobileconnection/gonk/MobileConnectionService.js +++ b/dom/mobileconnection/gonk/MobileConnectionService.js @@ -27,8 +27,6 @@ const MOBILECELLINFO_CID = Components.ID("{0635d9ab-997e-4cdf-84e7-c1883752dff3}"); const MOBILECALLFORWARDINGOPTIONS_CID = Components.ID("{e0cf4463-ee63-4b05-ab2e-d94bf764836c}"); -const TELEPHONYDIALCALLBACK_CID = - Components.ID("{c2af1a5d-3649-44ef-a1ff-18e9ac1dec51}"); const NEIGHBORINGCELLINFO_CID = Components.ID("{6078cbf1-f34c-44fa-96f8-11a88d4bfdd3}"); const GSMCELLINFO_CID = @@ -280,62 +278,6 @@ CdmaCellInfo.prototype = { evdoSnr: INT32_MAX }; -/** - * Wrap a MobileConnectionCallback to a TelephonyDialCallback. - */ -function TelephonyDialCallback(aCallback) { - this.callback = aCallback; -} -TelephonyDialCallback.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyDialCallback]), - classID: TELEPHONYDIALCALLBACK_CID, - - notifyDialMMI: function(mmiServiceCode) { - this.serviceCode = mmiServiceCode; - }, - - notifyDialMMISuccess: function(statusMessage) { - this.callback.notifySendCancelMmiSuccess(this.serviceCode, statusMessage); - }, - - notifyDialMMISuccessWithInteger: function(statusMessage, additionalInfo) { - this.callback.notifySendCancelMmiSuccessWithInteger(this.serviceCode, - statusMessage, - additionalInfo); - }, - - notifyDialMMISuccessWithStrings: function(statusMessage, count, additionalInfo) { - this.callback.notifySendCancelMmiSuccessWithStrings(this.serviceCode, - statusMessage, - count, - additionalInfo); - }, - - notifyDialMMISuccessWithCallForwardingOptions: function(statusMessage, count, additionalInfo) { - this.callback.notifySendCancelMmiSuccessWithCallForwardingOptions( - this.serviceCode, - statusMessage, - count, - additionalInfo); - }, - - notifyDialMMIError: function(error) { - this.callback.notifyError(error, "", this.serviceCode); - }, - - notifyDialMMIErrorWithInfo: function(error, info) { - this.callback.notifyError(error, "", this.serviceCode, info); - }, - - notifyDialError: function() { - throw Cr.NS_ERROR_UNEXPECTED; - }, - - notifyDialSuccess: function() { - throw Cr.NS_ERROR_UNEXPECTED; - }, -}; - function MobileConnectionProvider(aClientId, aRadioInterface) { this._clientId = aClientId; this._radioInterface = aRadioInterface; @@ -833,24 +775,6 @@ MobileConnectionProvider.prototype = { }).bind(this)); }, - sendMMI: function(aMmi, aCallback) { - let callback = new TelephonyDialCallback(aCallback); - gGonkTelephonyService.dialMMI(this._clientId, aMmi, callback); - }, - - cancelMMI: function(aCallback) { - this._radioInterface.sendWorkerMessage("cancelUSSD", null, - (function(aResponse) { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - return false; - } - - aCallback.notifySuccess(); - return false; - }).bind(this)); - }, - setCallForwarding: function(aAction, aReason, aNumber, aTimeSeconds, aServiceClass, aCallback) { let options = { @@ -1190,18 +1114,6 @@ MobileConnectionService.prototype = { this.getItemByServiceId(aClientId).updateDataInfo(aDataInfo); }, - notifyUssdReceived: function(aClientId, aMessage, aSessionEnded) { - if (DEBUG) { - debug("notifyUssdReceived for " + aClientId + ": " + - aMessage + " (sessionEnded : " + aSessionEnded + ")"); - } - - gMobileConnectionMessenger.notifyUssdReceived(aClientId, aMessage, aSessionEnded); - - this.getItemByServiceId(aClientId) - .deliverListenerEvent("notifyUssdReceived", [aMessage, aSessionEnded]); - }, - notifyDataError: function(aClientId, aMessage) { if (DEBUG) { debug("notifyDataError for " + aClientId + ": " + aMessage); diff --git a/dom/system/gonk/RILSystemMessengerHelper.js b/dom/system/gonk/RILSystemMessengerHelper.js index 7411fb6e8c87..89b4006663b6 100644 --- a/dom/system/gonk/RILSystemMessengerHelper.js +++ b/dom/system/gonk/RILSystemMessengerHelper.js @@ -73,6 +73,10 @@ RILSystemMessengerHelper.prototype = { aDuration, aOutgoing, aHangUpLocal); }, + notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) { + this.messenger.notifyUssdReceived(aServiceId, aMessage, aSessionEnded); + }, + /** * nsISmsMessenger API */ @@ -100,10 +104,6 @@ RILSystemMessengerHelper.prototype = { /** * nsIMobileConnectionMessenger API */ - notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) { - this.messenger.notifyUssdReceived(aServiceId, aMessage, aSessionEnded); - }, - notifyCdmaInfoRecDisplay: function(aServiceId, aDisplay) { this.messenger.notifyCdmaInfoRecDisplay(aServiceId, aDisplay); }, diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 33e3c4e2b010..a25ef11be526 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -2655,7 +2655,7 @@ RilObject.prototype = { options.ussd = mmi.fullMMI; - if (options.startNewSession && this._ussdSession) { + if (this._ussdSession) { if (DEBUG) this.context.debug("Cancel existing ussd session."); this.cachedUSSDRequest = options; this.cancelUSSD({}); diff --git a/dom/telephony/gonk/TelephonyService.js b/dom/telephony/gonk/TelephonyService.js index 77d3e4684bc0..ac5040fc7c76 100644 --- a/dom/telephony/gonk/TelephonyService.js +++ b/dom/telephony/gonk/TelephonyService.js @@ -566,7 +566,7 @@ TelephonyService.prototype = { return; } - this._dialMMI(aClientId, mmi, aCallback, true); + this._dialMMI(aClientId, mmi, aCallback); } } }, @@ -664,15 +664,14 @@ TelephonyService.prototype = { * @param aStartNewSession * True to start a new session for ussd request. */ - _dialMMI: function(aClientId, aMmi, aCallback, aStartNewSession) { + _dialMMI: function(aClientId, aMmi, aCallback) { let mmiServiceCode = aMmi ? this._serviceCodeToKeyString(aMmi.serviceCode) : RIL.MMI_KS_SC_USSD; aCallback.notifyDialMMI(mmiServiceCode); this._sendToRilWorker(aClientId, "sendMMI", - { mmi: aMmi, - startNewSession: aStartNewSession }, response => { + { mmi: aMmi }, response => { if (DEBUG) debug("MMI response: " + JSON.stringify(response)); if (!response.success) { @@ -1304,13 +1303,7 @@ TelephonyService.prototype = { aMessage + " (sessionEnded : " + aSessionEnded + ")"); } - gGonkMobileConnectionService.notifyUssdReceived(aClientId, aMessage, - aSessionEnded); - }, - - dialMMI: function(aClientId, aMmiString, aCallback) { - let mmi = this._parseMMI(aMmiString, this._hasCalls(aClientId)); - this._dialMMI(aClientId, mmi, aCallback, false); + gTelephonyMessenger.notifyUssdReceived(aClientId, aMessage, aSessionEnded); }, /** @@ -1357,7 +1350,6 @@ USSDReceivedWrapper.prototype = { let event = new aWindow.USSDReceivedEvent("ussdreceived", { serviceId: aMessage.serviceId, message: aMessage.message, - sessionEnded: aMessage.sessionEnded, session: session }); From eb5db1064e2041aea0cf177cc2b0deba64a7907a Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Sun, 21 Dec 2014 17:35:00 +0100 Subject: [PATCH 29/64] Bug 1070831 - Part 5: Clean up the related IPC files. r=aknow --- .../ipc/MobileConnectionChild.cpp | 109 ------------------ .../ipc/MobileConnectionChild.h | 10 -- .../ipc/MobileConnectionParent.cpp | 105 +---------------- .../ipc/MobileConnectionParent.h | 6 - .../ipc/PMobileConnection.ipdl | 12 -- .../ipc/PMobileConnectionRequest.ipdl | 17 --- 6 files changed, 3 insertions(+), 256 deletions(-) diff --git a/dom/mobileconnection/ipc/MobileConnectionChild.cpp b/dom/mobileconnection/ipc/MobileConnectionChild.cpp index a970079ac83c..d052e36c2896 100644 --- a/dom/mobileconnection/ipc/MobileConnectionChild.cpp +++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp @@ -222,20 +222,6 @@ MobileConnectionChild::GetVoicePrivacyMode(nsIMobileConnectionCallback* aCallbac ? NS_OK : NS_ERROR_FAILURE; } -NS_IMETHODIMP -MobileConnectionChild::SendMMI(const nsAString& aMmi, - nsIMobileConnectionCallback* aCallback) -{ - return SendRequest(SendMmiRequest(nsAutoString(aMmi)), aCallback) - ? NS_OK : NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -MobileConnectionChild::CancelMMI(nsIMobileConnectionCallback* aCallback) -{ - return SendRequest(CancelMmiRequest(), aCallback) ? NS_OK : NS_ERROR_FAILURE; -} - NS_IMETHODIMP MobileConnectionChild::SetCallForwarding(uint16_t aAction, uint16_t aReason, const nsAString& aNumber, @@ -415,17 +401,6 @@ MobileConnectionChild::RecvNotifyDataInfoChanged(nsIMobileConnectionInfo* const& return true; } -bool -MobileConnectionChild::RecvNotifyUssdReceived(const nsString& aMessage, - const bool& aSessionEnd) -{ - for (int32_t i = 0; i < mListeners.Count(); i++) { - mListeners[i]->NotifyUssdReceived(aMessage, aSessionEnd); - } - - return true; -} - bool MobileConnectionChild::RecvNotifyDataError(const nsString& aMessage) { @@ -568,60 +543,6 @@ MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessNetworks const_cast(aReply.results().Elements()))); } -bool -MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessMmi& aReply) -{ - nsAutoString serviceCode(aReply.serviceCode()); - nsAutoString statusMessage(aReply.statusMessage()); - AdditionalInformation info(aReply.additionalInformation()); - - // Handle union types - switch (info.type()) { - case AdditionalInformation::Tvoid_t: - return NS_SUCCEEDED(mRequestCallback->NotifySendCancelMmiSuccess(serviceCode, - statusMessage)); - - case AdditionalInformation::Tuint16_t: - return NS_SUCCEEDED(mRequestCallback->NotifySendCancelMmiSuccessWithInteger( - serviceCode, statusMessage, info.get_uint16_t())); - - case AdditionalInformation::TArrayOfnsString: { - uint32_t count = info.get_ArrayOfnsString().Length(); - const nsTArray& additionalInformation = info.get_ArrayOfnsString(); - - nsAutoArrayPtr additionalInfoPtrs(new const char16_t*[count]); - for (size_t i = 0; i < count; ++i) { - additionalInfoPtrs[i] = additionalInformation[i].get(); - } - - return NS_SUCCEEDED(mRequestCallback->NotifySendCancelMmiSuccessWithStrings( - serviceCode, statusMessage, count, additionalInfoPtrs)); - } - - case AdditionalInformation::TArrayOfnsMobileCallForwardingOptions: { - uint32_t count = info.get_ArrayOfnsMobileCallForwardingOptions().Length(); - - nsTArray> results; - for (uint32_t i = 0; i < count; i++) { - // Use dont_AddRef here because these instances are already AddRef-ed in - // MobileConnectionIPCSerializer.h - nsCOMPtr item = dont_AddRef( - info.get_ArrayOfnsMobileCallForwardingOptions()[i]); - results.AppendElement(item); - } - - return NS_SUCCEEDED(mRequestCallback->NotifySendCancelMmiSuccessWithCallForwardingOptions( - serviceCode, statusMessage, count, - const_cast(info.get_ArrayOfnsMobileCallForwardingOptions().Elements()))); - } - - default: - MOZ_CRASH("Received invalid type!"); - } - - return false; -} - bool MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessCallForwarding& aReply) { @@ -671,32 +592,6 @@ MobileConnectionRequestChild::DoReply(const MobileConnectionReplyError& aReply) return NS_SUCCEEDED(mRequestCallback->NotifyError(aReply.message())); } -bool -MobileConnectionRequestChild::DoReply(const MobileConnectionReplyErrorMmi& aReply) -{ - nsAutoString name(aReply.name()); - nsAutoString message(aReply.message()); - nsAutoString serviceCode(aReply.serviceCode()); - AdditionalInformation info(aReply.additionalInformation()); - - // Handle union types - switch (info.type()) { - case AdditionalInformation::Tuint16_t: - return NS_SUCCEEDED(mRequestCallback->NotifyError(name, - message, - serviceCode, - info.get_uint16_t())); - case AdditionalInformation::Tvoid_t: - default: - // If additionInfomation is not uint16_t, handle it as void_t. - return NS_SUCCEEDED(mRequestCallback->NotifyError(name, - message, - serviceCode)); - } - - return false; -} - bool MobileConnectionRequestChild::Recv__delete__(const MobileConnectionReply& aReply) { @@ -709,8 +604,6 @@ MobileConnectionRequestChild::Recv__delete__(const MobileConnectionReply& aReply return DoReply(aReply.get_MobileConnectionReplySuccessBoolean()); case MobileConnectionReply::TMobileConnectionReplySuccessNetworks: return DoReply(aReply.get_MobileConnectionReplySuccessNetworks()); - case MobileConnectionReply::TMobileConnectionReplySuccessMmi: - return DoReply(aReply.get_MobileConnectionReplySuccessMmi()); case MobileConnectionReply::TMobileConnectionReplySuccessCallForwarding: return DoReply(aReply.get_MobileConnectionReplySuccessCallForwarding()); case MobileConnectionReply::TMobileConnectionReplySuccessCallBarring: @@ -723,8 +616,6 @@ MobileConnectionRequestChild::Recv__delete__(const MobileConnectionReply& aReply return DoReply(aReply.get_MobileConnectionReplySuccessRoamingPreference()); case MobileConnectionReply::TMobileConnectionReplyError: return DoReply(aReply.get_MobileConnectionReplyError()); - case MobileConnectionReply::TMobileConnectionReplyErrorMmi: - return DoReply(aReply.get_MobileConnectionReplyErrorMmi()); default: MOZ_CRASH("Received invalid response type!"); } diff --git a/dom/mobileconnection/ipc/MobileConnectionChild.h b/dom/mobileconnection/ipc/MobileConnectionChild.h index 5a01f16d4107..d861ea6d4ac8 100644 --- a/dom/mobileconnection/ipc/MobileConnectionChild.h +++ b/dom/mobileconnection/ipc/MobileConnectionChild.h @@ -69,10 +69,6 @@ protected: virtual bool RecvNotifyDataInfoChanged(nsIMobileConnectionInfo* const& aInfo) MOZ_OVERRIDE; - virtual bool - RecvNotifyUssdReceived(const nsString& aMessage, - const bool& aSessionEnd) MOZ_OVERRIDE; - virtual bool RecvNotifyDataError(const nsString& aMessage) MOZ_OVERRIDE; @@ -148,9 +144,6 @@ public: bool DoReply(const MobileConnectionReplySuccessNetworks& aReply); - bool - DoReply(const MobileConnectionReplySuccessMmi& aReply); - bool DoReply(const MobileConnectionReplySuccessCallForwarding& aReply); @@ -169,9 +162,6 @@ public: bool DoReply(const MobileConnectionReplyError& aReply); - bool - DoReply(const MobileConnectionReplyErrorMmi& aReply); - protected: virtual ~MobileConnectionRequestChild() diff --git a/dom/mobileconnection/ipc/MobileConnectionParent.cpp b/dom/mobileconnection/ipc/MobileConnectionParent.cpp index cb2416883f99..83c3ff34208c 100644 --- a/dom/mobileconnection/ipc/MobileConnectionParent.cpp +++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp @@ -67,10 +67,6 @@ MobileConnectionParent::RecvPMobileConnectionRequestConstructor(PMobileConnectio return actor->DoRequest(aRequest.get_SetVoicePrivacyModeRequest()); case MobileConnectionRequest::TGetVoicePrivacyModeRequest: return actor->DoRequest(aRequest.get_GetVoicePrivacyModeRequest()); - case MobileConnectionRequest::TSendMmiRequest: - return actor->DoRequest(aRequest.get_SendMmiRequest()); - case MobileConnectionRequest::TCancelMmiRequest: - return actor->DoRequest(aRequest.get_CancelMmiRequest()); case MobileConnectionRequest::TSetCallForwardingRequest: return actor->DoRequest(aRequest.get_SetCallForwardingRequest()); case MobileConnectionRequest::TGetCallForwardingRequest: @@ -192,16 +188,6 @@ MobileConnectionParent::NotifyDataChanged() return SendNotifyDataInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE; } -NS_IMETHODIMP -MobileConnectionParent::NotifyUssdReceived(const nsAString& aMessage, - bool aSessionEnded) -{ - NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); - - return SendNotifyUssdReceived(nsAutoString(aMessage), aSessionEnded) - ? NS_OK : NS_ERROR_FAILURE; -} - NS_IMETHODIMP MobileConnectionParent::NotifyDataError(const nsAString& aMessage) { @@ -399,22 +385,6 @@ MobileConnectionRequestParent::DoRequest(const GetVoicePrivacyModeRequest& aRequ return NS_SUCCEEDED(mMobileConnection->GetVoicePrivacyMode(this)); } -bool -MobileConnectionRequestParent::DoRequest(const SendMmiRequest& aRequest) -{ - NS_ENSURE_TRUE(mMobileConnection, false); - - return NS_SUCCEEDED(mMobileConnection->SendMMI(aRequest.mmi(), this)); -} - -bool -MobileConnectionRequestParent::DoRequest(const CancelMmiRequest& aRequest) -{ - NS_ENSURE_TRUE(mMobileConnection, false); - - return NS_SUCCEEDED(mMobileConnection->CancelMMI(this)); -} - bool MobileConnectionRequestParent::DoRequest(const SetCallForwardingRequest& aRequest) { @@ -556,57 +526,6 @@ MobileConnectionRequestParent::NotifyGetNetworksSuccess(uint32_t aCount, return SendReply(MobileConnectionReplySuccessNetworks(networks)); } -NS_IMETHODIMP -MobileConnectionRequestParent::NotifySendCancelMmiSuccess(const nsAString& aServiceCode, - const nsAString& aStatusMessage) -{ - return SendReply(MobileConnectionReplySuccessMmi(nsString(aServiceCode), - nsString(aStatusMessage), - AdditionalInformation(mozilla::void_t()))); -} - -NS_IMETHODIMP -MobileConnectionRequestParent::NotifySendCancelMmiSuccessWithInteger(const nsAString& aServiceCode, - const nsAString& aStatusMessage, - uint16_t aAdditionalInformation) -{ - return SendReply(MobileConnectionReplySuccessMmi(nsString(aServiceCode), - nsString(aStatusMessage), - AdditionalInformation(aAdditionalInformation))); -} - -NS_IMETHODIMP -MobileConnectionRequestParent::NotifySendCancelMmiSuccessWithStrings(const nsAString& aServiceCode, - const nsAString& aStatusMessage, - uint32_t aCount, - const char16_t** aAdditionalInformation) -{ - nsTArray additionalInformation; - for (uint32_t i = 0; i < aCount; i++) { - additionalInformation.AppendElement(nsDependentString(aAdditionalInformation[i])); - } - - return SendReply(MobileConnectionReplySuccessMmi(nsString(aServiceCode), - nsString(aStatusMessage), - AdditionalInformation(additionalInformation))); -} - -NS_IMETHODIMP -MobileConnectionRequestParent::NotifySendCancelMmiSuccessWithCallForwardingOptions(const nsAString& aServiceCode, - const nsAString& aStatusMessage, - uint32_t aCount, - nsIMobileCallForwardingOptions** aAdditionalInformation) -{ - nsTArray additionalInformation; - for (uint32_t i = 0; i < aCount; i++) { - additionalInformation.AppendElement(aAdditionalInformation[i]); - } - - return SendReply(MobileConnectionReplySuccessMmi(nsString(aServiceCode), - nsString(aStatusMessage), - AdditionalInformation(additionalInformation))); -} - NS_IMETHODIMP MobileConnectionRequestParent::NotifyGetCallForwardingSuccess(uint32_t aCount, nsIMobileCallForwardingOptions** aResults) @@ -648,26 +567,8 @@ MobileConnectionRequestParent::NotifyGetRoamingPreferenceSuccess(int32_t aMode) } NS_IMETHODIMP -MobileConnectionRequestParent::NotifyError(const nsAString& aName, - const nsAString& aMessage, - const nsAString& aServiceCode, - uint16_t aInfo, - uint8_t aArgc) +MobileConnectionRequestParent::NotifyError(const nsAString& aName) { - if (aArgc == 0) { - nsAutoString error(aName); - return SendReply(MobileConnectionReplyError(error)); - } - - nsAutoString name(aName); - nsAutoString message(aMessage); - nsAutoString serviceCode(aServiceCode); - - if (aArgc < 3) { - return SendReply(MobileConnectionReplyErrorMmi(name, message, serviceCode, - AdditionalInformation(mozilla::void_t()))); - } - - return SendReply(MobileConnectionReplyErrorMmi(name, message, serviceCode, - AdditionalInformation(aInfo))); + nsAutoString error(aName); + return SendReply(MobileConnectionReplyError(error)); } diff --git a/dom/mobileconnection/ipc/MobileConnectionParent.h b/dom/mobileconnection/ipc/MobileConnectionParent.h index 7f9a7c09dd7e..5e78d35d29d7 100644 --- a/dom/mobileconnection/ipc/MobileConnectionParent.h +++ b/dom/mobileconnection/ipc/MobileConnectionParent.h @@ -111,12 +111,6 @@ public: bool DoRequest(const GetVoicePrivacyModeRequest& aRequest); - bool - DoRequest(const SendMmiRequest& aRequest); - - bool - DoRequest(const CancelMmiRequest& aRequest); - bool DoRequest(const SetCallForwardingRequest& aRequest); diff --git a/dom/mobileconnection/ipc/PMobileConnection.ipdl b/dom/mobileconnection/ipc/PMobileConnection.ipdl index 41feaafd93d3..7281931d31c7 100644 --- a/dom/mobileconnection/ipc/PMobileConnection.ipdl +++ b/dom/mobileconnection/ipc/PMobileConnection.ipdl @@ -20,7 +20,6 @@ sync protocol PMobileConnection child: NotifyVoiceInfoChanged(nsMobileConnectionInfo aInfo); NotifyDataInfoChanged(nsMobileConnectionInfo aInfo); - NotifyUssdReceived(nsString aMessage, bool aSessionEnd); NotifyDataError(nsString aMessage); NotifyCFStateChanged(uint16_t aAction, uint16_t aReason, nsString aNumber, uint16_t aTimeSeconds, uint16_t aServiceClass); @@ -97,15 +96,6 @@ struct GetVoicePrivacyModeRequest { }; -struct SendMmiRequest -{ - nsString mmi; -}; - -struct CancelMmiRequest -{ -}; - struct SetCallForwardingRequest { uint16_t action; @@ -179,8 +169,6 @@ union MobileConnectionRequest GetRoamingPreferenceRequest; SetVoicePrivacyModeRequest; GetVoicePrivacyModeRequest; - SendMmiRequest; - CancelMmiRequest; SetCallForwardingRequest; GetCallForwardingRequest; SetCallBarringRequest; diff --git a/dom/mobileconnection/ipc/PMobileConnectionRequest.ipdl b/dom/mobileconnection/ipc/PMobileConnectionRequest.ipdl index 2c54373e82dd..ce7ed401bf78 100644 --- a/dom/mobileconnection/ipc/PMobileConnectionRequest.ipdl +++ b/dom/mobileconnection/ipc/PMobileConnectionRequest.ipdl @@ -40,13 +40,6 @@ struct MobileConnectionReplySuccessNetworks nsMobileNetworkInfo[] results; }; -struct MobileConnectionReplySuccessMmi -{ - nsString serviceCode; - nsString statusMessage; - AdditionalInformation additionalInformation; -}; - struct MobileConnectionReplySuccessCallForwarding { nsMobileCallForwardingOptions[] results; @@ -81,21 +74,12 @@ struct MobileConnectionReplyError nsString message; }; -struct MobileConnectionReplyErrorMmi -{ - nsString name; - nsString message; - nsString serviceCode; - AdditionalInformation additionalInformation; -}; - union MobileConnectionReply { // Success MobileConnectionReplySuccess; MobileConnectionReplySuccessBoolean; MobileConnectionReplySuccessNetworks; - MobileConnectionReplySuccessMmi; MobileConnectionReplySuccessCallForwarding; MobileConnectionReplySuccessCallBarring; MobileConnectionReplySuccessClirStatus; @@ -103,7 +87,6 @@ union MobileConnectionReply MobileConnectionReplySuccessRoamingPreference; // Error MobileConnectionReplyError; - MobileConnectionReplyErrorMmi; }; } // namespace mobileconnection From 42d775afdae967c4d85af95abcaa601b2a29210d Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Sun, 21 Dec 2014 17:37:00 +0100 Subject: [PATCH 30/64] Bug 1070831 - Part 6: Clean up BluetoothRilListener. r=btian --- dom/bluetooth/BluetoothRilListener.cpp | 7 ------- dom/bluetooth2/BluetoothRilListener.cpp | 7 ------- 2 files changed, 14 deletions(-) diff --git a/dom/bluetooth/BluetoothRilListener.cpp b/dom/bluetooth/BluetoothRilListener.cpp index 650d3c533e65..998337954873 100644 --- a/dom/bluetooth/BluetoothRilListener.cpp +++ b/dom/bluetooth/BluetoothRilListener.cpp @@ -101,13 +101,6 @@ MobileConnectionListener::NotifyDataChanged() return NS_OK; } -NS_IMETHODIMP -MobileConnectionListener::NotifyUssdReceived(const nsAString & message, - bool sessionEnded) -{ - return NS_OK; -} - NS_IMETHODIMP MobileConnectionListener::NotifyDataError(const nsAString & message) { diff --git a/dom/bluetooth2/BluetoothRilListener.cpp b/dom/bluetooth2/BluetoothRilListener.cpp index 650d3c533e65..998337954873 100644 --- a/dom/bluetooth2/BluetoothRilListener.cpp +++ b/dom/bluetooth2/BluetoothRilListener.cpp @@ -101,13 +101,6 @@ MobileConnectionListener::NotifyDataChanged() return NS_OK; } -NS_IMETHODIMP -MobileConnectionListener::NotifyUssdReceived(const nsAString & message, - bool sessionEnded) -{ - return NS_OK; -} - NS_IMETHODIMP MobileConnectionListener::NotifyDataError(const nsAString & message) { From 8f624173470bc53caa08adb007f3a09ff4a11ed9 Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Sun, 21 Dec 2014 17:38:00 +0100 Subject: [PATCH 31/64] Bug 1070831 - Part 7: Update related testcases. r=aknow --- .../tests/marionette/manifest.ini | 4 - .../tests/marionette/test_mobile_mmi.js | 46 ------ .../test_mobile_mmi_call_forwarding.js | 144 ------------------ .../marionette/test_mobile_mmi_change_pin.js | 111 -------------- .../test_mobileconnection_permission.html | 2 - .../test_mobilenetwork_permission.html | 2 - 6 files changed, 309 deletions(-) delete mode 100644 dom/mobileconnection/tests/marionette/test_mobile_mmi.js delete mode 100644 dom/mobileconnection/tests/marionette/test_mobile_mmi_call_forwarding.js delete mode 100644 dom/mobileconnection/tests/marionette/test_mobile_mmi_change_pin.js diff --git a/dom/mobileconnection/tests/marionette/manifest.ini b/dom/mobileconnection/tests/marionette/manifest.ini index dea9c104d0ae..ba36f1acf242 100644 --- a/dom/mobileconnection/tests/marionette/manifest.ini +++ b/dom/mobileconnection/tests/marionette/manifest.ini @@ -14,10 +14,6 @@ qemu = true [test_mobile_data_connection.js] [test_mobile_data_location.js] [test_mobile_data_state.js] -[test_mobile_mmi.js] -[test_mobile_mmi_change_pin.js] -[test_mobile_mmi_call_forwarding.js] -[test_mobile_mmi_unlock_puk.js] [test_mobile_roaming_preference.js] [test_call_barring_get_option.js] [test_call_barring_set_error.js] diff --git a/dom/mobileconnection/tests/marionette/test_mobile_mmi.js b/dom/mobileconnection/tests/marionette/test_mobile_mmi.js deleted file mode 100644 index c1424d0e1c93..000000000000 --- a/dom/mobileconnection/tests/marionette/test_mobile_mmi.js +++ /dev/null @@ -1,46 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -function testGettingIMEI() { - log("Test *#06# ..."); - - let MMI_CODE = "*#06#"; - return sendMMI(MMI_CODE) - .then(function resolve(aResult) { - ok(true, MMI_CODE + " success"); - is(aResult.serviceCode, "scImei", "Service code IMEI"); - // IMEI is hardcoded as "000000000000000". - // See it here {B2G_HOME}/external/qemu/telephony/android_modem.c - // (The result of +CGSN). - is(aResult.statusMessage, "000000000000000", "Emulator IMEI"); - is(aResult.additionalInformation, undefined, "No additional information"); - }, function reject() { - ok(false, MMI_CODE + " should not fail"); - }); -} - -function testInvalidMMICode() { - log("Test invalid MMI code ..."); - - let MMI_CODE = "InvalidMMICode"; - return sendMMI(MMI_CODE) - .then(function resolve() { - ok(false, MMI_CODE + " should not success"); - }, function reject(aError) { - ok(true, MMI_CODE + " fail"); - is(aError.name, "emMmiError", "MMI error name"); - is(aError.message, "", "No message"); - is(aError.serviceCode, "scUssd", "Service code USSD"); - is(aError.additionalInformation, null, "No additional information"); - }); -} - -// Start test -startTestCommon(function() { - return Promise.resolve() - .then(() => testGettingIMEI()) - .then(() => testInvalidMMICode()); -}); diff --git a/dom/mobileconnection/tests/marionette/test_mobile_mmi_call_forwarding.js b/dom/mobileconnection/tests/marionette/test_mobile_mmi_call_forwarding.js deleted file mode 100644 index 594fcc3a05a5..000000000000 --- a/dom/mobileconnection/tests/marionette/test_mobile_mmi_call_forwarding.js +++ /dev/null @@ -1,144 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -const TEST_DATA = [ - { - reason: MozMobileConnection.CALL_FORWARD_REASON_UNCONDITIONAL, - number: "+886912345678", - serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE, - timeSeconds: 5 - }, { - reason: MozMobileConnection.CALL_FORWARD_REASON_MOBILE_BUSY, - number: "0912345678", - serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE, - timeSeconds: 10 - }, { - reason: MozMobileConnection.CALL_FORWARD_REASON_NO_REPLY, - number: "+886987654321", - serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE, - timeSeconds: 15 - }, { - reason: MozMobileConnection.CALL_FORWARD_REASON_NOT_REACHABLE, - number: "+0987654321", - serviceClass: MozMobileConnection.ICC_SERVICE_CLASS_VOICE, - timeSeconds: 20 - } -]; - -// Please see TS 22.030 Annex B -const CF_REASON_TO_MMI = { - /* CALL_FORWARD_REASON_UNCONDITIONAL */ - 0: "21", - /* CALL_FORWARD_REASON_MOBILE_BUSY */ - 1: "67", - /* CALL_FORWARD_REASON_NO_REPLY */ - 2: "61", - /* CALL_FORWARD_REASON_NOT_REACHABLE */ - 3: "62", - /* CALL_FORWARD_REASON_ALL_CALL_FORWARDING */ - 4: "002", - /* CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING */ - 5: "004" -}; - -// Please see TS 22.030 Annex C -const SERVICE_CLASS_TO_MMI = { - /* ICC_SERVICE_CLASS_VOICE */ - 1: "11" -}; - -function testSetCallForwarding(aData) { - // Registration: **SC*SIA*SIB*SIC# - let MMI_CODE = "**" + CF_REASON_TO_MMI[aData.reason] + "*" + aData.number + - "*" + SERVICE_CLASS_TO_MMI[aData.serviceClass] + - "*" + aData.timeSeconds + "#"; - log("Test " + MMI_CODE); - - let promises = []; - // Check cfstatechange event. - promises.push(waitForManagerEvent("cfstatechange").then(function(aEvent) { - is(aEvent.action, MozMobileConnection.CALL_FORWARD_ACTION_REGISTRATION, - "check action"); - is(aEvent.reason, aData.reason, "check reason"); - is(aEvent.number, aData.number, "check number"); - is(aEvent.timeSeconds, aData.timeSeconds, "check timeSeconds"); - is(aEvent.serviceClass, aData.serviceClass, "check serviceClass"); - })); - // Check DOMRequest's result. - promises.push(sendMMI(MMI_CODE) - .then(function resolve(aResult) { - is(aResult.serviceCode, "scCallForwarding", "Check service code"); - is(aResult.statusMessage, "smServiceRegistered", "Check status message"); - is(aResult.additionalInformation, undefined, "Check additional information"); - }, function reject(aError) { - ok(false, "got '" + aError.name + "' error"); - })); - - return Promise.all(promises); -} - -function testGetCallForwarding(aExpectedData) { - // Interrogation: *#SC# - let MMI_CODE = "*#" + CF_REASON_TO_MMI[aExpectedData.reason] + "#"; - log("Test " + MMI_CODE); - - return sendMMI(MMI_CODE) - .then(function resolve(aResult) { - is(aResult.serviceCode, "scCallForwarding", "Check service code"); - is(aResult.statusMessage, "smServiceInterrogated", "Check status message"); - is(Array.isArray(aResult.additionalInformation), true, - "additionalInformation should be an array"); - - for (let i = 0; i < aResult.additionalInformation.length; i++) { - let result = aResult.additionalInformation[i]; - - // Only need to check the result containing the serviceClass that we are - // interested in. - if (!(result.serviceClass & aExpectedData.serviceClass)) { - continue; - } - - is(result.active, true, "check active"); - is(result.reason, aExpectedData.reason, "check reason"); - is(result.number, aExpectedData.number, "check number"); - is(result.timeSeconds, aExpectedData.timeSeconds, "check timeSeconds"); - } - }, function reject(aError) { - ok(false, MMI_CODE + " got error: " + aError.name); - }); -} - -function clearAllCallForwardingSettings() { - log("Clear all call forwarding settings"); - - let promise = Promise.resolve(); - for (let reason = MozMobileConnection.CALL_FORWARD_REASON_UNCONDITIONAL; - reason <= MozMobileConnection.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING; - reason++) { - let options = { - reason: reason, - action: MozMobileConnection.CALL_FORWARD_ACTION_ERASURE - }; - // Emulator doesn't support CALL_FORWARD_REASON_ALL_* yet, we catch the - // reject here in order to avoid impact the test result. - promise = - promise.then(() => setCallForwardingOption(options).then(null, () => {})); - } - return promise; -} - -// Start tests -startTestCommon(function() { - let promise = Promise.resolve(); - for (let i = 0; i < TEST_DATA.length; i++) { - let data = TEST_DATA[i]; - promise = promise.then(() => testSetCallForwarding(data)) - .then(() => testGetCallForwarding(data)); - } - // reset call forwarding settings. - return promise.then(null, () => { ok(false, "promise reject during test"); }) - .then(() => clearAllCallForwardingSettings()); -}); diff --git a/dom/mobileconnection/tests/marionette/test_mobile_mmi_change_pin.js b/dom/mobileconnection/tests/marionette/test_mobile_mmi_change_pin.js deleted file mode 100644 index 13fe3e19e158..000000000000 --- a/dom/mobileconnection/tests/marionette/test_mobile_mmi_change_pin.js +++ /dev/null @@ -1,111 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -// PIN is hardcoded as "0000" by default. -// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c, -// in asimcard_create(). -const TEST_DATA = [ - // Test passing no pin. - { - pin: "", - newPin: "0000", - newPinAgain: "1111", - expectedError: { - name: "emMmiError", - additionalInformation: null - } - }, - // Test passing no newPin. - { - pin: "0000", - newPin: "", - newPinAgain: "", - expectedError: { - name: "emMmiError", - additionalInformation: null - } - }, - // Test passing mismatched newPin. - { - pin: "0000", - newPin: "0000", - newPinAgain: "1111", - expectedError: { - name: "emMmiErrorMismatchPin", - additionalInformation: null - } - }, - // Test passing invalid pin (< 4 digit). - { - pin: "000", - newPin: "0000", - newPinAgain: "0000", - expectedError: { - name: "emMmiErrorInvalidPin", - additionalInformation: null - } - }, - // Test passing invalid newPin (> 8 digit). - { - pin: "0000", - newPin: "000000000", - newPinAgain: "000000000", - expectedError: { - name: "emMmiErrorInvalidPin", - additionalInformation: null - } - }, - // Test passing incorrect pin. - { - pin: "1234", - newPin: "0000", - newPinAgain: "0000", - expectedError: { - name: "emMmiErrorBadPin", - // The default pin retries is 3, failed once becomes to 2 - additionalInformation: 2 - } - }, - // Test changing pin successfully (Reset the retries). - { - pin: "0000", - newPin: "0000", - newPinAgain: "0000" - } -]; - -function testChangePin(aPin, aNewPin, aNewPinAgain, aExpectedError) { - let MMI_CODE = "**04*" + aPin + "*" + aNewPin + "*" + aNewPinAgain + "#"; - log("Test " + MMI_CODE); - - return sendMMI(MMI_CODE) - .then(function resolve(aResult) { - ok(!aExpectedError, MMI_CODE + " success"); - is(aResult.serviceCode, "scPin", "Check service code"); - is(aResult.statusMessage, "smPinChanged", "Check status message"); - is(aResult.additionalInformation, undefined, "Check additional information"); - }, function reject(aError) { - ok(aExpectedError, MMI_CODE + " fail"); - is(aError.name, aExpectedError.name, "Check name"); - is(aError.message, "", "Check message"); - is(aError.serviceCode, "scPin", "Check service code"); - is(aError.additionalInformation, aExpectedError.additionalInformation, - "Chech additional information"); - }); -} - -// Start test -startTestCommon(function() { - let promise = Promise.resolve(); - for (let i = 0; i < TEST_DATA.length; i++) { - let data = TEST_DATA[i]; - promise = promise.then(() => testChangePin(data.pin, - data.newPin, - data.newPinAgain, - data.expectedError)); - } - return promise; -}); diff --git a/dom/mobileconnection/tests/mochitest/test_mobileconnection_permission.html b/dom/mobileconnection/tests/mochitest/test_mobileconnection_permission.html index 89b055982a86..ba69674b65f7 100644 --- a/dom/mobileconnection/tests/mochitest/test_mobileconnection_permission.html +++ b/dom/mobileconnection/tests/mochitest/test_mobileconnection_permission.html @@ -49,8 +49,6 @@ if (!SpecialPowers.hasPermission("mobileconnection", document)) { is("getRoamingPreference" in mobileConnection, true, "getRoamingPreference"); is("setVoicePrivacyMode" in mobileConnection, true, "setVoicePrivacyMode"); is("getVoicePrivacyMode" in mobileConnection, true, "getVoicePrivacyMode"); - is("sendMMI" in mobileConnection, true, "sendMMI"); - is("cancelMMI" in mobileConnection, true, "cancelMMI"); is("setCallForwardingOption" in mobileConnection, true, "setCallForwardingOption"); is("getCallForwardingOption" in mobileConnection, true, "getCallForwardingOption"); is("setCallBarringOption" in mobileConnection, true, "setCallBarringOption"); diff --git a/dom/mobileconnection/tests/mochitest/test_mobilenetwork_permission.html b/dom/mobileconnection/tests/mochitest/test_mobilenetwork_permission.html index 0e8b94be6009..386d1ce93f8c 100644 --- a/dom/mobileconnection/tests/mochitest/test_mobilenetwork_permission.html +++ b/dom/mobileconnection/tests/mochitest/test_mobilenetwork_permission.html @@ -49,8 +49,6 @@ if (!SpecialPowers.hasPermission("mobilenetwork", document)) { is("getRoamingPreference" in mobileConnection, false, "getRoamingPreference"); is("setVoicePrivacyMode" in mobileConnection, false, "setVoicePrivacyMode"); is("getVoicePrivacyMode" in mobileConnection, false, "getVoicePrivacyMode"); - is("sendMMI" in mobileConnection, false, "sendMMI"); - is("cancelMMI" in mobileConnection, false, "cancelMMI"); is("setCallForwardingOption" in mobileConnection, false, "setCallForwardingOption"); is("getCallForwardingOption" in mobileConnection, false, "getCallForwardingOption"); is("setCallBarringOption" in mobileConnection, false, "setCallBarringOption"); From 1e1e033d3408e602f33038f3dd6d361cc003fe68 Mon Sep 17 00:00:00 2001 From: Alexandre Lissy Date: Wed, 17 Dec 2014 07:49:00 +0100 Subject: [PATCH 32/64] Bug 1093108 - Do not overwrite pre-existing logs. r=gwagner Simply rely on OS.File.makeDir() and gracefully fail instead of overwriting pre-existing user data. --- b2g/components/LogShake.jsm | 63 ++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/b2g/components/LogShake.jsm b/b2g/components/LogShake.jsm index 7fd4a0fd494c..2da6506ed8b0 100644 --- a/b2g/components/LogShake.jsm +++ b/b2g/components/LogShake.jsm @@ -262,12 +262,16 @@ function getSdcardPrefix() { return volumeService.getVolumeByName('sdcard').mountPoint; } +function getLogDirectoryRoot() { + return 'logs'; +} + function getLogDirectory() { let d = new Date(); d = new Date(d.getTime() - d.getTimezoneOffset() * 60000); let timestamp = d.toISOString().slice(0, -5).replace(/[:T]/g, '-'); // return directory name of format 'logs/timestamp/' - return OS.Path.join('logs', timestamp); + return timestamp; } /** @@ -281,9 +285,10 @@ function saveLogs(logArrays) { }); } - let sdcardPrefix, dirName; + let sdcardPrefix, dirNameRoot, dirName; try { sdcardPrefix = getSdcardPrefix(); + dirNameRoot = getLogDirectoryRoot(); dirName = getLogDirectory(); } catch(e) { // Return promise failed with exception e @@ -291,33 +296,39 @@ function saveLogs(logArrays) { return Promise.reject(e); } - debug('making a directory all the way from '+sdcardPrefix+' to '+(sdcardPrefix + '/' + dirName)); - return OS.File.makeDir(OS.Path.join(sdcardPrefix, dirName), {from: sdcardPrefix}) - .then(function() { - // Now the directory is guaranteed to exist, save the logs - let logFilenames = []; - let saveRequests = []; + debug('making a directory all the way from '+sdcardPrefix+' to '+(sdcardPrefix + '/' + dirNameRoot + '/' + dirName)); + let logsRoot = OS.Path.join(sdcardPrefix, dirNameRoot); + return OS.File.makeDir(logsRoot, {from: sdcardPrefix}).then( + function() { + let logsDir = OS.Path.join(logsRoot, dirName); + return OS.File.makeDir(logsDir, {ignoreExisting: false}).then( + function() { + // Now the directory is guaranteed to exist, save the logs + let logFilenames = []; + let saveRequests = []; - for (let logLocation in logArrays) { - debug('requesting save of ' + logLocation); - let logArray = logArrays[logLocation]; - // The filename represents the relative path within the SD card, not the - // absolute path because Gaia will refer to it using the DeviceStorage - // API - let filename = OS.Path.join(dirName, getLogFilename(logLocation)); - logFilenames.push(filename); - let saveRequest = OS.File.writeAtomic(OS.Path.join(sdcardPrefix, filename), logArray); - saveRequests.push(saveRequest); - } + for (let logLocation in logArrays) { + debug('requesting save of ' + logLocation); + let logArray = logArrays[logLocation]; + // The filename represents the relative path within the SD card, not the + // absolute path because Gaia will refer to it using the DeviceStorage + // API + let filename = OS.Path.join(dirNameRoot, dirName, getLogFilename(logLocation)); + logFilenames.push(filename); + let saveRequest = OS.File.writeAtomic(OS.Path.join(sdcardPrefix, filename), logArray); + saveRequests.push(saveRequest); + } - return Promise.all(saveRequests).then(function() { - debug('returning logfilenames: '+logFilenames.toSource()); - return { - logFilenames: logFilenames, - logPrefix: dirName - }; + return Promise.all(saveRequests).then( + function() { + debug('returning logfilenames: '+logFilenames.toSource()); + return { + logFilenames: logFilenames, + logPrefix: OS.Path.join(dirNameRoot, dirName) + }; + }); + }); }); - }); } LogShake.init(); From eabfa84986accf034917d63f0c452db0547ae952 Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Wed, 17 Dec 2014 18:26:00 +0100 Subject: [PATCH 33/64] Bug 1098970 - Part 1: Add new LL native files. r=sotaro Copied from aosp/framework/native/gui. --- .../GonkBufferQueueLL/BufferItem.cpp | 192 ++++ .../GonkBufferQueueLL/BufferItem.h | 103 ++ .../GonkBufferQueueLL/BufferQueue.cpp | 79 ++ .../GonkBufferQueueLL/BufferQueue.h | 88 ++ .../GonkBufferQueueLL/BufferQueueConsumer.cpp | 523 ++++++++++ .../GonkBufferQueueLL/BufferQueueConsumer.h | 181 ++++ .../GonkBufferQueueLL/BufferQueueCore.cpp | 238 +++++ .../GonkBufferQueueLL/BufferQueueCore.h | 253 +++++ .../GonkBufferQueueLL/BufferQueueDefs.h | 35 + .../GonkBufferQueueLL/BufferQueueProducer.cpp | 982 ++++++++++++++++++ .../GonkBufferQueueLL/BufferQueueProducer.h | 204 ++++ .../GonkBufferQueueLL/BufferSlot.cpp | 31 + .../GonkBufferQueueLL/BufferSlot.h | 142 +++ .../GonkBufferQueueLL/ConsumerBase.cpp | 269 +++++ .../GonkBufferQueueLL/ConsumerBase.h | 241 +++++ .../IGraphicBufferConsumer.cpp | 553 ++++++++++ .../IGraphicBufferConsumer.h | 327 ++++++ 17 files changed, 4441 insertions(+) create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp create mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp new file mode 100644 index 000000000000..d3fa43e75f08 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp @@ -0,0 +1,192 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include + +namespace android { + +BufferItem::BufferItem() : + mTransform(0), + mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mTimestamp(0), + mIsAutoTimestamp(false), + mFrameNumber(0), + mSlot(INVALID_BUFFER_SLOT), + mIsDroppable(false), + mAcquireCalled(false), + mTransformToDisplayInverse(false) { + mCrop.makeInvalid(); +} + +BufferItem::operator IGraphicBufferConsumer::BufferItem() const { + IGraphicBufferConsumer::BufferItem bufferItem; + bufferItem.mGraphicBuffer = mGraphicBuffer; + bufferItem.mFence = mFence; + bufferItem.mCrop = mCrop; + bufferItem.mTransform = mTransform; + bufferItem.mScalingMode = mScalingMode; + bufferItem.mTimestamp = mTimestamp; + bufferItem.mIsAutoTimestamp = mIsAutoTimestamp; + bufferItem.mFrameNumber = mFrameNumber; + bufferItem.mBuf = mSlot; + bufferItem.mIsDroppable = mIsDroppable; + bufferItem.mAcquireCalled = mAcquireCalled; + bufferItem.mTransformToDisplayInverse = mTransformToDisplayInverse; + return bufferItem; +} + +size_t BufferItem::getPodSize() const { + size_t c = sizeof(mCrop) + + sizeof(mTransform) + + sizeof(mScalingMode) + + sizeof(mTimestamp) + + sizeof(mIsAutoTimestamp) + + sizeof(mFrameNumber) + + sizeof(mSlot) + + sizeof(mIsDroppable) + + sizeof(mAcquireCalled) + + sizeof(mTransformToDisplayInverse); + return c; +} + +size_t BufferItem::getFlattenedSize() const { + size_t c = 0; + if (mGraphicBuffer != 0) { + c += mGraphicBuffer->getFlattenedSize(); + FlattenableUtils::align<4>(c); + } + if (mFence != 0) { + c += mFence->getFlattenedSize(); + FlattenableUtils::align<4>(c); + } + return sizeof(int32_t) + c + getPodSize(); +} + +size_t BufferItem::getFdCount() const { + size_t c = 0; + if (mGraphicBuffer != 0) { + c += mGraphicBuffer->getFdCount(); + } + if (mFence != 0) { + c += mFence->getFdCount(); + } + return c; +} + +status_t BufferItem::flatten( + void*& buffer, size_t& size, int*& fds, size_t& count) const { + + // make sure we have enough space + if (count < BufferItem::getFlattenedSize()) { + return NO_MEMORY; + } + + // content flags are stored first + uint32_t& flags = *static_cast(buffer); + + // advance the pointer + FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); + + flags = 0; + if (mGraphicBuffer != 0) { + status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + flags |= 1; + } + if (mFence != 0) { + status_t err = mFence->flatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + flags |= 2; + } + + // check we have enough space (in case flattening the fence/graphicbuffer lied to us) + if (size < getPodSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, mCrop); + FlattenableUtils::write(buffer, size, mTransform); + FlattenableUtils::write(buffer, size, mScalingMode); + FlattenableUtils::write(buffer, size, mTimestamp); + FlattenableUtils::write(buffer, size, mIsAutoTimestamp); + FlattenableUtils::write(buffer, size, mFrameNumber); + FlattenableUtils::write(buffer, size, mSlot); + FlattenableUtils::write(buffer, size, mIsDroppable); + FlattenableUtils::write(buffer, size, mAcquireCalled); + FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); + + return NO_ERROR; +} + +status_t BufferItem::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) { + + if (size < sizeof(uint32_t)) + return NO_MEMORY; + + uint32_t flags = 0; + FlattenableUtils::read(buffer, size, flags); + + if (flags & 1) { + mGraphicBuffer = new GraphicBuffer(); + status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + } + + if (flags & 2) { + mFence = new Fence(); + status_t err = mFence->unflatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + } + + // check we have enough space + if (size < getPodSize()) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, mCrop); + FlattenableUtils::read(buffer, size, mTransform); + FlattenableUtils::read(buffer, size, mScalingMode); + FlattenableUtils::read(buffer, size, mTimestamp); + FlattenableUtils::read(buffer, size, mIsAutoTimestamp); + FlattenableUtils::read(buffer, size, mFrameNumber); + FlattenableUtils::read(buffer, size, mSlot); + FlattenableUtils::read(buffer, size, mIsDroppable); + FlattenableUtils::read(buffer, size, mAcquireCalled); + FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); + + return NO_ERROR; +} + +const char* BufferItem::scalingModeName(uint32_t scalingMode) { + switch (scalingMode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; + default: return "Unknown"; + } +} + +} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h new file mode 100644 index 000000000000..5effd10e04cf --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h @@ -0,0 +1,103 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERITEM_H +#define ANDROID_GUI_BUFFERITEM_H + +#include +#include + +#include + +#include + +#include +#include + +namespace android { + +class Fence; +class GraphicBuffer; + +class BufferItem : public Flattenable { + friend class Flattenable; + size_t getPodSize() const; + size_t getFlattenedSize() const; + size_t getFdCount() const; + status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; + status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + + public: + // The default value of mBuf, used to indicate this doesn't correspond to a slot. + enum { INVALID_BUFFER_SLOT = -1 }; + BufferItem(); + operator IGraphicBufferConsumer::BufferItem() const; + + static const char* scalingModeName(uint32_t scalingMode); + + // mGraphicBuffer points to the buffer allocated for this slot, or is NULL + // if the buffer in this slot has been acquired in the past (see + // BufferSlot.mAcquireCalled). + sp mGraphicBuffer; + + // mFence is a fence that will signal when the buffer is idle. + sp mFence; + + // mCrop is the current crop rectangle for this buffer slot. + Rect mCrop; + + // mTransform is the current transform flags for this buffer slot. + // refer to NATIVE_WINDOW_TRANSFORM_* in + uint32_t mTransform; + + // mScalingMode is the current scaling mode for this buffer slot. + // refer to NATIVE_WINDOW_SCALING_* in + uint32_t mScalingMode; + + // mTimestamp is the current timestamp for this buffer slot. This gets + // to set by queueBuffer each time this slot is queued. This value + // is guaranteed to be monotonically increasing for each newly + // acquired buffer. + int64_t mTimestamp; + + // mIsAutoTimestamp indicates whether mTimestamp was generated + // automatically when the buffer was queued. + bool mIsAutoTimestamp; + + // mFrameNumber is the number of the queued frame for this slot. + uint64_t mFrameNumber; + + // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). + int mSlot; + + // mIsDroppable whether this buffer was queued with the + // property that it can be replaced by a new buffer for the purpose of + // making sure dequeueBuffer() won't block. + // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer + // was queued. + bool mIsDroppable; + + // Indicates whether this buffer has been seen by a consumer yet + bool mAcquireCalled; + + // Indicates this buffer must be transformed by the inverse transform of the screen + // it is displayed onto. This is applied after mTransform. + bool mTransformToDisplayInverse; +}; + +} // namespace android + +#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp new file mode 100644 index 000000000000..c49a8868f0f7 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BufferQueue" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include + +namespace android { + +BufferQueue::ProxyConsumerListener::ProxyConsumerListener( + const wp& consumerListener): + mConsumerListener(consumerListener) {} + +BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} + +void BufferQueue::ProxyConsumerListener::onFrameAvailable() { + sp listener(mConsumerListener.promote()); + if (listener != NULL) { + listener->onFrameAvailable(); + } +} + +void BufferQueue::ProxyConsumerListener::onBuffersReleased() { + sp listener(mConsumerListener.promote()); + if (listener != NULL) { + listener->onBuffersReleased(); + } +} + +void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { + sp listener(mConsumerListener.promote()); + if (listener != NULL) { + listener->onSidebandStreamChanged(); + } +} + +void BufferQueue::createBufferQueue(sp* outProducer, + sp* outConsumer, + const sp& allocator) { + LOG_ALWAYS_FATAL_IF(outProducer == NULL, + "BufferQueue: outProducer must not be NULL"); + LOG_ALWAYS_FATAL_IF(outConsumer == NULL, + "BufferQueue: outConsumer must not be NULL"); + + sp core(new BufferQueueCore(allocator)); + LOG_ALWAYS_FATAL_IF(core == NULL, + "BufferQueue: failed to create BufferQueueCore"); + + sp producer(new BufferQueueProducer(core)); + LOG_ALWAYS_FATAL_IF(producer == NULL, + "BufferQueue: failed to create BufferQueueProducer"); + + sp consumer(new BufferQueueConsumer(core)); + LOG_ALWAYS_FATAL_IF(consumer == NULL, + "BufferQueue: failed to create BufferQueueConsumer"); + + *outProducer = producer; + *outConsumer = consumer; +} + +}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h new file mode 100644 index 000000000000..3297b10443db --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERQUEUE_H +#define ANDROID_GUI_BUFFERQUEUE_H + +#include +#include +#include +#include + +// These are only required to keep other parts of the framework with incomplete +// dependencies building successfully +#include + +namespace android { + +class BufferQueue { +public: + // BufferQueue will keep track of at most this value of buffers. + // Attempts at runtime to increase the number of buffers past this will fail. + enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; + // Used as a placeholder slot# when the value isn't pointing to an existing buffer. + enum { INVALID_BUFFER_SLOT = IGraphicBufferConsumer::BufferItem::INVALID_BUFFER_SLOT }; + // Alias to -- please scope from there in future code! + enum { + NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE, + PRESENT_LATER = IGraphicBufferConsumer::PRESENT_LATER, + }; + + // When in async mode we reserve two slots in order to guarantee that the + // producer and consumer can run asynchronously. + enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; + + // for backward source compatibility + typedef ::android::ConsumerListener ConsumerListener; + typedef IGraphicBufferConsumer::BufferItem BufferItem; + + // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak + // reference to the actual consumer object. It forwards all calls to that + // consumer object so long as it exists. + // + // This class exists to avoid having a circular reference between the + // BufferQueue object and the consumer object. The reason this can't be a weak + // reference in the BufferQueue class is because we're planning to expose the + // consumer side of a BufferQueue as a binder interface, which doesn't support + // weak references. + class ProxyConsumerListener : public BnConsumerListener { + public: + ProxyConsumerListener(const wp& consumerListener); + virtual ~ProxyConsumerListener(); + virtual void onFrameAvailable(); + virtual void onBuffersReleased(); + virtual void onSidebandStreamChanged(); + private: + // mConsumerListener is a weak reference to the IConsumerListener. This is + // the raison d'etre of ProxyConsumerListener. + wp mConsumerListener; + }; + + // BufferQueue manages a pool of gralloc memory slots to be used by + // producers and consumers. allocator is used to allocate all the + // needed gralloc buffers. + static void createBufferQueue(sp* outProducer, + sp* outConsumer, + const sp& allocator = NULL); + +private: + BufferQueue(); // Create through createBufferQueue +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_BUFFERQUEUE_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp new file mode 100644 index 000000000000..36e3c06a5a9f --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp @@ -0,0 +1,523 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "BufferQueueConsumer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +namespace android { + +BufferQueueConsumer::BufferQueueConsumer(const sp& core) : + mCore(core), + mSlots(core->mSlots), + mConsumerName() {} + +BufferQueueConsumer::~BufferQueueConsumer() {} + +status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, + nsecs_t expectedPresent) { + ATRACE_CALL(); + Mutex::Autolock lock(mCore->mMutex); + + // Check that the consumer doesn't currently have the maximum number of + // buffers acquired. We allow the max buffer count to be exceeded by one + // buffer so that the consumer can successfully set up the newly acquired + // buffer before releasing the old one. + int numAcquiredBuffers = 0; + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { + ++numAcquiredBuffers; + } + } + if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { + BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", + numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); + return INVALID_OPERATION; + } + + // Check if the queue is empty. + // In asynchronous mode the list is guaranteed to be one buffer deep, + // while in synchronous mode we use the oldest buffer. + if (mCore->mQueue.empty()) { + return NO_BUFFER_AVAILABLE; + } + + BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); + + // If expectedPresent is specified, we may not want to return a buffer yet. + // If it's specified and there's more than one buffer queued, we may want + // to drop a buffer. + if (expectedPresent != 0) { + const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second + + // The 'expectedPresent' argument indicates when the buffer is expected + // to be presented on-screen. If the buffer's desired present time is + // earlier (less) than expectedPresent -- meaning it will be displayed + // on time or possibly late if we show it as soon as possible -- we + // acquire and return it. If we don't want to display it until after the + // expectedPresent time, we return PRESENT_LATER without acquiring it. + // + // To be safe, we don't defer acquisition if expectedPresent is more + // than one second in the future beyond the desired present time + // (i.e., we'd be holding the buffer for a long time). + // + // NOTE: Code assumes monotonic time values from the system clock + // are positive. + + // Start by checking to see if we can drop frames. We skip this check if + // the timestamps are being auto-generated by Surface. If the app isn't + // generating timestamps explicitly, it probably doesn't want frames to + // be discarded based on them. + while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { + // If entry[1] is timely, drop entry[0] (and repeat). We apply an + // additional criterion here: we only drop the earlier buffer if our + // desiredPresent falls within +/- 1 second of the expected present. + // Otherwise, bogus desiredPresent times (e.g., 0 or a small + // relative timestamp), which normally mean "ignore the timestamp + // and acquire immediately", would cause us to drop frames. + // + // We may want to add an additional criterion: don't drop the + // earlier buffer if entry[1]'s fence hasn't signaled yet. + const BufferItem& bufferItem(mCore->mQueue[1]); + nsecs_t desiredPresent = bufferItem.mTimestamp; + if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || + desiredPresent > expectedPresent) { + // This buffer is set to display in the near future, or + // desiredPresent is garbage. Either way we don't want to drop + // the previous buffer just to get this on the screen sooner. + BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" + PRId64 " (%" PRId64 ") now=%" PRId64, + desiredPresent, expectedPresent, + desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + break; + } + + BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 + " size=%zu", + desiredPresent, expectedPresent, mCore->mQueue.size()); + if (mCore->stillTracking(front)) { + // Front buffer is still in mSlots, so mark the slot as free + mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + } + mCore->mQueue.erase(front); + front = mCore->mQueue.begin(); + } + + // See if the front buffer is due + nsecs_t desiredPresent = front->mTimestamp; + if (desiredPresent > expectedPresent && + desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { + BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 + " (%" PRId64 ") now=%" PRId64, + desiredPresent, expectedPresent, + desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + return PRESENT_LATER; + } + + BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " + "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, + desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + } + + int slot = front->mSlot; + *outBuffer = *front; + ATRACE_BUFFER_INDEX(slot); + + BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", + slot, front->mFrameNumber, front->mGraphicBuffer->handle); + // If the front buffer is still being tracked, update its slot state + if (mCore->stillTracking(front)) { + mSlots[slot].mAcquireCalled = true; + mSlots[slot].mNeedsCleanupOnRelease = false; + mSlots[slot].mBufferState = BufferSlot::ACQUIRED; + mSlots[slot].mFence = Fence::NO_FENCE; + } + + // If the buffer has previously been acquired by the consumer, set + // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer + // on the consumer side + if (outBuffer->mAcquireCalled) { + outBuffer->mGraphicBuffer = NULL; + } + + mCore->mQueue.erase(front); + + // We might have freed a slot while dropping old buffers, or the producer + // may be blocked waiting for the number of buffers in the queue to + // decrease. + mCore->mDequeueCondition.broadcast(); + + ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); + + return NO_ERROR; +} + +status_t BufferQueueConsumer::detachBuffer(int slot) { + ATRACE_CALL(); + ATRACE_BUFFER_INDEX(slot); + BQ_LOGV("detachBuffer(C): slot %d", slot); + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("detachBuffer(C): BufferQueue has been abandoned"); + return NO_INIT; + } + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("detachBuffer(C): slot index %d out of range [0, %d)", + slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; + } else if (mSlots[slot].mBufferState != BufferSlot::ACQUIRED) { + BQ_LOGE("detachBuffer(C): slot %d is not owned by the consumer " + "(state = %d)", slot, mSlots[slot].mBufferState); + return BAD_VALUE; + } + + mCore->freeBufferLocked(slot); + mCore->mDequeueCondition.broadcast(); + + return NO_ERROR; +} + +status_t BufferQueueConsumer::attachBuffer(int* outSlot, + const sp& buffer) { + ATRACE_CALL(); + + if (outSlot == NULL) { + BQ_LOGE("attachBuffer(P): outSlot must not be NULL"); + return BAD_VALUE; + } else if (buffer == NULL) { + BQ_LOGE("attachBuffer(P): cannot attach NULL buffer"); + return BAD_VALUE; + } + + Mutex::Autolock lock(mCore->mMutex); + + // Make sure we don't have too many acquired buffers and find a free slot + // to put the buffer into (the oldest if there are multiple). + int numAcquiredBuffers = 0; + int found = BufferQueueCore::INVALID_BUFFER_SLOT; + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { + ++numAcquiredBuffers; + } else if (mSlots[s].mBufferState == BufferSlot::FREE) { + if (found == BufferQueueCore::INVALID_BUFFER_SLOT || + mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { + found = s; + } + } + } + + if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { + BQ_LOGE("attachBuffer(P): max acquired buffer count reached: %d " + "(max %d)", numAcquiredBuffers, + mCore->mMaxAcquiredBufferCount); + return INVALID_OPERATION; + } + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + BQ_LOGE("attachBuffer(P): could not find free buffer slot"); + return NO_MEMORY; + } + + *outSlot = found; + ATRACE_BUFFER_INDEX(*outSlot); + BQ_LOGV("attachBuffer(C): returning slot %d", *outSlot); + + mSlots[*outSlot].mGraphicBuffer = buffer; + mSlots[*outSlot].mBufferState = BufferSlot::ACQUIRED; + mSlots[*outSlot].mAttachedByConsumer = true; + mSlots[*outSlot].mNeedsCleanupOnRelease = false; + mSlots[*outSlot].mFence = Fence::NO_FENCE; + mSlots[*outSlot].mFrameNumber = 0; + + // mAcquireCalled tells BufferQueue that it doesn't need to send a valid + // GraphicBuffer pointer on the next acquireBuffer call, which decreases + // Binder traffic by not un/flattening the GraphicBuffer. However, it + // requires that the consumer maintain a cached copy of the slot <--> buffer + // mappings, which is why the consumer doesn't need the valid pointer on + // acquire. + // + // The StreamSplitter is one of the primary users of the attach/detach + // logic, and while it is running, all buffers it acquires are immediately + // detached, and all buffers it eventually releases are ones that were + // attached (as opposed to having been obtained from acquireBuffer), so it + // doesn't make sense to maintain the slot/buffer mappings, which would + // become invalid for every buffer during detach/attach. By setting this to + // false, the valid GraphicBuffer pointer will always be sent with acquire + // for attached buffers. + mSlots[*outSlot].mAcquireCalled = false; + + return NO_ERROR; +} + +status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, + const sp& releaseFence, EGLDisplay eglDisplay, + EGLSyncKHR eglFence) { + ATRACE_CALL(); + ATRACE_BUFFER_INDEX(slot); + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || + releaseFence == NULL) { + return BAD_VALUE; + } + + sp listener; + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + + // If the frame number has changed because the buffer has been reallocated, + // we can ignore this releaseBuffer for the old buffer + if (frameNumber != mSlots[slot].mFrameNumber) { + return STALE_BUFFER_SLOT; + } + + // Make sure this buffer hasn't been queued while acquired by the consumer + BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); + while (current != mCore->mQueue.end()) { + if (current->mSlot == slot) { + BQ_LOGE("releaseBuffer: buffer slot %d pending release is " + "currently queued", slot); + return BAD_VALUE; + } + ++current; + } + + if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { + mSlots[slot].mEglDisplay = eglDisplay; + mSlots[slot].mEglFence = eglFence; + mSlots[slot].mFence = releaseFence; + mSlots[slot].mBufferState = BufferSlot::FREE; + listener = mCore->mConnectedProducerListener; + BQ_LOGV("releaseBuffer: releasing slot %d", slot); + } else if (mSlots[slot].mNeedsCleanupOnRelease) { + BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d " + "(state = %d)", slot, mSlots[slot].mBufferState); + mSlots[slot].mNeedsCleanupOnRelease = false; + return STALE_BUFFER_SLOT; + } else { + BQ_LOGV("releaseBuffer: attempted to release buffer slot %d " + "but its state was %d", slot, mSlots[slot].mBufferState); + return BAD_VALUE; + } + + mCore->mDequeueCondition.broadcast(); + } // Autolock scope + + // Call back without lock held + if (listener != NULL) { + listener->onBufferReleased(); + } + + return NO_ERROR; +} + +status_t BufferQueueConsumer::connect( + const sp& consumerListener, bool controlledByApp) { + ATRACE_CALL(); + + if (consumerListener == NULL) { + BQ_LOGE("connect(C): consumerListener may not be NULL"); + return BAD_VALUE; + } + + BQ_LOGV("connect(C): controlledByApp=%s", + controlledByApp ? "true" : "false"); + + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("connect(C): BufferQueue has been abandoned"); + return NO_INIT; + } + + mCore->mConsumerListener = consumerListener; + mCore->mConsumerControlledByApp = controlledByApp; + + return NO_ERROR; +} + +status_t BufferQueueConsumer::disconnect() { + ATRACE_CALL(); + + BQ_LOGV("disconnect(C)"); + + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mConsumerListener == NULL) { + BQ_LOGE("disconnect(C): no consumer is connected"); + return BAD_VALUE; + } + + mCore->mIsAbandoned = true; + mCore->mConsumerListener = NULL; + mCore->mQueue.clear(); + mCore->freeAllBuffersLocked(); + mCore->mDequeueCondition.broadcast(); + return NO_ERROR; +} + +status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { + ATRACE_CALL(); + + if (outSlotMask == NULL) { + BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL"); + return BAD_VALUE; + } + + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned"); + return NO_INIT; + } + + uint64_t mask = 0; + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (!mSlots[s].mAcquireCalled) { + mask |= (1ULL << s); + } + } + + // Remove from the mask queued buffers for which acquire has been called, + // since the consumer will not receive their buffer addresses and so must + // retain their cached information + BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); + while (current != mCore->mQueue.end()) { + if (current->mAcquireCalled) { + mask &= ~(1ULL << current->mSlot); + } + ++current; + } + + BQ_LOGV("getReleasedBuffers: returning mask %#" PRIx64, mask); + *outSlotMask = mask; + return NO_ERROR; +} + +status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, + uint32_t height) { + ATRACE_CALL(); + + if (width == 0 || height == 0) { + BQ_LOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u " + "height=%u)", width, height); + return BAD_VALUE; + } + + BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height); + + Mutex::Autolock lock(mCore->mMutex); + mCore->mDefaultWidth = width; + mCore->mDefaultHeight = height; + return NO_ERROR; +} + +status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) { + ATRACE_CALL(); + Mutex::Autolock lock(mCore->mMutex); + return mCore->setDefaultMaxBufferCountLocked(bufferCount); +} + +status_t BufferQueueConsumer::disableAsyncBuffer() { + ATRACE_CALL(); + + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mConsumerListener != NULL) { + BQ_LOGE("disableAsyncBuffer: consumer already connected"); + return INVALID_OPERATION; + } + + BQ_LOGV("disableAsyncBuffer"); + mCore->mUseAsyncBuffer = false; + return NO_ERROR; +} + +status_t BufferQueueConsumer::setMaxAcquiredBufferCount( + int maxAcquiredBuffers) { + ATRACE_CALL(); + + if (maxAcquiredBuffers < 1 || + maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { + BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d", + maxAcquiredBuffers); + return BAD_VALUE; + } + + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected"); + return INVALID_OPERATION; + } + + BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); + mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; + return NO_ERROR; +} + +void BufferQueueConsumer::setConsumerName(const String8& name) { + ATRACE_CALL(); + BQ_LOGV("setConsumerName: '%s'", name.string()); + Mutex::Autolock lock(mCore->mMutex); + mCore->mConsumerName = name; + mConsumerName = name; +} + +status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { + ATRACE_CALL(); + BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat); + Mutex::Autolock lock(mCore->mMutex); + mCore->mDefaultBufferFormat = defaultFormat; + return NO_ERROR; +} + +status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { + ATRACE_CALL(); + BQ_LOGV("setConsumerUsageBits: %#x", usage); + Mutex::Autolock lock(mCore->mMutex); + mCore->mConsumerUsageBits = usage; + return NO_ERROR; +} + +status_t BufferQueueConsumer::setTransformHint(uint32_t hint) { + ATRACE_CALL(); + BQ_LOGV("setTransformHint: %#x", hint); + Mutex::Autolock lock(mCore->mMutex); + mCore->mTransformHint = hint; + return NO_ERROR; +} + +sp BufferQueueConsumer::getSidebandStream() const { + return mCore->mSidebandStream; +} + +void BufferQueueConsumer::dump(String8& result, const char* prefix) const { + mCore->dump(result, prefix); +} + +} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h new file mode 100644 index 000000000000..1912ed03da63 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h @@ -0,0 +1,181 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERQUEUECONSUMER_H +#define ANDROID_GUI_BUFFERQUEUECONSUMER_H + +#include +#include + +#include +#include + +namespace android { + +class BufferQueueCore; + +class BufferQueueConsumer : public BnGraphicBufferConsumer { + +public: + BufferQueueConsumer(const sp& core); + virtual ~BufferQueueConsumer(); + + // acquireBuffer attempts to acquire ownership of the next pending buffer in + // the BufferQueue. If no buffer is pending then it returns + // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the + // information about the buffer is returned in BufferItem. If the buffer + // returned had previously been acquired then the BufferItem::mGraphicBuffer + // field of buffer is set to NULL and it is assumed that the consumer still + // holds a reference to the buffer. + // + // If expectedPresent is nonzero, it indicates the time when the buffer + // will be displayed on screen. If the buffer's timestamp is farther in the + // future, the buffer won't be acquired, and PRESENT_LATER will be + // returned. The presentation time is in nanoseconds, and the time base + // is CLOCK_MONOTONIC. + virtual status_t acquireBuffer(BufferItem* outBuffer, + nsecs_t expectedPresent); + + // See IGraphicBufferConsumer::detachBuffer + virtual status_t detachBuffer(int slot); + + // See IGraphicBufferConsumer::attachBuffer + virtual status_t attachBuffer(int* slot, const sp& buffer); + + // releaseBuffer releases a buffer slot from the consumer back to the + // BufferQueue. This may be done while the buffer's contents are still + // being accessed. The fence will signal when the buffer is no longer + // in use. frameNumber is used to indentify the exact buffer returned. + // + // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free + // any references to the just-released buffer that it might have, as if it + // had received a onBuffersReleased() call with a mask set for the released + // buffer. + // + // Note that the dependencies on EGL will be removed once we switch to using + // the Android HW Sync HAL. + virtual status_t releaseBuffer(int slot, uint64_t frameNumber, + const sp& releaseFence, EGLDisplay display, + EGLSyncKHR fence); + + // connect connects a consumer to the BufferQueue. Only one + // consumer may be connected, and when that consumer disconnects the + // BufferQueue is placed into the "abandoned" state, causing most + // interactions with the BufferQueue by the producer to fail. + // controlledByApp indicates whether the consumer is controlled by + // the application. + // + // consumerListener may not be NULL. + virtual status_t connect(const sp& consumerListener, + bool controlledByApp); + + // disconnect disconnects a consumer from the BufferQueue. All + // buffers will be freed and the BufferQueue is placed in the "abandoned" + // state, causing most interactions with the BufferQueue by the producer to + // fail. + virtual status_t disconnect(); + + // getReleasedBuffers sets the value pointed to by outSlotMask to a bit mask + // indicating which buffer slots have been released by the BufferQueue + // but have not yet been released by the consumer. + // + // This should be called from the onBuffersReleased() callback. + virtual status_t getReleasedBuffers(uint64_t* outSlotMask); + + // setDefaultBufferSize is used to set the size of buffers returned by + // dequeueBuffer when a width and height of zero is requested. Default + // is 1x1. + virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height); + + // setDefaultMaxBufferCount sets the default value for the maximum buffer + // count (the initial default is 2). If the producer has requested a + // buffer count using setBufferCount, the default buffer count will only + // take effect if the producer sets the count back to zero. + // + // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. + virtual status_t setDefaultMaxBufferCount(int bufferCount); + + // disableAsyncBuffer disables the extra buffer used in async mode + // (when both producer and consumer have set their "isControlledByApp" + // flag) and has dequeueBuffer() return WOULD_BLOCK instead. + // + // This can only be called before connect(). + virtual status_t disableAsyncBuffer(); + + // setMaxAcquiredBufferCount sets the maximum number of buffers that can + // be acquired by the consumer at one time (default 1). This call will + // fail if a producer is connected to the BufferQueue. + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + + // setConsumerName sets the name used in logging + virtual void setConsumerName(const String8& name); + + // setDefaultBufferFormat allows the BufferQueue to create + // GraphicBuffers of a defaultFormat if no format is specified + // in dequeueBuffer. Formats are enumerated in graphics.h; the + // initial default is HAL_PIXEL_FORMAT_RGBA_8888. + virtual status_t setDefaultBufferFormat(uint32_t defaultFormat); + + // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. + // These are merged with the bits passed to dequeueBuffer. The values are + // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. + virtual status_t setConsumerUsageBits(uint32_t usage); + + // setTransformHint bakes in rotation to buffers so overlays can be used. + // The values are enumerated in window.h, e.g. + // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). + virtual status_t setTransformHint(uint32_t hint); + + // Retrieve the sideband buffer stream, if any. + virtual sp getSidebandStream() const; + + // dump our state in a String + virtual void dump(String8& result, const char* prefix) const; + + // Functions required for backwards compatibility. + // These will be modified/renamed in IGraphicBufferConsumer and will be + // removed from this class at that time. See b/13306289. + + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, + EGLDisplay display, EGLSyncKHR fence, + const sp& releaseFence) { + return releaseBuffer(buf, frameNumber, releaseFence, display, fence); + } + + virtual status_t consumerConnect(const sp& consumer, + bool controlledByApp) { + return connect(consumer, controlledByApp); + } + + virtual status_t consumerDisconnect() { return disconnect(); } + + // End functions required for backwards compatibility + +private: + sp mCore; + + // This references mCore->mSlots. Lock mCore->mMutex while accessing. + BufferQueueDefs::SlotsType& mSlots; + + // This is a cached copy of the name stored in the BufferQueueCore. + // It's updated during setConsumerName. + String8 mConsumerName; + +}; // class BufferQueueConsumer + +} // namespace android + +#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp new file mode 100644 index 000000000000..ec1e63112d71 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp @@ -0,0 +1,238 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BufferQueueCore" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#define EGL_EGLEXT_PROTOTYPES + +#include + +#include +#include +#include +#include +#include +#include +#include + +template +static inline T max(T a, T b) { return a > b ? a : b; } + +namespace android { + +static String8 getUniqueName() { + static volatile int32_t counter = 0; + return String8::format("unnamed-%d-%d", getpid(), + android_atomic_inc(&counter)); +} + +BufferQueueCore::BufferQueueCore(const sp& allocator) : + mAllocator(allocator), + mMutex(), + mIsAbandoned(false), + mConsumerControlledByApp(false), + mConsumerName(getUniqueName()), + mConsumerListener(), + mConsumerUsageBits(0), + mConnectedApi(NO_CONNECTED_API), + mConnectedProducerListener(), + mSlots(), + mQueue(), + mOverrideMaxBufferCount(0), + mDequeueCondition(), + mUseAsyncBuffer(true), + mDequeueBufferCannotBlock(false), + mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), + mDefaultWidth(1), + mDefaultHeight(1), + mDefaultMaxBufferCount(2), + mMaxAcquiredBufferCount(1), + mBufferHasBeenQueued(false), + mFrameCounter(0), + mTransformHint(0), + mIsAllocating(false), + mIsAllocatingCondition() +{ + if (allocator == NULL) { + sp composer(ComposerService::getComposerService()); + mAllocator = composer->createGraphicBufferAlloc(); + if (mAllocator == NULL) { + BQ_LOGE("createGraphicBufferAlloc failed"); + } + } +} + +BufferQueueCore::~BufferQueueCore() {} + +void BufferQueueCore::dump(String8& result, const char* prefix) const { + Mutex::Autolock lock(mMutex); + + String8 fifo; + Fifo::const_iterator current(mQueue.begin()); + while (current != mQueue.end()) { + fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " + "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n", + current->mSlot, current->mGraphicBuffer.get(), + current->mCrop.left, current->mCrop.top, current->mCrop.right, + current->mCrop.bottom, current->mTransform, current->mTimestamp, + BufferItem::scalingModeName(current->mScalingMode)); + ++current; + } + + result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, " + "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " + "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n", + prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, + mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, + mQueue.size(), fifo.string()); + + // Trim the free buffers so as to not spam the dump + int maxBufferCount = 0; + for (int s = BufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) { + const BufferSlot& slot(mSlots[s]); + if (slot.mBufferState != BufferSlot::FREE || + slot.mGraphicBuffer != NULL) { + maxBufferCount = s + 1; + break; + } + } + + for (int s = 0; s < maxBufferCount; ++s) { + const BufferSlot& slot(mSlots[s]); + const sp& buffer(slot.mGraphicBuffer); + result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix, + (slot.mBufferState == BufferSlot::ACQUIRED) ? ">" : " ", + s, buffer.get(), + BufferSlot::bufferStateName(slot.mBufferState)); + + if (buffer != NULL) { + result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle, + buffer->width, buffer->height, buffer->stride, + buffer->format); + } + + result.append("\n"); + } +} + +int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const { + // If dequeueBuffer is allowed to error out, we don't have to add an + // extra buffer. + if (!mUseAsyncBuffer) { + return mMaxAcquiredBufferCount; + } + + if (mDequeueBufferCannotBlock || async) { + return mMaxAcquiredBufferCount + 1; + } + + return mMaxAcquiredBufferCount; +} + +int BufferQueueCore::getMinMaxBufferCountLocked(bool async) const { + return getMinUndequeuedBufferCountLocked(async) + 1; +} + +int BufferQueueCore::getMaxBufferCountLocked(bool async) const { + int minMaxBufferCount = getMinMaxBufferCountLocked(async); + + int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount); + if (mOverrideMaxBufferCount != 0) { + assert(mOverrideMaxBufferCount >= minMaxBufferCount); + maxBufferCount = mOverrideMaxBufferCount; + } + + // Any buffers that are dequeued by the producer or sitting in the queue + // waiting to be consumed need to have their slots preserved. Such buffers + // will temporarily keep the max buffer count up until the slots no longer + // need to be preserved. + for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + BufferSlot::BufferState state = mSlots[s].mBufferState; + if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { + maxBufferCount = s + 1; + } + } + + return maxBufferCount; +} + +status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) { + const int minBufferCount = mUseAsyncBuffer ? 2 : 1; + if (count < minBufferCount || count > BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGV("setDefaultMaxBufferCount: invalid count %d, should be in " + "[%d, %d]", + count, minBufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; + } + + BQ_LOGV("setDefaultMaxBufferCount: setting count to %d", count); + mDefaultMaxBufferCount = count; + mDequeueCondition.broadcast(); + + return NO_ERROR; +} + +void BufferQueueCore::freeBufferLocked(int slot) { + BQ_LOGV("freeBufferLocked: slot %d", slot); + mSlots[slot].mGraphicBuffer.clear(); + if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { + mSlots[slot].mNeedsCleanupOnRelease = true; + } + mSlots[slot].mBufferState = BufferSlot::FREE; + mSlots[slot].mFrameNumber = UINT32_MAX; + mSlots[slot].mAcquireCalled = false; + + // Destroy fence as BufferQueue now takes ownership + if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) { + eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence); + mSlots[slot].mEglFence = EGL_NO_SYNC_KHR; + } + mSlots[slot].mFence = Fence::NO_FENCE; +} + +void BufferQueueCore::freeAllBuffersLocked() { + mBufferHasBeenQueued = false; + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + freeBufferLocked(s); + } +} + +bool BufferQueueCore::stillTracking(const BufferItem* item) const { + const BufferSlot& slot = mSlots[item->mSlot]; + + BQ_LOGV("stillTracking: item { slot=%d/%" PRIu64 " buffer=%p } " + "slot { slot=%d/%" PRIu64 " buffer=%p }", + item->mSlot, item->mFrameNumber, + (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), + item->mSlot, slot.mFrameNumber, + (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); + + // Compare item with its original buffer slot. We can check the slot as + // the buffer would not be moved to a different slot by the producer. + return (slot.mGraphicBuffer != NULL) && + (item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); +} + +void BufferQueueCore::waitWhileAllocatingLocked() const { + ATRACE_CALL(); + while (mIsAllocating) { + mIsAllocatingCondition.wait(mMutex); + } +} + +} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h new file mode 100644 index 000000000000..1050e3b6ca2a --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h @@ -0,0 +1,253 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERQUEUECORE_H +#define ANDROID_GUI_BUFFERQUEUECORE_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BQ_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) + +#define ATRACE_BUFFER_INDEX(index) \ + if (ATRACE_ENABLED()) { \ + char ___traceBuf[1024]; \ + snprintf(___traceBuf, 1024, "%s: %d", \ + mCore->mConsumerName.string(), (index)); \ + android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ + } + +namespace android { + +class BufferItem; +class IConsumerListener; +class IGraphicBufferAlloc; +class IProducerListener; + +class BufferQueueCore : public virtual RefBase { + + friend class BufferQueueProducer; + friend class BufferQueueConsumer; + +public: + // Used as a placeholder slot number when the value isn't pointing to an + // existing buffer. + enum { INVALID_BUFFER_SLOT = -1 }; // TODO: Extract from IGBC::BufferItem + + // We reserve two slots in order to guarantee that the producer and + // consumer can run asynchronously. + enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; + + // The default API number used to indicate that no producer is connected + enum { NO_CONNECTED_API = 0 }; + + typedef Vector Fifo; + + // BufferQueueCore manages a pool of gralloc memory slots to be used by + // producers and consumers. allocator is used to allocate all the needed + // gralloc buffers. + BufferQueueCore(const sp& allocator = NULL); + virtual ~BufferQueueCore(); + +private: + // Dump our state in a string + void dump(String8& result, const char* prefix) const; + + // getMinUndequeuedBufferCountLocked returns the minimum number of buffers + // that must remain in a state other than DEQUEUED. The async parameter + // tells whether we're in asynchronous mode. + int getMinUndequeuedBufferCountLocked(bool async) const; + + // getMinMaxBufferCountLocked returns the minimum number of buffers allowed + // given the current BufferQueue state. The async parameter tells whether + // we're in asynchonous mode. + int getMinMaxBufferCountLocked(bool async) const; + + // getMaxBufferCountLocked returns the maximum number of buffers that can be + // allocated at once. This value depends on the following member variables: + // + // mDequeueBufferCannotBlock + // mMaxAcquiredBufferCount + // mDefaultMaxBufferCount + // mOverrideMaxBufferCount + // async parameter + // + // Any time one of these member variables is changed while a producer is + // connected, mDequeueCondition must be broadcast. + int getMaxBufferCountLocked(bool async) const; + + // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots + // that will be used if the producer does not override the buffer slot + // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The + // initial default is 2. + status_t setDefaultMaxBufferCountLocked(int count); + + // freeBufferLocked frees the GraphicBuffer and sync resources for the + // given slot. + void freeBufferLocked(int slot); + + // freeAllBuffersLocked frees the GraphicBuffer and sync resources for + // all slots. + void freeAllBuffersLocked(); + + // stillTracking returns true iff the buffer item is still being tracked + // in one of the slots. + bool stillTracking(const BufferItem* item) const; + + // waitWhileAllocatingLocked blocks until mIsAllocating is false. + void waitWhileAllocatingLocked() const; + + // mAllocator is the connection to SurfaceFlinger that is used to allocate + // new GraphicBuffer objects. + sp mAllocator; + + // mMutex is the mutex used to prevent concurrent access to the member + // variables of BufferQueueCore objects. It must be locked whenever any + // member variable is accessed. + mutable Mutex mMutex; + + // mIsAbandoned indicates that the BufferQueue will no longer be used to + // consume image buffers pushed to it using the IGraphicBufferProducer + // interface. It is initialized to false, and set to true in the + // consumerDisconnect method. A BufferQueue that is abandoned will return + // the NO_INIT error from all IGraphicBufferProducer methods capable of + // returning an error. + bool mIsAbandoned; + + // mConsumerControlledByApp indicates whether the connected consumer is + // controlled by the application. + bool mConsumerControlledByApp; + + // mConsumerName is a string used to identify the BufferQueue in log + // messages. It is set by the IGraphicBufferConsumer::setConsumerName + // method. + String8 mConsumerName; + + // mConsumerListener is used to notify the connected consumer of + // asynchronous events that it may wish to react to. It is initially + // set to NULL and is written by consumerConnect and consumerDisconnect. + sp mConsumerListener; + + // mConsumerUsageBits contains flags that the consumer wants for + // GraphicBuffers. + uint32_t mConsumerUsageBits; + + // mConnectedApi indicates the producer API that is currently connected + // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated + // by the connect and disconnect methods. + int mConnectedApi; + + // mConnectedProducerToken is used to set a binder death notification on + // the producer. + sp mConnectedProducerListener; + + // mSlots is an array of buffer slots that must be mirrored on the producer + // side. This allows buffer ownership to be transferred between the producer + // and consumer without sending a GraphicBuffer over Binder. The entire + // array is initialized to NULL at construction time, and buffers are + // allocated for a slot when requestBuffer is called with that slot's index. + BufferQueueDefs::SlotsType mSlots; + + // mQueue is a FIFO of queued buffers used in synchronous mode. + Fifo mQueue; + + // mOverrideMaxBufferCount is the limit on the number of buffers that will + // be allocated at one time. This value is set by the producer by calling + // setBufferCount. The default is 0, which means that the producer doesn't + // care about the number of buffers in the pool. In that case, + // mDefaultMaxBufferCount is used as the limit. + int mOverrideMaxBufferCount; + + // mDequeueCondition is a condition variable used for dequeueBuffer in + // synchronous mode. + mutable Condition mDequeueCondition; + + // mUseAsyncBuffer indicates whether an extra buffer is used in async mode + // to prevent dequeueBuffer from blocking. + bool mUseAsyncBuffer; + + // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to + // block. This flag is set during connect when both the producer and + // consumer are controlled by the application. + bool mDequeueBufferCannotBlock; + + // mDefaultBufferFormat can be set so it will override the buffer format + // when it isn't specified in dequeueBuffer. + uint32_t mDefaultBufferFormat; + + // mDefaultWidth holds the default width of allocated buffers. It is used + // in dequeueBuffer if a width and height of 0 are specified. + int mDefaultWidth; + + // mDefaultHeight holds the default height of allocated buffers. It is used + // in dequeueBuffer if a width and height of 0 are specified. + int mDefaultHeight; + + // mDefaultMaxBufferCount is the default limit on the number of buffers that + // will be allocated at one time. This default limit is set by the consumer. + // The limit (as opposed to the default limit) may be overriden by the + // producer. + int mDefaultMaxBufferCount; + + // mMaxAcquiredBufferCount is the number of buffers that the consumer may + // acquire at one time. It defaults to 1, and can be changed by the consumer + // via setMaxAcquiredBufferCount, but this may only be done while no + // producer is connected to the BufferQueue. This value is used to derive + // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. + int mMaxAcquiredBufferCount; + + // mBufferHasBeenQueued is true once a buffer has been queued. It is reset + // when something causes all buffers to be freed (e.g., changing the buffer + // count). + bool mBufferHasBeenQueued; + + // mFrameCounter is the free running counter, incremented on every + // successful queueBuffer call and buffer allocation. + uint64_t mFrameCounter; + + // mTransformHint is used to optimize for screen rotations. + uint32_t mTransformHint; + + // mSidebandStream is a handle to the sideband buffer stream, if any + sp mSidebandStream; + + // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which + // releases mMutex while doing the allocation proper). Producers should not modify any of the + // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to + // false. + bool mIsAllocating; + + // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating + // becomes false. + mutable Condition mIsAllocatingCondition; +}; // class BufferQueueCore + +} // namespace android + +#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h new file mode 100644 index 000000000000..83e958003780 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h @@ -0,0 +1,35 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERQUEUECOREDEFS_H +#define ANDROID_GUI_BUFFERQUEUECOREDEFS_H + +#include + +namespace android { + class BufferQueueCore; + + namespace BufferQueueDefs { + // BufferQueue will keep track of at most this value of buffers. + // Attempts at runtime to increase the number of buffers past this + // will fail. + enum { NUM_BUFFER_SLOTS = 64 }; + + typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]; + } // namespace BufferQueueDefs +} // namespace android + +#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp new file mode 100644 index 000000000000..d2fd3b025541 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp @@ -0,0 +1,982 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "BufferQueueProducer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#define EGL_EGLEXT_PROTOTYPES + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace android { + +BufferQueueProducer::BufferQueueProducer(const sp& core) : + mCore(core), + mSlots(core->mSlots), + mConsumerName(), + mStickyTransform(0) {} + +BufferQueueProducer::~BufferQueueProducer() {} + +status_t BufferQueueProducer::requestBuffer(int slot, sp* buf) { + ATRACE_CALL(); + BQ_LOGV("requestBuffer: slot %d", slot); + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("requestBuffer: BufferQueue has been abandoned"); + return NO_INIT; + } + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", + slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; + } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { + BQ_LOGE("requestBuffer: slot %d is not owned by the producer " + "(state = %d)", slot, mSlots[slot].mBufferState); + return BAD_VALUE; + } + + mSlots[slot].mRequestBufferCalled = true; + *buf = mSlots[slot].mGraphicBuffer; + return NO_ERROR; +} + +status_t BufferQueueProducer::setBufferCount(int bufferCount) { + ATRACE_CALL(); + BQ_LOGV("setBufferCount: count = %d", bufferCount); + + sp listener; + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(); + + if (mCore->mIsAbandoned) { + BQ_LOGE("setBufferCount: BufferQueue has been abandoned"); + return NO_INIT; + } + + if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("setBufferCount: bufferCount %d too large (max %d)", + bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; + } + + // There must be no dequeued buffers when changing the buffer count. + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) { + BQ_LOGE("setBufferCount: buffer owned by producer"); + return BAD_VALUE; + } + } + + if (bufferCount == 0) { + mCore->mOverrideMaxBufferCount = 0; + mCore->mDequeueCondition.broadcast(); + return NO_ERROR; + } + + const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false); + if (bufferCount < minBufferSlots) { + BQ_LOGE("setBufferCount: requested buffer count %d is less than " + "minimum %d", bufferCount, minBufferSlots); + return BAD_VALUE; + } + + // Here we are guaranteed that the producer doesn't have any dequeued + // buffers and will release all of its buffer references. We don't + // clear the queue, however, so that currently queued buffers still + // get displayed. + mCore->freeAllBuffersLocked(); + mCore->mOverrideMaxBufferCount = bufferCount; + mCore->mDequeueCondition.broadcast(); + listener = mCore->mConsumerListener; + } // Autolock scope + + // Call back without lock held + if (listener != NULL) { + listener->onBuffersReleased(); + } + + return NO_ERROR; +} + +status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, + bool async, int* found, status_t* returnFlags) const { + bool tryAgain = true; + while (tryAgain) { + if (mCore->mIsAbandoned) { + BQ_LOGE("%s: BufferQueue has been abandoned", caller); + return NO_INIT; + } + + const int maxBufferCount = mCore->getMaxBufferCountLocked(async); + if (async && mCore->mOverrideMaxBufferCount) { + // FIXME: Some drivers are manually setting the buffer count + // (which they shouldn't), so we do this extra test here to + // handle that case. This is TEMPORARY until we get this fixed. + if (mCore->mOverrideMaxBufferCount < maxBufferCount) { + BQ_LOGE("%s: async mode is invalid with buffer count override", + caller); + return BAD_VALUE; + } + } + + // Free up any buffers that are in slots beyond the max buffer count + for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + assert(mSlots[s].mBufferState == BufferSlot::FREE); + if (mSlots[s].mGraphicBuffer != NULL) { + mCore->freeBufferLocked(s); + *returnFlags |= RELEASE_ALL_BUFFERS; + } + } + + // Look for a free buffer to give to the client + *found = BufferQueueCore::INVALID_BUFFER_SLOT; + int dequeuedCount = 0; + int acquiredCount = 0; + for (int s = 0; s < maxBufferCount; ++s) { + switch (mSlots[s].mBufferState) { + case BufferSlot::DEQUEUED: + ++dequeuedCount; + break; + case BufferSlot::ACQUIRED: + ++acquiredCount; + break; + case BufferSlot::FREE: + // We return the oldest of the free buffers to avoid + // stalling the producer if possible, since the consumer + // may still have pending reads of in-flight buffers + if (*found == BufferQueueCore::INVALID_BUFFER_SLOT || + mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) { + *found = s; + } + break; + default: + break; + } + } + + // Producers are not allowed to dequeue more than one buffer if they + // did not set a buffer count + if (!mCore->mOverrideMaxBufferCount && dequeuedCount) { + BQ_LOGE("%s: can't dequeue multiple buffers without setting the " + "buffer count", caller); + return INVALID_OPERATION; + } + + // See whether a buffer has been queued since the last + // setBufferCount so we know whether to perform the min undequeued + // buffers check below + if (mCore->mBufferHasBeenQueued) { + // Make sure the producer is not trying to dequeue more buffers + // than allowed + const int newUndequeuedCount = + maxBufferCount - (dequeuedCount + 1); + const int minUndequeuedCount = + mCore->getMinUndequeuedBufferCountLocked(async); + if (newUndequeuedCount < minUndequeuedCount) { + BQ_LOGE("%s: min undequeued buffer count (%d) exceeded " + "(dequeued=%d undequeued=%d)", + caller, minUndequeuedCount, + dequeuedCount, newUndequeuedCount); + return INVALID_OPERATION; + } + } + + // If we disconnect and reconnect quickly, we can be in a state where + // our slots are empty but we have many buffers in the queue. This can + // cause us to run out of memory if we outrun the consumer. Wait here if + // it looks like we have too many buffers queued up. + bool tooManyBuffers = mCore->mQueue.size() + > static_cast(maxBufferCount); + if (tooManyBuffers) { + BQ_LOGV("%s: queue size is %zu, waiting", caller, + mCore->mQueue.size()); + } + + // If no buffer is found, or if the queue has too many buffers + // outstanding, wait for a buffer to be acquired or released, or for the + // max buffer count to change. + tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || + tooManyBuffers; + if (tryAgain) { + // Return an error if we're in non-blocking mode (producer and + // consumer are controlled by the application). + // However, the consumer is allowed to briefly acquire an extra + // buffer (which could cause us to have to wait here), which is + // okay, since it is only used to implement an atomic acquire + + // release (e.g., in GLConsumer::updateTexImage()) + if (mCore->mDequeueBufferCannotBlock && + (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { + return WOULD_BLOCK; + } + mCore->mDequeueCondition.wait(mCore->mMutex); + } + } // while (tryAgain) + + return NO_ERROR; +} + +status_t BufferQueueProducer::dequeueBuffer(int *outSlot, + sp *outFence, bool async, + uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { + ATRACE_CALL(); + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + mConsumerName = mCore->mConsumerName; + } // Autolock scope + + BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x", + async ? "true" : "false", width, height, format, usage); + + if ((width && !height) || (!width && height)) { + BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); + return BAD_VALUE; + } + + status_t returnFlags = NO_ERROR; + EGLDisplay eglDisplay = EGL_NO_DISPLAY; + EGLSyncKHR eglFence = EGL_NO_SYNC_KHR; + bool attachedByConsumer = false; + + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(); + + if (format == 0) { + format = mCore->mDefaultBufferFormat; + } + + // Enable the usage bits the consumer requested + usage |= mCore->mConsumerUsageBits; + + int found; + status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, + &found, &returnFlags); + if (status != NO_ERROR) { + return status; + } + + // This should not happen + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + BQ_LOGE("dequeueBuffer: no available buffer slots"); + return -EBUSY; + } + + *outSlot = found; + ATRACE_BUFFER_INDEX(found); + + attachedByConsumer = mSlots[found].mAttachedByConsumer; + + const bool useDefaultSize = !width && !height; + if (useDefaultSize) { + width = mCore->mDefaultWidth; + height = mCore->mDefaultHeight; + } + + mSlots[found].mBufferState = BufferSlot::DEQUEUED; + + const sp& buffer(mSlots[found].mGraphicBuffer); + if ((buffer == NULL) || + (static_cast(buffer->width) != width) || + (static_cast(buffer->height) != height) || + (static_cast(buffer->format) != format) || + ((static_cast(buffer->usage) & usage) != usage)) + { + mSlots[found].mAcquireCalled = false; + mSlots[found].mGraphicBuffer = NULL; + mSlots[found].mRequestBufferCalled = false; + mSlots[found].mEglDisplay = EGL_NO_DISPLAY; + mSlots[found].mEglFence = EGL_NO_SYNC_KHR; + mSlots[found].mFence = Fence::NO_FENCE; + + returnFlags |= BUFFER_NEEDS_REALLOCATION; + } + + if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { + BQ_LOGE("dequeueBuffer: about to return a NULL fence - " + "slot=%d w=%d h=%d format=%u", + found, buffer->width, buffer->height, buffer->format); + } + + eglDisplay = mSlots[found].mEglDisplay; + eglFence = mSlots[found].mEglFence; + *outFence = mSlots[found].mFence; + mSlots[found].mEglFence = EGL_NO_SYNC_KHR; + mSlots[found].mFence = Fence::NO_FENCE; + } // Autolock scope + + if (returnFlags & BUFFER_NEEDS_REALLOCATION) { + status_t error; + BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); + sp graphicBuffer(mCore->mAllocator->createGraphicBuffer( + width, height, format, usage, &error)); + if (graphicBuffer == NULL) { + BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); + return error; + } + + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); + return NO_INIT; + } + + mSlots[*outSlot].mFrameNumber = UINT32_MAX; + mSlots[*outSlot].mGraphicBuffer = graphicBuffer; + } // Autolock scope + } + + if (attachedByConsumer) { + returnFlags |= BUFFER_NEEDS_REALLOCATION; + } + + if (eglFence != EGL_NO_SYNC_KHR) { + EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0, + 1000000000); + // If something goes wrong, log the error, but return the buffer without + // synchronizing access to it. It's too late at this point to abort the + // dequeue operation. + if (result == EGL_FALSE) { + BQ_LOGE("dequeueBuffer: error %#x waiting for fence", + eglGetError()); + } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { + BQ_LOGE("dequeueBuffer: timeout waiting for fence"); + } + eglDestroySyncKHR(eglDisplay, eglFence); + } + + BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", + *outSlot, + mSlots[*outSlot].mFrameNumber, + mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); + + return returnFlags; +} + +status_t BufferQueueProducer::detachBuffer(int slot) { + ATRACE_CALL(); + ATRACE_BUFFER_INDEX(slot); + BQ_LOGV("detachBuffer(P): slot %d", slot); + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("detachBuffer(P): BufferQueue has been abandoned"); + return NO_INIT; + } + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("detachBuffer(P): slot index %d out of range [0, %d)", + slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; + } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { + BQ_LOGE("detachBuffer(P): slot %d is not owned by the producer " + "(state = %d)", slot, mSlots[slot].mBufferState); + return BAD_VALUE; + } else if (!mSlots[slot].mRequestBufferCalled) { + BQ_LOGE("detachBuffer(P): buffer in slot %d has not been requested", + slot); + return BAD_VALUE; + } + + mCore->freeBufferLocked(slot); + mCore->mDequeueCondition.broadcast(); + + return NO_ERROR; +} + +status_t BufferQueueProducer::detachNextBuffer(sp* outBuffer, + sp* outFence) { + ATRACE_CALL(); + + if (outBuffer == NULL) { + BQ_LOGE("detachNextBuffer: outBuffer must not be NULL"); + return BAD_VALUE; + } else if (outFence == NULL) { + BQ_LOGE("detachNextBuffer: outFence must not be NULL"); + return BAD_VALUE; + } + + Mutex::Autolock lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(); + + if (mCore->mIsAbandoned) { + BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned"); + return NO_INIT; + } + + // Find the oldest valid slot + int found = BufferQueueCore::INVALID_BUFFER_SLOT; + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == BufferSlot::FREE && + mSlots[s].mGraphicBuffer != NULL) { + if (found == BufferQueueCore::INVALID_BUFFER_SLOT || + mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { + found = s; + } + } + } + + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + return NO_MEMORY; + } + + BQ_LOGV("detachNextBuffer detached slot %d", found); + + *outBuffer = mSlots[found].mGraphicBuffer; + *outFence = mSlots[found].mFence; + mCore->freeBufferLocked(found); + + return NO_ERROR; +} + +status_t BufferQueueProducer::attachBuffer(int* outSlot, + const sp& buffer) { + ATRACE_CALL(); + + if (outSlot == NULL) { + BQ_LOGE("attachBuffer(P): outSlot must not be NULL"); + return BAD_VALUE; + } else if (buffer == NULL) { + BQ_LOGE("attachBuffer(P): cannot attach NULL buffer"); + return BAD_VALUE; + } + + Mutex::Autolock lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(); + + status_t returnFlags = NO_ERROR; + int found; + // TODO: Should we provide an async flag to attachBuffer? It seems + // unlikely that buffers which we are attaching to a BufferQueue will + // be asynchronous (droppable), but it may not be impossible. + status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false, + &found, &returnFlags); + if (status != NO_ERROR) { + return status; + } + + // This should not happen + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + BQ_LOGE("attachBuffer(P): no available buffer slots"); + return -EBUSY; + } + + *outSlot = found; + ATRACE_BUFFER_INDEX(*outSlot); + BQ_LOGV("attachBuffer(P): returning slot %d flags=%#x", + *outSlot, returnFlags); + + mSlots[*outSlot].mGraphicBuffer = buffer; + mSlots[*outSlot].mBufferState = BufferSlot::DEQUEUED; + mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR; + mSlots[*outSlot].mFence = Fence::NO_FENCE; + mSlots[*outSlot].mRequestBufferCalled = true; + + return returnFlags; +} + +status_t BufferQueueProducer::queueBuffer(int slot, + const QueueBufferInput &input, QueueBufferOutput *output) { + ATRACE_CALL(); + ATRACE_BUFFER_INDEX(slot); + + int64_t timestamp; + bool isAutoTimestamp; + Rect crop; + int scalingMode; + uint32_t transform; + uint32_t stickyTransform; + bool async; + sp fence; + input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, + &async, &fence, &stickyTransform); + + if (fence == NULL) { + BQ_LOGE("queueBuffer: fence is NULL"); + // Temporary workaround for b/17946343: soldier-on instead of returning an error. This + // prevents the client from dying, at the risk of visible corruption due to hwcomposer + // reading the buffer before the producer is done rendering it. Unless the buffer is the + // last frame of an animation, the corruption will be transient. + fence = Fence::NO_FENCE; + // return BAD_VALUE; + } + + switch (scalingMode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: + break; + default: + BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode); + return BAD_VALUE; + } + + sp listener; + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("queueBuffer: BufferQueue has been abandoned"); + return NO_INIT; + } + + const int maxBufferCount = mCore->getMaxBufferCountLocked(async); + if (async && mCore->mOverrideMaxBufferCount) { + // FIXME: Some drivers are manually setting the buffer count + // (which they shouldn't), so we do this extra test here to + // handle that case. This is TEMPORARY until we get this fixed. + if (mCore->mOverrideMaxBufferCount < maxBufferCount) { + BQ_LOGE("queueBuffer: async mode is invalid with " + "buffer count override"); + return BAD_VALUE; + } + } + + if (slot < 0 || slot >= maxBufferCount) { + BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", + slot, maxBufferCount); + return BAD_VALUE; + } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { + BQ_LOGE("queueBuffer: slot %d is not owned by the producer " + "(state = %d)", slot, mSlots[slot].mBufferState); + return BAD_VALUE; + } else if (!mSlots[slot].mRequestBufferCalled) { + BQ_LOGE("queueBuffer: slot %d was queued without requesting " + "a buffer", slot); + return BAD_VALUE; + } + + BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 + " crop=[%d,%d,%d,%d] transform=%#x scale=%s", + slot, mCore->mFrameCounter + 1, timestamp, + crop.left, crop.top, crop.right, crop.bottom, + transform, BufferItem::scalingModeName(scalingMode)); + + const sp& graphicBuffer(mSlots[slot].mGraphicBuffer); + Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); + Rect croppedRect; + crop.intersect(bufferRect, &croppedRect); + if (croppedRect != crop) { + BQ_LOGE("queueBuffer: crop rect is not contained within the " + "buffer in slot %d", slot); + return BAD_VALUE; + } + + mSlots[slot].mFence = fence; + mSlots[slot].mBufferState = BufferSlot::QUEUED; + ++mCore->mFrameCounter; + mSlots[slot].mFrameNumber = mCore->mFrameCounter; + + BufferItem item; + item.mAcquireCalled = mSlots[slot].mAcquireCalled; + item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; + item.mCrop = crop; + item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; + item.mTransformToDisplayInverse = + bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); + item.mScalingMode = scalingMode; + item.mTimestamp = timestamp; + item.mIsAutoTimestamp = isAutoTimestamp; + item.mFrameNumber = mCore->mFrameCounter; + item.mSlot = slot; + item.mFence = fence; + item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; + + mStickyTransform = stickyTransform; + + if (mCore->mQueue.empty()) { + // When the queue is empty, we can ignore mDequeueBufferCannotBlock + // and simply queue this buffer + mCore->mQueue.push_back(item); + listener = mCore->mConsumerListener; + } else { + // When the queue is not empty, we need to look at the front buffer + // state to see if we need to replace it + BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); + if (front->mIsDroppable) { + // If the front queued buffer is still being tracked, we first + // mark it as freed + if (mCore->stillTracking(front)) { + mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + // Reset the frame number of the freed buffer so that it is + // the first in line to be dequeued again + mSlots[front->mSlot].mFrameNumber = 0; + } + // Overwrite the droppable buffer with the incoming one + *front = item; + } else { + mCore->mQueue.push_back(item); + listener = mCore->mConsumerListener; + } + } + + mCore->mBufferHasBeenQueued = true; + mCore->mDequeueCondition.broadcast(); + + output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, + mCore->mTransformHint, mCore->mQueue.size()); + + ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); + } // Autolock scope + + // Call back without lock held + if (listener != NULL) { + listener->onFrameAvailable(); + } + + return NO_ERROR; +} + +void BufferQueueProducer::cancelBuffer(int slot, const sp& fence) { + ATRACE_CALL(); + BQ_LOGV("cancelBuffer: slot %d", slot); + Mutex::Autolock lock(mCore->mMutex); + + if (mCore->mIsAbandoned) { + BQ_LOGE("cancelBuffer: BufferQueue has been abandoned"); + return; + } + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", + slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + return; + } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { + BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " + "(state = %d)", slot, mSlots[slot].mBufferState); + return; + } else if (fence == NULL) { + BQ_LOGE("cancelBuffer: fence is NULL"); + return; + } + + mSlots[slot].mBufferState = BufferSlot::FREE; + mSlots[slot].mFrameNumber = 0; + mSlots[slot].mFence = fence; + mCore->mDequeueCondition.broadcast(); +} + +int BufferQueueProducer::query(int what, int *outValue) { + ATRACE_CALL(); + Mutex::Autolock lock(mCore->mMutex); + + if (outValue == NULL) { + BQ_LOGE("query: outValue was NULL"); + return BAD_VALUE; + } + + if (mCore->mIsAbandoned) { + BQ_LOGE("query: BufferQueue has been abandoned"); + return NO_INIT; + } + + int value; + switch (what) { + case NATIVE_WINDOW_WIDTH: + value = mCore->mDefaultWidth; + break; + case NATIVE_WINDOW_HEIGHT: + value = mCore->mDefaultHeight; + break; + case NATIVE_WINDOW_FORMAT: + value = mCore->mDefaultBufferFormat; + break; + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: + value = mCore->getMinUndequeuedBufferCountLocked(false); + break; + case NATIVE_WINDOW_STICKY_TRANSFORM: + value = static_cast(mStickyTransform); + break; + case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: + value = (mCore->mQueue.size() > 1); + break; + case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + value = mCore->mConsumerUsageBits; + break; + default: + return BAD_VALUE; + } + + BQ_LOGV("query: %d? %d", what, value); + *outValue = value; + return NO_ERROR; +} + +status_t BufferQueueProducer::connect(const sp& listener, + int api, bool producerControlledByApp, QueueBufferOutput *output) { + ATRACE_CALL(); + Mutex::Autolock lock(mCore->mMutex); + mConsumerName = mCore->mConsumerName; + BQ_LOGV("connect(P): api=%d producerControlledByApp=%s", api, + producerControlledByApp ? "true" : "false"); + + if (mCore->mIsAbandoned) { + BQ_LOGE("connect(P): BufferQueue has been abandoned"); + return NO_INIT; + } + + if (mCore->mConsumerListener == NULL) { + BQ_LOGE("connect(P): BufferQueue has no consumer"); + return NO_INIT; + } + + if (output == NULL) { + BQ_LOGE("connect(P): output was NULL"); + return BAD_VALUE; + } + + if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("connect(P): already connected (cur=%d req=%d)", + mCore->mConnectedApi, api); + return BAD_VALUE; + } + + int status = NO_ERROR; + switch (api) { + case NATIVE_WINDOW_API_EGL: + case NATIVE_WINDOW_API_CPU: + case NATIVE_WINDOW_API_MEDIA: + case NATIVE_WINDOW_API_CAMERA: + mCore->mConnectedApi = api; + output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, + mCore->mTransformHint, mCore->mQueue.size()); + + // Set up a death notification so that we can disconnect + // automatically if the remote producer dies + if (listener != NULL && + listener->asBinder()->remoteBinder() != NULL) { + status = listener->asBinder()->linkToDeath( + static_cast(this)); + if (status != NO_ERROR) { + BQ_LOGE("connect(P): linkToDeath failed: %s (%d)", + strerror(-status), status); + } + } + mCore->mConnectedProducerListener = listener; + break; + default: + BQ_LOGE("connect(P): unknown API %d", api); + status = BAD_VALUE; + break; + } + + mCore->mBufferHasBeenQueued = false; + mCore->mDequeueBufferCannotBlock = + mCore->mConsumerControlledByApp && producerControlledByApp; + + return status; +} + +status_t BufferQueueProducer::disconnect(int api) { + ATRACE_CALL(); + BQ_LOGV("disconnect(P): api %d", api); + + int status = NO_ERROR; + sp listener; + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(); + + if (mCore->mIsAbandoned) { + // It's not really an error to disconnect after the surface has + // been abandoned; it should just be a no-op. + return NO_ERROR; + } + + switch (api) { + case NATIVE_WINDOW_API_EGL: + case NATIVE_WINDOW_API_CPU: + case NATIVE_WINDOW_API_MEDIA: + case NATIVE_WINDOW_API_CAMERA: + if (mCore->mConnectedApi == api) { + mCore->freeAllBuffersLocked(); + + // Remove our death notification callback if we have one + if (mCore->mConnectedProducerListener != NULL) { + sp token = + mCore->mConnectedProducerListener->asBinder(); + // This can fail if we're here because of the death + // notification, but we just ignore it + token->unlinkToDeath( + static_cast(this)); + } + mCore->mConnectedProducerListener = NULL; + mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; + mCore->mSidebandStream.clear(); + mCore->mDequeueCondition.broadcast(); + listener = mCore->mConsumerListener; + } else { + BQ_LOGE("disconnect(P): connected to another API " + "(cur=%d req=%d)", mCore->mConnectedApi, api); + status = BAD_VALUE; + } + break; + default: + BQ_LOGE("disconnect(P): unknown API %d", api); + status = BAD_VALUE; + break; + } + } // Autolock scope + + // Call back without lock held + if (listener != NULL) { + listener->onBuffersReleased(); + } + + return status; +} + +status_t BufferQueueProducer::setSidebandStream(const sp& stream) { + sp listener; + { // Autolock scope + Mutex::Autolock _l(mCore->mMutex); + mCore->mSidebandStream = stream; + listener = mCore->mConsumerListener; + } // Autolock scope + + if (listener != NULL) { + listener->onSidebandStreamChanged(); + } + return NO_ERROR; +} + +void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, + uint32_t height, uint32_t format, uint32_t usage) { + ATRACE_CALL(); + while (true) { + Vector freeSlots; + size_t newBufferCount = 0; + uint32_t allocWidth = 0; + uint32_t allocHeight = 0; + uint32_t allocFormat = 0; + uint32_t allocUsage = 0; + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + mCore->waitWhileAllocatingLocked(); + + int currentBufferCount = 0; + for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + if (mSlots[slot].mGraphicBuffer != NULL) { + ++currentBufferCount; + } else { + if (mSlots[slot].mBufferState != BufferSlot::FREE) { + BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE", + slot); + continue; + } + + freeSlots.push_back(slot); + } + } + + int maxBufferCount = mCore->getMaxBufferCountLocked(async); + BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers", + currentBufferCount, maxBufferCount); + if (maxBufferCount <= currentBufferCount) + return; + newBufferCount = maxBufferCount - currentBufferCount; + if (freeSlots.size() < newBufferCount) { + BQ_LOGE("allocateBuffers: ran out of free slots"); + return; + } + allocWidth = width > 0 ? width : mCore->mDefaultWidth; + allocHeight = height > 0 ? height : mCore->mDefaultHeight; + allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; + allocUsage = usage | mCore->mConsumerUsageBits; + + mCore->mIsAllocating = true; + } // Autolock scope + + Vector > buffers; + for (size_t i = 0; i < newBufferCount; ++i) { + status_t result = NO_ERROR; + sp graphicBuffer(mCore->mAllocator->createGraphicBuffer( + allocWidth, allocHeight, allocFormat, allocUsage, &result)); + if (result != NO_ERROR) { + BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format" + " %u, usage %u)", width, height, format, usage); + Mutex::Autolock lock(mCore->mMutex); + mCore->mIsAllocating = false; + mCore->mIsAllocatingCondition.broadcast(); + return; + } + buffers.push_back(graphicBuffer); + } + + { // Autolock scope + Mutex::Autolock lock(mCore->mMutex); + uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; + uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; + uint32_t checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; + uint32_t checkUsage = usage | mCore->mConsumerUsageBits; + if (checkWidth != allocWidth || checkHeight != allocHeight || + checkFormat != allocFormat || checkUsage != allocUsage) { + // Something changed while we released the lock. Retry. + BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying."); + mCore->mIsAllocating = false; + mCore->mIsAllocatingCondition.broadcast(); + continue; + } + + for (size_t i = 0; i < newBufferCount; ++i) { + int slot = freeSlots[i]; + if (mSlots[slot].mBufferState != BufferSlot::FREE) { + // A consumer allocated the FREE slot with attachBuffer. Discard the buffer we + // allocated. + BQ_LOGV("allocateBuffers: slot %d was acquired while allocating. " + "Dropping allocated buffer.", slot); + continue; + } + mCore->freeBufferLocked(slot); // Clean up the slot first + mSlots[slot].mGraphicBuffer = buffers[i]; + mSlots[slot].mFrameNumber = 0; + mSlots[slot].mFence = Fence::NO_FENCE; + BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot); + } + + mCore->mIsAllocating = false; + mCore->mIsAllocatingCondition.broadcast(); + } // Autolock scope + } +} + +void BufferQueueProducer::binderDied(const wp& /* who */) { + // If we're here, it means that a producer we were connected to died. + // We're guaranteed that we are still connected to it because we remove + // this callback upon disconnect. It's therefore safe to read mConnectedApi + // without synchronization here. + int api = mCore->mConnectedApi; + disconnect(api); +} + +} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h new file mode 100644 index 000000000000..3fc5de2dd1ee --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h @@ -0,0 +1,204 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERQUEUEPRODUCER_H +#define ANDROID_GUI_BUFFERQUEUEPRODUCER_H + +#include +#include + +namespace android { + +class BufferSlot; + +class BufferQueueProducer : public BnGraphicBufferProducer, + private IBinder::DeathRecipient { +public: + friend class BufferQueue; // Needed to access binderDied + + BufferQueueProducer(const sp& core); + virtual ~BufferQueueProducer(); + + // requestBuffer returns the GraphicBuffer for slot N. + // + // In normal operation, this is called the first time slot N is returned + // by dequeueBuffer. It must be called again if dequeueBuffer returns + // flags indicating that previously-returned buffers are no longer valid. + virtual status_t requestBuffer(int slot, sp* buf); + + // setBufferCount updates the number of available buffer slots. If this + // method succeeds, buffer slots will be both unallocated and owned by + // the BufferQueue object (i.e. they are not owned by the producer or + // consumer). + // + // This will fail if the producer has dequeued any buffers, or if + // bufferCount is invalid. bufferCount must generally be a value + // between the minimum undequeued buffer count (exclusive) and NUM_BUFFER_SLOTS + // (inclusive). It may also be set to zero (the default) to indicate + // that the producer does not wish to set a value. The minimum value + // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + // ...). + // + // This may only be called by the producer. The consumer will be told + // to discard buffers through the onBuffersReleased callback. + virtual status_t setBufferCount(int bufferCount); + + // dequeueBuffer gets the next buffer slot index for the producer to use. + // If a buffer slot is available then that slot index is written to the + // location pointed to by the buf argument and a status of OK is returned. + // If no slot is available then a status of -EBUSY is returned and buf is + // unmodified. + // + // The outFence parameter will be updated to hold the fence associated with + // the buffer. The contents of the buffer must not be overwritten until the + // fence signals. If the fence is Fence::NO_FENCE, the buffer may be + // written immediately. + // + // The width and height parameters must be no greater than the minimum of + // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). + // An error due to invalid dimensions might not be reported until + // updateTexImage() is called. If width and height are both zero, the + // default values specified by setDefaultBufferSize() are used instead. + // + // The pixel formats are enumerated in graphics.h, e.g. + // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format + // will be used. + // + // The usage argument specifies gralloc buffer usage flags. The values + // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These + // will be merged with the usage flags specified by setConsumerUsageBits. + // + // The return value may be a negative error value or a non-negative + // collection of flags. If the flags are set, the return values are + // valid, but additional actions must be performed. + // + // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the + // producer must discard cached GraphicBuffer references for the slot + // returned in buf. + // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer + // must discard cached GraphicBuffer references for all slots. + // + // In both cases, the producer will need to call requestBuffer to get a + // GraphicBuffer handle for the returned slot. + virtual status_t dequeueBuffer(int *outSlot, sp* outFence, bool async, + uint32_t width, uint32_t height, uint32_t format, uint32_t usage); + + // See IGraphicBufferProducer::detachBuffer + virtual status_t detachBuffer(int slot); + + // See IGraphicBufferProducer::detachNextBuffer + virtual status_t detachNextBuffer(sp* outBuffer, + sp* outFence); + + // See IGraphicBufferProducer::attachBuffer + virtual status_t attachBuffer(int* outSlot, const sp& buffer); + + // queueBuffer returns a filled buffer to the BufferQueue. + // + // Additional data is provided in the QueueBufferInput struct. Notably, + // a timestamp must be provided for the buffer. The timestamp is in + // nanoseconds, and must be monotonically increasing. Its other semantics + // (zero point, etc) are producer-specific and should be documented by the + // producer. + // + // The caller may provide a fence that signals when all rendering + // operations have completed. Alternatively, NO_FENCE may be used, + // indicating that the buffer is ready immediately. + // + // Some values are returned in the output struct: the current settings + // for default width and height, the current transform hint, and the + // number of queued buffers. + virtual status_t queueBuffer(int slot, + const QueueBufferInput& input, QueueBufferOutput* output); + + // cancelBuffer returns a dequeued buffer to the BufferQueue, but doesn't + // queue it for use by the consumer. + // + // The buffer will not be overwritten until the fence signals. The fence + // will usually be the one obtained from dequeueBuffer. + virtual void cancelBuffer(int slot, const sp& fence); + + // Query native window attributes. The "what" values are enumerated in + // window.h (e.g. NATIVE_WINDOW_FORMAT). + virtual int query(int what, int* outValue); + + // connect attempts to connect a producer API to the BufferQueue. This + // must be called before any other IGraphicBufferProducer methods are + // called except for getAllocator. A consumer must already be connected. + // + // This method will fail if connect was previously called on the + // BufferQueue and no corresponding disconnect call was made (i.e. if + // it's still connected to a producer). + // + // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). + virtual status_t connect(const sp& listener, + int api, bool producerControlledByApp, QueueBufferOutput* output); + + // disconnect attempts to disconnect a producer API from the BufferQueue. + // Calling this method will cause any subsequent calls to other + // IGraphicBufferProducer methods to fail except for getAllocator and connect. + // Successfully calling connect after this will allow the other methods to + // succeed again. + // + // This method will fail if the the BufferQueue is not currently + // connected to the specified producer API. + virtual status_t disconnect(int api); + + // Attaches a sideband buffer stream to the IGraphicBufferProducer. + // + // A sideband stream is a device-specific mechanism for passing buffers + // from the producer to the consumer without using dequeueBuffer/ + // queueBuffer. If a sideband stream is present, the consumer can choose + // whether to acquire buffers from the sideband stream or from the queued + // buffers. + // + // Passing NULL or a different stream handle will detach the previous + // handle if any. + virtual status_t setSidebandStream(const sp& stream); + + // See IGraphicBufferProducer::allocateBuffers + virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, + uint32_t format, uint32_t usage); + +private: + // This is required by the IBinder::DeathRecipient interface + virtual void binderDied(const wp& who); + + // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may + // block if there are no available slots and we are not in non-blocking + // mode (producer and consumer controlled by the application). If it blocks, + // it will release mCore->mMutex while blocked so that other operations on + // the BufferQueue may succeed. + status_t waitForFreeSlotThenRelock(const char* caller, bool async, + int* found, status_t* returnFlags) const; + + sp mCore; + + // This references mCore->mSlots. Lock mCore->mMutex while accessing. + BufferQueueDefs::SlotsType& mSlots; + + // This is a cached copy of the name stored in the BufferQueueCore. + // It's updated during connect and dequeueBuffer (which should catch + // most updates). + String8 mConsumerName; + + uint32_t mStickyTransform; + +}; // class BufferQueueProducer + +} // namespace android + +#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp new file mode 100644 index 000000000000..b8877fef617f --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace android { + +const char* BufferSlot::bufferStateName(BufferState state) { + switch (state) { + case BufferSlot::DEQUEUED: return "DEQUEUED"; + case BufferSlot::QUEUED: return "QUEUED"; + case BufferSlot::FREE: return "FREE"; + case BufferSlot::ACQUIRED: return "ACQUIRED"; + default: return "Unknown"; + } +} + +} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h new file mode 100644 index 000000000000..6085e116a3d6 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h @@ -0,0 +1,142 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERSLOT_H +#define ANDROID_GUI_BUFFERSLOT_H + +#include +#include + +#include +#include + +#include + +namespace android { + +class Fence; + +struct BufferSlot { + + BufferSlot() + : mEglDisplay(EGL_NO_DISPLAY), + mBufferState(BufferSlot::FREE), + mRequestBufferCalled(false), + mFrameNumber(0), + mEglFence(EGL_NO_SYNC_KHR), + mAcquireCalled(false), + mNeedsCleanupOnRelease(false), + mAttachedByConsumer(false) { + } + + // mGraphicBuffer points to the buffer allocated for this slot or is NULL + // if no buffer has been allocated. + sp mGraphicBuffer; + + // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects. + EGLDisplay mEglDisplay; + + // BufferState represents the different states in which a buffer slot + // can be. All slots are initially FREE. + enum BufferState { + // FREE indicates that the buffer is available to be dequeued + // by the producer. The buffer may be in use by the consumer for + // a finite time, so the buffer must not be modified until the + // associated fence is signaled. + // + // The slot is "owned" by BufferQueue. It transitions to DEQUEUED + // when dequeueBuffer is called. + FREE = 0, + + // DEQUEUED indicates that the buffer has been dequeued by the + // producer, but has not yet been queued or canceled. The + // producer may modify the buffer's contents as soon as the + // associated ready fence is signaled. + // + // The slot is "owned" by the producer. It can transition to + // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer). + DEQUEUED = 1, + + // QUEUED indicates that the buffer has been filled by the + // producer and queued for use by the consumer. The buffer + // contents may continue to be modified for a finite time, so + // the contents must not be accessed until the associated fence + // is signaled. + // + // The slot is "owned" by BufferQueue. It can transition to + // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is + // queued in asynchronous mode). + QUEUED = 2, + + // ACQUIRED indicates that the buffer has been acquired by the + // consumer. As with QUEUED, the contents must not be accessed + // by the consumer until the fence is signaled. + // + // The slot is "owned" by the consumer. It transitions to FREE + // when releaseBuffer is called. + ACQUIRED = 3 + }; + + static const char* bufferStateName(BufferState state); + + // mBufferState is the current state of this buffer slot. + BufferState mBufferState; + + // mRequestBufferCalled is used for validating that the producer did + // call requestBuffer() when told to do so. Technically this is not + // needed but useful for debugging and catching producer bugs. + bool mRequestBufferCalled; + + // mFrameNumber is the number of the queued frame for this slot. This + // is used to dequeue buffers in LRU order (useful because buffers + // may be released before their release fence is signaled). + uint64_t mFrameNumber; + + // mEglFence is the EGL sync object that must signal before the buffer + // associated with this buffer slot may be dequeued. It is initialized + // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a + // new sync object in releaseBuffer. (This is deprecated in favor of + // mFence, below.) + EGLSyncKHR mEglFence; + + // mFence is a fence which will signal when work initiated by the + // previous owner of the buffer is finished. When the buffer is FREE, + // the fence indicates when the consumer has finished reading + // from the buffer, or when the producer has finished writing if it + // called cancelBuffer after queueing some writes. When the buffer is + // QUEUED, it indicates when the producer has finished filling the + // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been + // passed to the consumer or producer along with ownership of the + // buffer, and mFence is set to NO_FENCE. + sp mFence; + + // Indicates whether this buffer has been seen by a consumer yet + bool mAcquireCalled; + + // Indicates whether this buffer needs to be cleaned up by the + // consumer. This is set when a buffer in ACQUIRED state is freed. + // It causes releaseBuffer to return STALE_BUFFER_SLOT. + bool mNeedsCleanupOnRelease; + + // Indicates whether the buffer was attached on the consumer side. + // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued + // to prevent the producer from using a stale cached buffer. + bool mAttachedByConsumer; +}; + +} // namespace android + +#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp new file mode 100644 index 000000000000..f19b6c7737df --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "ConsumerBase" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#define EGL_EGLEXT_PROTOTYPES + +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +// Macros for including the ConsumerBase name in log messages +#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) + +namespace android { + +// Get an ID that's unique within this process. +static int32_t createProcessUniqueId() { + static volatile int32_t globalCounter = 0; + return android_atomic_inc(&globalCounter); +} + +ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : + mAbandoned(false), + mConsumer(bufferQueue) { + // Choose a name using the PID and a process-unique ID. + mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); + + // Note that we can't create an sp<...>(this) in a ctor that will not keep a + // reference once the ctor ends, as that would cause the refcount of 'this' + // dropping to 0 at the end of the ctor. Since all we need is a wp<...> + // that's what we create. + wp listener = static_cast(this); + sp proxy = new BufferQueue::ProxyConsumerListener(listener); + + status_t err = mConsumer->consumerConnect(proxy, controlledByApp); + if (err != NO_ERROR) { + CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", + strerror(-err), err); + } else { + mConsumer->setConsumerName(mName); + } +} + +ConsumerBase::~ConsumerBase() { + CB_LOGV("~ConsumerBase"); + Mutex::Autolock lock(mMutex); + + // Verify that abandon() has been called before we get here. This should + // be done by ConsumerBase::onLastStrongRef(), but it's possible for a + // derived class to override that method and not call + // ConsumerBase::onLastStrongRef(). + LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the " + "consumer is not abandoned!", mName.string()); +} + +void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { + abandon(); +} + +void ConsumerBase::freeBufferLocked(int slotIndex) { + CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); + mSlots[slotIndex].mGraphicBuffer = 0; + mSlots[slotIndex].mFence = Fence::NO_FENCE; + mSlots[slotIndex].mFrameNumber = 0; +} + +void ConsumerBase::onFrameAvailable() { + CB_LOGV("onFrameAvailable"); + + sp listener; + { // scope for the lock + Mutex::Autolock lock(mMutex); + listener = mFrameAvailableListener.promote(); + } + + if (listener != NULL) { + CB_LOGV("actually calling onFrameAvailable"); + listener->onFrameAvailable(); + } +} + +void ConsumerBase::onBuffersReleased() { + Mutex::Autolock lock(mMutex); + + CB_LOGV("onBuffersReleased"); + + if (mAbandoned) { + // Nothing to do if we're already abandoned. + return; + } + + uint64_t mask = 0; + mConsumer->getReleasedBuffers(&mask); + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + if (mask & (1ULL << i)) { + freeBufferLocked(i); + } + } +} + +void ConsumerBase::onSidebandStreamChanged() { +} + +void ConsumerBase::abandon() { + CB_LOGV("abandon"); + Mutex::Autolock lock(mMutex); + + if (!mAbandoned) { + abandonLocked(); + mAbandoned = true; + } +} + +void ConsumerBase::abandonLocked() { + CB_LOGV("abandonLocked"); + for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + freeBufferLocked(i); + } + // disconnect from the BufferQueue + mConsumer->consumerDisconnect(); + mConsumer.clear(); +} + +void ConsumerBase::setFrameAvailableListener( + const wp& listener) { + CB_LOGV("setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = listener; +} + +void ConsumerBase::dump(String8& result) const { + dump(result, ""); +} + +void ConsumerBase::dump(String8& result, const char* prefix) const { + Mutex::Autolock _l(mMutex); + dumpLocked(result, prefix); +} + +void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { + result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); + + if (!mAbandoned) { + mConsumer->dump(result, prefix); + } +} + +status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item, + nsecs_t presentWhen) { + status_t err = mConsumer->acquireBuffer(item, presentWhen); + if (err != NO_ERROR) { + return err; + } + + if (item->mGraphicBuffer != NULL) { + mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; + } + + mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; + mSlots[item->mBuf].mFence = item->mFence; + + CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, + item->mBuf, item->mFrameNumber); + + return OK; +} + +status_t ConsumerBase::addReleaseFence(int slot, + const sp graphicBuffer, const sp& fence) { + Mutex::Autolock lock(mMutex); + return addReleaseFenceLocked(slot, graphicBuffer, fence); +} + +status_t ConsumerBase::addReleaseFenceLocked(int slot, + const sp graphicBuffer, const sp& fence) { + CB_LOGV("addReleaseFenceLocked: slot=%d", slot); + + // If consumer no longer tracks this graphicBuffer, we can safely + // drop this fence, as it will never be received by the producer. + if (!stillTracking(slot, graphicBuffer)) { + return OK; + } + + if (!mSlots[slot].mFence.get()) { + mSlots[slot].mFence = fence; + } else { + sp mergedFence = Fence::merge( + String8::format("%.28s:%d", mName.string(), slot), + mSlots[slot].mFence, fence); + if (!mergedFence.get()) { + CB_LOGE("failed to merge release fences"); + // synchronization is broken, the best we can do is hope fences + // signal in order so the new fence will act like a union + mSlots[slot].mFence = fence; + return BAD_VALUE; + } + mSlots[slot].mFence = mergedFence; + } + + return OK; +} + +status_t ConsumerBase::releaseBufferLocked( + int slot, const sp graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) { + // If consumer no longer tracks this graphicBuffer (we received a new + // buffer on the same slot), the buffer producer is definitely no longer + // tracking it. + if (!stillTracking(slot, graphicBuffer)) { + return OK; + } + + CB_LOGV("releaseBufferLocked: slot=%d/%" PRIu64, + slot, mSlots[slot].mFrameNumber); + status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, + display, eglFence, mSlots[slot].mFence); + if (err == IGraphicBufferConsumer::STALE_BUFFER_SLOT) { + freeBufferLocked(slot); + } + + mSlots[slot].mFence = Fence::NO_FENCE; + + return err; +} + +bool ConsumerBase::stillTracking(int slot, + const sp graphicBuffer) { + if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { + return false; + } + return (mSlots[slot].mGraphicBuffer != NULL && + mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); +} + +} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h b/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h new file mode 100644 index 000000000000..100bb260f918 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_CONSUMERBASE_H +#define ANDROID_GUI_CONSUMERBASE_H + +#include + +#include + +#include +#include +#include +#include + +namespace android { +// ---------------------------------------------------------------------------- + +class String8; + +// ConsumerBase is a base class for BufferQueue consumer end-points. It +// handles common tasks like management of the connection to the BufferQueue +// and the buffer pool. +class ConsumerBase : public virtual RefBase, + protected ConsumerListener { +public: + struct FrameAvailableListener : public virtual RefBase { + // onFrameAvailable() is called each time an additional frame becomes + // available for consumption. This means that frames that are queued + // while in asynchronous mode only trigger the callback if no previous + // frames are pending. Frames queued while in synchronous mode always + // trigger the callback. + // + // This is called without any lock held and can be called concurrently + // by multiple threads. + virtual void onFrameAvailable() = 0; + }; + + virtual ~ConsumerBase(); + + // abandon frees all the buffers and puts the ConsumerBase into the + // 'abandoned' state. Once put in this state the ConsumerBase can never + // leave it. When in the 'abandoned' state, all methods of the + // IGraphicBufferProducer interface will fail with the NO_INIT error. + // + // Note that while calling this method causes all the buffers to be freed + // from the perspective of the the ConsumerBase, if there are additional + // references on the buffers (e.g. if a buffer is referenced by a client + // or by OpenGL ES as a texture) then those buffer will remain allocated. + void abandon(); + + // set the name of the ConsumerBase that will be used to identify it in + // log messages. + void setName(const String8& name); + + // dump writes the current state to a string. Child classes should add + // their state to the dump by overriding the dumpLocked method, which is + // called by these methods after locking the mutex. + void dump(String8& result) const; + void dump(String8& result, const char* prefix) const; + + // setFrameAvailableListener sets the listener object that will be notified + // when a new frame becomes available. + void setFrameAvailableListener(const wp& listener); + +private: + ConsumerBase(const ConsumerBase&); + void operator=(const ConsumerBase&); + +protected: + // ConsumerBase constructs a new ConsumerBase object to consume image + // buffers from the given IGraphicBufferConsumer. + // The controlledByApp flag indicates that this consumer is under the application's + // control. + ConsumerBase(const sp& consumer, bool controlledByApp = false); + + // onLastStrongRef gets called by RefBase just before the dtor of the most + // derived class. It is used to clean up the buffers so that ConsumerBase + // can coordinate the clean-up by calling into virtual methods implemented + // by the derived classes. This would not be possible from the + // ConsuemrBase dtor because by the time that gets called the derived + // classes have already been destructed. + // + // This methods should not need to be overridden by derived classes, but + // if they are overridden the ConsumerBase implementation must be called + // from the derived class. + virtual void onLastStrongRef(const void* id); + + // Implementation of the IConsumerListener interface. These + // calls are used to notify the ConsumerBase of asynchronous events in the + // BufferQueue. The onFrameAvailable and onBuffersReleased methods should + // not need to be overridden by derived classes, but if they are overridden + // the ConsumerBase implementation must be called from the derived class. + // The ConsumerBase version of onSidebandStreamChanged does nothing and can + // be overriden by derived classes if they want the notification. + virtual void onFrameAvailable(); + virtual void onBuffersReleased(); + virtual void onSidebandStreamChanged(); + + // freeBufferLocked frees up the given buffer slot. If the slot has been + // initialized this will release the reference to the GraphicBuffer in that + // slot. Otherwise it has no effect. + // + // Derived classes should override this method to clean up any state they + // keep per slot. If it is overridden, the derived class's implementation + // must call ConsumerBase::freeBufferLocked. + // + // This method must be called with mMutex locked. + virtual void freeBufferLocked(int slotIndex); + + // abandonLocked puts the BufferQueue into the abandoned state, causing + // all future operations on it to fail. This method rather than the public + // abandon method should be overridden by child classes to add abandon- + // time behavior. + // + // Derived classes should override this method to clean up any object + // state they keep (as opposed to per-slot state). If it is overridden, + // the derived class's implementation must call ConsumerBase::abandonLocked. + // + // This method must be called with mMutex locked. + virtual void abandonLocked(); + + // dumpLocked dumps the current state of the ConsumerBase object to the + // result string. Each line is prefixed with the string pointed to by the + // prefix argument. The buffer argument points to a buffer that may be + // used for intermediate formatting data, and the size of that buffer is + // indicated by the size argument. + // + // Derived classes should override this method to dump their internal + // state. If this method is overridden the derived class's implementation + // should call ConsumerBase::dumpLocked. + // + // This method must be called with mMutex locked. + virtual void dumpLocked(String8& result, const char* prefix) const; + + // acquireBufferLocked fetches the next buffer from the BufferQueue and + // updates the buffer slot for the buffer returned. + // + // Derived classes should override this method to perform any + // initialization that must take place the first time a buffer is assigned + // to a slot. If it is overridden the derived class's implementation must + // call ConsumerBase::acquireBufferLocked. + virtual status_t acquireBufferLocked(IGraphicBufferConsumer::BufferItem *item, + nsecs_t presentWhen); + + // releaseBufferLocked relinquishes control over a buffer, returning that + // control to the BufferQueue. + // + // Derived classes should override this method to perform any cleanup that + // must take place when a buffer is released back to the BufferQueue. If + // it is overridden the derived class's implementation must call + // ConsumerBase::releaseBufferLocked.e + virtual status_t releaseBufferLocked(int slot, + const sp graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence); + + // returns true iff the slot still has the graphicBuffer in it. + bool stillTracking(int slot, const sp graphicBuffer); + + // addReleaseFence* adds the sync points associated with a fence to the set + // of sync points that must be reached before the buffer in the given slot + // may be used after the slot has been released. This should be called by + // derived classes each time some asynchronous work is kicked off that + // references the buffer. + status_t addReleaseFence(int slot, + const sp graphicBuffer, const sp& fence); + status_t addReleaseFenceLocked(int slot, + const sp graphicBuffer, const sp& fence); + + // Slot contains the information and object references that + // ConsumerBase maintains about a BufferQueue buffer slot. + struct Slot { + // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if + // no Gralloc buffer is in the slot. + sp mGraphicBuffer; + + // mFence is a fence which will signal when the buffer associated with + // this buffer slot is no longer being used by the consumer and can be + // overwritten. The buffer can be dequeued before the fence signals; + // the producer is responsible for delaying writes until it signals. + sp mFence; + + // the frame number of the last acquired frame for this slot + uint64_t mFrameNumber; + }; + + // mSlots stores the buffers that have been allocated by the BufferQueue + // for each buffer slot. It is initialized to null pointers, and gets + // filled in with the result of BufferQueue::acquire when the + // client dequeues a buffer from a + // slot that has not yet been used. The buffer allocated to a slot will also + // be replaced if the requested buffer usage or geometry differs from that + // of the buffer allocated to a slot. + Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS]; + + // mAbandoned indicates that the BufferQueue will no longer be used to + // consume images buffers pushed to it using the IGraphicBufferProducer + // interface. It is initialized to false, and set to true in the abandon + // method. A BufferQueue that has been abandoned will return the NO_INIT + // error from all IConsumerBase methods capable of returning an error. + bool mAbandoned; + + // mName is a string used to identify the ConsumerBase in log messages. + // It can be set by the setName method. + String8 mName; + + // mFrameAvailableListener is the listener object that will be called when a + // new frame becomes available. If it is not NULL it will be called from + // queueBuffer. + wp mFrameAvailableListener; + + // The ConsumerBase has-a BufferQueue and is responsible for creating this object + // if none is supplied + sp mConsumer; + + // mMutex is the mutex used to prevent concurrent access to the member + // variables of ConsumerBase objects. It must be locked whenever the + // member variables are accessed or when any of the *Locked methods are + // called. + // + // This mutex is intended to be locked by derived classes. + mutable Mutex mMutex; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_CONSUMERBASE_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp new file mode 100644 index 000000000000..f6d087d3b297 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +namespace android { +// --------------------------------------------------------------------------- + +IGraphicBufferConsumer::BufferItem::BufferItem() : + mTransform(0), + mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mTimestamp(0), + mIsAutoTimestamp(false), + mFrameNumber(0), + mBuf(INVALID_BUFFER_SLOT), + mIsDroppable(false), + mAcquireCalled(false), + mTransformToDisplayInverse(false) { + mCrop.makeInvalid(); +} + +size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { + size_t c = sizeof(mCrop) + + sizeof(mTransform) + + sizeof(mScalingMode) + + sizeof(mTimestamp) + + sizeof(mIsAutoTimestamp) + + sizeof(mFrameNumber) + + sizeof(mBuf) + + sizeof(mIsDroppable) + + sizeof(mAcquireCalled) + + sizeof(mTransformToDisplayInverse); + return c; +} + +size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const { + size_t c = 0; + if (mGraphicBuffer != 0) { + c += mGraphicBuffer->getFlattenedSize(); + c = FlattenableUtils::align<4>(c); + } + if (mFence != 0) { + c += mFence->getFlattenedSize(); + c = FlattenableUtils::align<4>(c); + } + return sizeof(int32_t) + c + getPodSize(); +} + +size_t IGraphicBufferConsumer::BufferItem::getFdCount() const { + size_t c = 0; + if (mGraphicBuffer != 0) { + c += mGraphicBuffer->getFdCount(); + } + if (mFence != 0) { + c += mFence->getFdCount(); + } + return c; +} + +static void writeBoolAsInt(void*& buffer, size_t& size, bool b) { + FlattenableUtils::write(buffer, size, static_cast(b)); +} + +static bool readBoolFromInt(void const*& buffer, size_t& size) { + int32_t i; + FlattenableUtils::read(buffer, size, i); + return static_cast(i); +} + +status_t IGraphicBufferConsumer::BufferItem::flatten( + void*& buffer, size_t& size, int*& fds, size_t& count) const { + + // make sure we have enough space + if (size < BufferItem::getFlattenedSize()) { + return NO_MEMORY; + } + + // content flags are stored first + uint32_t& flags = *static_cast(buffer); + + // advance the pointer + FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); + + flags = 0; + if (mGraphicBuffer != 0) { + status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + flags |= 1; + } + if (mFence != 0) { + status_t err = mFence->flatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + flags |= 2; + } + + // check we have enough space (in case flattening the fence/graphicbuffer lied to us) + if (size < getPodSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, mCrop); + FlattenableUtils::write(buffer, size, mTransform); + FlattenableUtils::write(buffer, size, mScalingMode); + FlattenableUtils::write(buffer, size, mTimestamp); + writeBoolAsInt(buffer, size, mIsAutoTimestamp); + FlattenableUtils::write(buffer, size, mFrameNumber); + FlattenableUtils::write(buffer, size, mBuf); + writeBoolAsInt(buffer, size, mIsDroppable); + writeBoolAsInt(buffer, size, mAcquireCalled); + writeBoolAsInt(buffer, size, mTransformToDisplayInverse); + + return NO_ERROR; +} + +status_t IGraphicBufferConsumer::BufferItem::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) { + + if (size < sizeof(uint32_t)) + return NO_MEMORY; + + uint32_t flags = 0; + FlattenableUtils::read(buffer, size, flags); + + if (flags & 1) { + mGraphicBuffer = new GraphicBuffer(); + status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + } + + if (flags & 2) { + mFence = new Fence(); + status_t err = mFence->unflatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + } + + // check we have enough space + if (size < getPodSize()) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, mCrop); + FlattenableUtils::read(buffer, size, mTransform); + FlattenableUtils::read(buffer, size, mScalingMode); + FlattenableUtils::read(buffer, size, mTimestamp); + mIsAutoTimestamp = readBoolFromInt(buffer, size); + FlattenableUtils::read(buffer, size, mFrameNumber); + FlattenableUtils::read(buffer, size, mBuf); + mIsDroppable = readBoolFromInt(buffer, size); + mAcquireCalled = readBoolFromInt(buffer, size); + mTransformToDisplayInverse = readBoolFromInt(buffer, size); + + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + +enum { + ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + DETACH_BUFFER, + ATTACH_BUFFER, + RELEASE_BUFFER, + CONSUMER_CONNECT, + CONSUMER_DISCONNECT, + GET_RELEASED_BUFFERS, + SET_DEFAULT_BUFFER_SIZE, + SET_DEFAULT_MAX_BUFFER_COUNT, + DISABLE_ASYNC_BUFFER, + SET_MAX_ACQUIRED_BUFFER_COUNT, + SET_CONSUMER_NAME, + SET_DEFAULT_BUFFER_FORMAT, + SET_CONSUMER_USAGE_BITS, + SET_TRANSFORM_HINT, + GET_SIDEBAND_STREAM, + DUMP, +}; + + +class BpGraphicBufferConsumer : public BpInterface +{ +public: + BpGraphicBufferConsumer(const sp& impl) + : BpInterface(impl) + { + } + + virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt64(presentWhen); + status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.read(*buffer); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t detachBuffer(int slot) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(slot); + status_t result = remote()->transact(DETACH_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; + } + + virtual status_t attachBuffer(int* slot, const sp& buffer) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.write(*buffer.get()); + status_t result = remote()->transact(ATTACH_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + *slot = reply.readInt32(); + result = reply.readInt32(); + return result; + } + + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, + EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)), + const sp& releaseFence) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(buf); + data.writeInt64(frameNumber); + data.write(*releaseFence); + status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeStrongBinder(consumer->asBinder()); + data.writeInt32(controlledByApp); + status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t consumerDisconnect() { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t getReleasedBuffers(uint64_t* slotMask) { + Parcel data, reply; + if (slotMask == NULL) { + ALOGE("getReleasedBuffers: slotMask must not be NULL"); + return BAD_VALUE; + } + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); + if (result != NO_ERROR) { + return result; + } + *slotMask = reply.readInt64(); + return reply.readInt32(); + } + + virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(w); + data.writeInt32(h); + status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setDefaultMaxBufferCount(int bufferCount) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(bufferCount); + status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t disableAsyncBuffer() { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(maxAcquiredBuffers); + status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual void setConsumerName(const String8& name) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeString8(name); + remote()->transact(SET_CONSUMER_NAME, data, &reply); + } + + virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(defaultFormat); + status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setConsumerUsageBits(uint32_t usage) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(usage); + status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setTransformHint(uint32_t hint) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(hint); + status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual sp getSidebandStream() const { + Parcel data, reply; + status_t err; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) { + return NULL; + } + sp stream; + if (reply.readInt32()) { + stream = NativeHandle::create(reply.readNativeHandle(), true); + } + return stream; + } + + virtual void dump(String8& result, const char* prefix) const { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeString8(result); + data.writeString8(String8(prefix ? prefix : "")); + remote()->transact(DUMP, data, &reply); + reply.readString8(); + } +}; + +IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer"); + +// ---------------------------------------------------------------------- + +status_t BnGraphicBufferConsumer::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case ACQUIRE_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + BufferItem item; + int64_t presentWhen = data.readInt64(); + status_t result = acquireBuffer(&item, presentWhen); + status_t err = reply->write(item); + if (err) return err; + reply->writeInt32(result); + return NO_ERROR; + } break; + case DETACH_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + int slot = data.readInt32(); + int result = detachBuffer(slot); + reply->writeInt32(result); + return NO_ERROR; + } break; + case ATTACH_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + sp buffer = new GraphicBuffer(); + data.read(*buffer.get()); + int slot; + int result = attachBuffer(&slot, buffer); + reply->writeInt32(slot); + reply->writeInt32(result); + return NO_ERROR; + } break; + case RELEASE_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + int buf = data.readInt32(); + uint64_t frameNumber = data.readInt64(); + sp releaseFence = new Fence(); + status_t err = data.read(*releaseFence); + if (err) return err; + status_t result = releaseBuffer(buf, frameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); + reply->writeInt32(result); + return NO_ERROR; + } break; + case CONSUMER_CONNECT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + sp consumer = IConsumerListener::asInterface( data.readStrongBinder() ); + bool controlledByApp = data.readInt32(); + status_t result = consumerConnect(consumer, controlledByApp); + reply->writeInt32(result); + return NO_ERROR; + } break; + case CONSUMER_DISCONNECT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + status_t result = consumerDisconnect(); + reply->writeInt32(result); + return NO_ERROR; + } break; + case GET_RELEASED_BUFFERS: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint64_t slotMask; + status_t result = getReleasedBuffers(&slotMask); + reply->writeInt64(slotMask); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_DEFAULT_BUFFER_SIZE: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + status_t result = setDefaultBufferSize(w, h); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_DEFAULT_MAX_BUFFER_COUNT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t bufferCount = data.readInt32(); + status_t result = setDefaultMaxBufferCount(bufferCount); + reply->writeInt32(result); + return NO_ERROR; + } break; + case DISABLE_ASYNC_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + status_t result = disableAsyncBuffer(); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_MAX_ACQUIRED_BUFFER_COUNT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t maxAcquiredBuffers = data.readInt32(); + status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_CONSUMER_NAME: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + setConsumerName( data.readString8() ); + return NO_ERROR; + } break; + case SET_DEFAULT_BUFFER_FORMAT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t defaultFormat = data.readInt32(); + status_t result = setDefaultBufferFormat(defaultFormat); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_CONSUMER_USAGE_BITS: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t usage = data.readInt32(); + status_t result = setConsumerUsageBits(usage); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_TRANSFORM_HINT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t hint = data.readInt32(); + status_t result = setTransformHint(hint); + reply->writeInt32(result); + return NO_ERROR; + } break; + case DUMP: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + String8 result = data.readString8(); + String8 prefix = data.readString8(); + static_cast(this)->dump(result, prefix); + reply->writeString8(result); + return NO_ERROR; + } + } + return BBinder::onTransact(code, data, reply, flags); +} + +}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h new file mode 100644 index 000000000000..15f51fe8c0f2 --- /dev/null +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H +#define ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +namespace android { +// ---------------------------------------------------------------------------- + +class Fence; +class GraphicBuffer; +class IConsumerListener; +class NativeHandle; + +class IGraphicBufferConsumer : public IInterface { + +public: + + // public facing structure for BufferSlot + class BufferItem : public Flattenable { + friend class Flattenable; + size_t getPodSize() const; + size_t getFlattenedSize() const; + size_t getFdCount() const; + status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; + status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + + public: + // The default value of mBuf, used to indicate this doesn't correspond to a slot. + enum { INVALID_BUFFER_SLOT = -1 }; + BufferItem(); + + // mGraphicBuffer points to the buffer allocated for this slot, or is NULL + // if the buffer in this slot has been acquired in the past (see + // BufferSlot.mAcquireCalled). + sp mGraphicBuffer; + + // mFence is a fence that will signal when the buffer is idle. + sp mFence; + + // mCrop is the current crop rectangle for this buffer slot. + Rect mCrop; + + // mTransform is the current transform flags for this buffer slot. + // refer to NATIVE_WINDOW_TRANSFORM_* in + uint32_t mTransform; + + // mScalingMode is the current scaling mode for this buffer slot. + // refer to NATIVE_WINDOW_SCALING_* in + uint32_t mScalingMode; + + // mTimestamp is the current timestamp for this buffer slot. This gets + // to set by queueBuffer each time this slot is queued. This value + // is guaranteed to be monotonically increasing for each newly + // acquired buffer. + int64_t mTimestamp; + + // mIsAutoTimestamp indicates whether mTimestamp was generated + // automatically when the buffer was queued. + bool mIsAutoTimestamp; + + // mFrameNumber is the number of the queued frame for this slot. + uint64_t mFrameNumber; + + // mBuf is the slot index of this buffer (default INVALID_BUFFER_SLOT). + int mBuf; + + // mIsDroppable whether this buffer was queued with the + // property that it can be replaced by a new buffer for the purpose of + // making sure dequeueBuffer() won't block. + // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer + // was queued. + bool mIsDroppable; + + // Indicates whether this buffer has been seen by a consumer yet + bool mAcquireCalled; + + // Indicates this buffer must be transformed by the inverse transform of the screen + // it is displayed onto. This is applied after mTransform. + bool mTransformToDisplayInverse; + }; + + enum { + // Returned by releaseBuffer, after which the consumer must + // free any references to the just-released buffer that it might have. + STALE_BUFFER_SLOT = 1, + // Returned by dequeueBuffer if there are no pending buffers available. + NO_BUFFER_AVAILABLE, + // Returned by dequeueBuffer if it's too early for the buffer to be acquired. + PRESENT_LATER, + }; + + // acquireBuffer attempts to acquire ownership of the next pending buffer in + // the BufferQueue. If no buffer is pending then it returns + // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the + // information about the buffer is returned in BufferItem. + // + // If the buffer returned had previously been + // acquired then the BufferItem::mGraphicBuffer field of buffer is set to + // NULL and it is assumed that the consumer still holds a reference to the + // buffer. + // + // If presentWhen is non-zero, it indicates the time when the buffer will + // be displayed on screen. If the buffer's timestamp is farther in the + // future, the buffer won't be acquired, and PRESENT_LATER will be + // returned. The presentation time is in nanoseconds, and the time base + // is CLOCK_MONOTONIC. + // + // Return of NO_ERROR means the operation completed as normal. + // + // Return of a positive value means the operation could not be completed + // at this time, but the user should try again later: + // * NO_BUFFER_AVAILABLE - no buffer is pending (nothing queued by producer) + // * PRESENT_LATER - the buffer's timestamp is farther in the future + // + // Return of a negative value means an error has occurred: + // * INVALID_OPERATION - too many buffers have been acquired + virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0; + + // detachBuffer attempts to remove all ownership of the buffer in the given + // slot from the buffer queue. If this call succeeds, the slot will be + // freed, and there will be no way to obtain the buffer from this interface. + // The freed slot will remain unallocated until either it is selected to + // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached + // to the slot. The buffer must have already been acquired. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * BAD_VALUE - the given slot number is invalid, either because it is + // out of the range [0, NUM_BUFFER_SLOTS) or because the slot + // it refers to is not currently acquired. + virtual status_t detachBuffer(int slot) = 0; + + // attachBuffer attempts to transfer ownership of a buffer to the buffer + // queue. If this call succeeds, it will be as if this buffer was acquired + // from the returned slot number. As such, this call will fail if attaching + // this buffer would cause too many buffers to be simultaneously acquired. + // + // If the buffer is successfully attached, its frameNumber is initialized + // to 0. This must be passed into the releaseBuffer call or else the buffer + // will be deallocated as stale. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * BAD_VALUE - outSlot or buffer were NULL + // * INVALID_OPERATION - cannot attach the buffer because it would cause too + // many buffers to be acquired. + // * NO_MEMORY - no free slots available + virtual status_t attachBuffer(int *outSlot, + const sp& buffer) = 0; + + // releaseBuffer releases a buffer slot from the consumer back to the + // BufferQueue. This may be done while the buffer's contents are still + // being accessed. The fence will signal when the buffer is no longer + // in use. frameNumber is used to indentify the exact buffer returned. + // + // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free + // any references to the just-released buffer that it might have, as if it + // had received a onBuffersReleased() call with a mask set for the released + // buffer. + // + // Note that the dependencies on EGL will be removed once we switch to using + // the Android HW Sync HAL. + // + // Return of NO_ERROR means the operation completed as normal. + // + // Return of a positive value means the operation could not be completed + // at this time, but the user should try again later: + // * STALE_BUFFER_SLOT - see above (second paragraph) + // + // Return of a negative value means an error has occurred: + // * BAD_VALUE - one of the following could've happened: + // * the buffer slot was invalid + // * the fence was NULL + // * the buffer slot specified is not in the acquired state + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, + EGLDisplay display, EGLSyncKHR fence, + const sp& releaseFence) = 0; + + // consumerConnect connects a consumer to the BufferQueue. Only one + // consumer may be connected, and when that consumer disconnects the + // BufferQueue is placed into the "abandoned" state, causing most + // interactions with the BufferQueue by the producer to fail. + // controlledByApp indicates whether the consumer is controlled by + // the application. + // + // consumer may not be NULL. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * NO_INIT - the buffer queue has been abandoned + // * BAD_VALUE - a NULL consumer was provided + virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) = 0; + + // consumerDisconnect disconnects a consumer from the BufferQueue. All + // buffers will be freed and the BufferQueue is placed in the "abandoned" + // state, causing most interactions with the BufferQueue by the producer to + // fail. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * BAD_VALUE - no consumer is currently connected + virtual status_t consumerDisconnect() = 0; + + // getReleasedBuffers sets the value pointed to by slotMask to a bit set. + // Each bit index with a 1 corresponds to a released buffer slot with that + // index value. In particular, a released buffer is one that has + // been released by the BufferQueue but have not yet been released by the consumer. + // + // This should be called from the onBuffersReleased() callback. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * NO_INIT - the buffer queue has been abandoned. + virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0; + + // setDefaultBufferSize is used to set the size of buffers returned by + // dequeueBuffer when a width and height of zero is requested. Default + // is 1x1. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * BAD_VALUE - either w or h was zero + virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; + + // setDefaultMaxBufferCount sets the default value for the maximum buffer + // count (the initial default is 2). If the producer has requested a + // buffer count using setBufferCount, the default buffer count will only + // take effect if the producer sets the count back to zero. + // + // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * BAD_VALUE - bufferCount was out of range (see above). + virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0; + + // disableAsyncBuffer disables the extra buffer used in async mode + // (when both producer and consumer have set their "isControlledByApp" + // flag) and has dequeueBuffer() return WOULD_BLOCK instead. + // + // This can only be called before consumerConnect(). + // + // Return of a value other than NO_ERROR means an error has occurred: + // * INVALID_OPERATION - attempting to call this after consumerConnect. + virtual status_t disableAsyncBuffer() = 0; + + // setMaxAcquiredBufferCount sets the maximum number of buffers that can + // be acquired by the consumer at one time (default 1). This call will + // fail if a producer is connected to the BufferQueue. + // + // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. + // + // Return of a value other than NO_ERROR means an error has occurred: + // * BAD_VALUE - maxAcquiredBuffers was out of range (see above). + // * INVALID_OPERATION - attempting to call this after a producer connected. + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; + + // setConsumerName sets the name used in logging + virtual void setConsumerName(const String8& name) = 0; + + // setDefaultBufferFormat allows the BufferQueue to create + // GraphicBuffers of a defaultFormat if no format is specified + // in dequeueBuffer. Formats are enumerated in graphics.h; the + // initial default is HAL_PIXEL_FORMAT_RGBA_8888. + // + // Return of a value other than NO_ERROR means an unknown error has occurred. + virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0; + + // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. + // These are merged with the bits passed to dequeueBuffer. The values are + // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. + // + // Return of a value other than NO_ERROR means an unknown error has occurred. + virtual status_t setConsumerUsageBits(uint32_t usage) = 0; + + // setTransformHint bakes in rotation to buffers so overlays can be used. + // The values are enumerated in window.h, e.g. + // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). + // + // Return of a value other than NO_ERROR means an unknown error has occurred. + virtual status_t setTransformHint(uint32_t hint) = 0; + + // Retrieve the sideband buffer stream, if any. + virtual sp getSidebandStream() const = 0; + + // dump state into a string + virtual void dump(String8& result, const char* prefix) const = 0; + +public: + DECLARE_META_INTERFACE(GraphicBufferConsumer); +}; + +// ---------------------------------------------------------------------------- + +class BnGraphicBufferConsumer : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H From 82bb82c84a1e6bd4c59690a6f8a9ff3f3c924580 Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Wed, 17 Dec 2014 22:29:00 +0100 Subject: [PATCH 34/64] Bug 1098970 - Part 2: Rename files. r=sotaro Add the "Gonk" prefix & "LL" suffix, and collect all BufferQueue related files on Lollipop in one directory. --HG-- rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h => widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp => widget/gonk/nativewindow/GonkConsumerBaseLL.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h => widget/gonk/nativewindow/GonkConsumerBaseLL.h rename : widget/gonk/nativewindow/IGonkGraphicBufferConsumer.cpp => widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp rename : widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h => widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h rename : widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp => widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp rename : widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h => widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h --- .../GonkBufferQueueLL/{BufferItem.cpp => GonkBufferItem.cpp} | 0 .../GonkBufferQueueLL/{BufferItem.h => GonkBufferItem.h} | 0 .../{BufferQueueConsumer.cpp => GonkBufferQueueConsumer.cpp} | 0 .../{BufferQueueConsumer.h => GonkBufferQueueConsumer.h} | 0 .../{BufferQueueCore.cpp => GonkBufferQueueCore.cpp} | 0 .../{BufferQueueCore.h => GonkBufferQueueCore.h} | 0 .../{BufferQueueDefs.h => GonkBufferQueueDefs.h} | 0 .../GonkBufferQueueLL/{BufferQueue.cpp => GonkBufferQueueLL.cpp} | 0 .../GonkBufferQueueLL/{BufferQueue.h => GonkBufferQueueLL.h} | 0 .../{BufferQueueProducer.cpp => GonkBufferQueueProducer.cpp} | 0 .../{BufferQueueProducer.h => GonkBufferQueueProducer.h} | 0 .../GonkBufferQueueLL/{BufferSlot.cpp => GonkBufferSlot.cpp} | 0 .../GonkBufferQueueLL/{BufferSlot.h => GonkBufferSlot.h} | 0 .../ConsumerBase.cpp => GonkConsumerBaseLL.cpp} | 0 .../{GonkBufferQueueLL/ConsumerBase.h => GonkConsumerBaseLL.h} | 0 ...GraphicBufferConsumer.cpp => IGonkGraphicBufferConsumerKK.cpp} | 0 ...GonkGraphicBufferConsumer.h => IGonkGraphicBufferConsumerKK.h} | 0 ...GraphicBufferConsumer.cpp => IGonkGraphicBufferConsumerLL.cpp} | 0 .../IGraphicBufferConsumer.h => IGonkGraphicBufferConsumerLL.h} | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferItem.cpp => GonkBufferItem.cpp} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferItem.h => GonkBufferItem.h} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueueConsumer.cpp => GonkBufferQueueConsumer.cpp} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueueConsumer.h => GonkBufferQueueConsumer.h} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueueCore.cpp => GonkBufferQueueCore.cpp} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueueCore.h => GonkBufferQueueCore.h} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueueDefs.h => GonkBufferQueueDefs.h} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueue.cpp => GonkBufferQueueLL.cpp} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueue.h => GonkBufferQueueLL.h} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueueProducer.cpp => GonkBufferQueueProducer.cpp} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferQueueProducer.h => GonkBufferQueueProducer.h} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferSlot.cpp => GonkBufferSlot.cpp} (100%) rename widget/gonk/nativewindow/GonkBufferQueueLL/{BufferSlot.h => GonkBufferSlot.h} (100%) rename widget/gonk/nativewindow/{GonkBufferQueueLL/ConsumerBase.cpp => GonkConsumerBaseLL.cpp} (100%) rename widget/gonk/nativewindow/{GonkBufferQueueLL/ConsumerBase.h => GonkConsumerBaseLL.h} (100%) rename widget/gonk/nativewindow/{IGonkGraphicBufferConsumer.cpp => IGonkGraphicBufferConsumerKK.cpp} (100%) rename widget/gonk/nativewindow/{IGonkGraphicBufferConsumer.h => IGonkGraphicBufferConsumerKK.h} (100%) rename widget/gonk/nativewindow/{GonkBufferQueueLL/IGraphicBufferConsumer.cpp => IGonkGraphicBufferConsumerLL.cpp} (100%) rename widget/gonk/nativewindow/{GonkBufferQueueLL/IGraphicBufferConsumer.h => IGonkGraphicBufferConsumerLL.h} (100%) diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h rename to widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp b/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp rename to widget/gonk/nativewindow/GonkConsumerBaseLL.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h b/widget/gonk/nativewindow/GonkConsumerBaseLL.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h rename to widget/gonk/nativewindow/GonkConsumerBaseLL.h diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp similarity index 100% rename from widget/gonk/nativewindow/IGonkGraphicBufferConsumer.cpp rename to widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h similarity index 100% rename from widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h rename to widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp rename to widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h similarity index 100% rename from widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h rename to widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h From fbec25158c6161b85856c61813346a55b9b4486f Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Wed, 17 Dec 2014 22:30:00 +0100 Subject: [PATCH 35/64] Bug 1098970 - Part 3: Add new files for Nativewindow. r=sotaro 1. Copied Surface.* and rename them as GonkNativeWindowClientLL.* 2. Copied BufferItemConsumer.* and rename them as GonkNativeWindowLL.* 3. Add new IGonkGraphicBufferConsumer.h to control the version 4. Fix the file mode for some JB files (remove execute permission) --- widget/gonk/nativewindow/GonkBufferQueue.h | 0 .../gonk/nativewindow/GonkBufferQueueJB.cpp | 0 widget/gonk/nativewindow/GonkBufferQueueJB.h | 0 .../gonk/nativewindow/GonkConsumerBaseJB.cpp | 0 widget/gonk/nativewindow/GonkConsumerBaseJB.h | 0 .../nativewindow/GonkNativeWindowClientJB.cpp | 0 .../nativewindow/GonkNativeWindowClientJB.h | 0 .../nativewindow/GonkNativeWindowClientLL.cpp | 910 ++++++++++++++++++ .../nativewindow/GonkNativeWindowClientLL.h | 293 ++++++ .../gonk/nativewindow/GonkNativeWindowJB.cpp | 0 widget/gonk/nativewindow/GonkNativeWindowJB.h | 0 .../gonk/nativewindow/GonkNativeWindowLL.cpp | 113 +++ widget/gonk/nativewindow/GonkNativeWindowLL.h | 103 ++ .../nativewindow/IGonkGraphicBufferConsumer.h | 18 + 14 files changed, 1437 insertions(+) mode change 100755 => 100644 widget/gonk/nativewindow/GonkBufferQueue.h mode change 100755 => 100644 widget/gonk/nativewindow/GonkBufferQueueJB.cpp mode change 100755 => 100644 widget/gonk/nativewindow/GonkBufferQueueJB.h mode change 100755 => 100644 widget/gonk/nativewindow/GonkConsumerBaseJB.cpp mode change 100755 => 100644 widget/gonk/nativewindow/GonkConsumerBaseJB.h mode change 100755 => 100644 widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp mode change 100755 => 100644 widget/gonk/nativewindow/GonkNativeWindowClientJB.h create mode 100644 widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp create mode 100644 widget/gonk/nativewindow/GonkNativeWindowClientLL.h mode change 100755 => 100644 widget/gonk/nativewindow/GonkNativeWindowJB.cpp mode change 100755 => 100644 widget/gonk/nativewindow/GonkNativeWindowJB.h create mode 100644 widget/gonk/nativewindow/GonkNativeWindowLL.cpp create mode 100644 widget/gonk/nativewindow/GonkNativeWindowLL.h create mode 100644 widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h diff --git a/widget/gonk/nativewindow/GonkBufferQueue.h b/widget/gonk/nativewindow/GonkBufferQueue.h old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkBufferQueueJB.h b/widget/gonk/nativewindow/GonkBufferQueueJB.h old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp b/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkConsumerBaseJB.h b/widget/gonk/nativewindow/GonkConsumerBaseJB.h old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientJB.h b/widget/gonk/nativewindow/GonkNativeWindowClientJB.h old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp new file mode 100644 index 000000000000..0e2baa28fd4d --- /dev/null +++ b/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp @@ -0,0 +1,910 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Surface" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace android { + +Surface::Surface( + const sp& bufferProducer, + bool controlledByApp) + : mGraphicBufferProducer(bufferProducer) +{ + // Initialize the ANativeWindow function pointers. + ANativeWindow::setSwapInterval = hook_setSwapInterval; + ANativeWindow::dequeueBuffer = hook_dequeueBuffer; + ANativeWindow::cancelBuffer = hook_cancelBuffer; + ANativeWindow::queueBuffer = hook_queueBuffer; + ANativeWindow::query = hook_query; + ANativeWindow::perform = hook_perform; + + ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; + ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; + ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; + ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; + + const_cast(ANativeWindow::minSwapInterval) = 0; + const_cast(ANativeWindow::maxSwapInterval) = 1; + + mReqWidth = 0; + mReqHeight = 0; + mReqFormat = 0; + mReqUsage = 0; + mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + mCrop.clear(); + mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; + mTransform = 0; + mStickyTransform = 0; + mDefaultWidth = 0; + mDefaultHeight = 0; + mUserWidth = 0; + mUserHeight = 0; + mTransformHint = 0; + mConsumerRunningBehind = false; + mConnectedToCpu = false; + mProducerControlledByApp = controlledByApp; + mSwapIntervalZero = false; +} + +Surface::~Surface() { + if (mConnectedToCpu) { + Surface::disconnect(NATIVE_WINDOW_API_CPU); + } +} + +sp Surface::getIGraphicBufferProducer() const { + return mGraphicBufferProducer; +} + +void Surface::setSidebandStream(const sp& stream) { + mGraphicBufferProducer->setSidebandStream(stream); +} + +void Surface::allocateBuffers() { + uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; + uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; + mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, mReqWidth, + mReqHeight, mReqFormat, mReqUsage); +} + +int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { + Surface* c = getSelf(window); + return c->setSwapInterval(interval); +} + +int Surface::hook_dequeueBuffer(ANativeWindow* window, + ANativeWindowBuffer** buffer, int* fenceFd) { + Surface* c = getSelf(window); + return c->dequeueBuffer(buffer, fenceFd); +} + +int Surface::hook_cancelBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd) { + Surface* c = getSelf(window); + return c->cancelBuffer(buffer, fenceFd); +} + +int Surface::hook_queueBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd) { + Surface* c = getSelf(window); + return c->queueBuffer(buffer, fenceFd); +} + +int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer** buffer) { + Surface* c = getSelf(window); + ANativeWindowBuffer* buf; + int fenceFd = -1; + int result = c->dequeueBuffer(&buf, &fenceFd); + sp fence(new Fence(fenceFd)); + int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); + if (waitResult != OK) { + ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", + waitResult); + c->cancelBuffer(buf, -1); + return waitResult; + } + *buffer = buf; + return result; +} + +int Surface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + Surface* c = getSelf(window); + return c->cancelBuffer(buffer, -1); +} + +int Surface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + Surface* c = getSelf(window); + return c->lockBuffer_DEPRECATED(buffer); +} + +int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + Surface* c = getSelf(window); + return c->queueBuffer(buffer, -1); +} + +int Surface::hook_query(const ANativeWindow* window, + int what, int* value) { + const Surface* c = getSelf(window); + return c->query(what, value); +} + +int Surface::hook_perform(ANativeWindow* window, int operation, ...) { + va_list args; + va_start(args, operation); + Surface* c = getSelf(window); + return c->perform(operation, args); +} + +int Surface::setSwapInterval(int interval) { + ATRACE_CALL(); + // EGL specification states: + // interval is silently clamped to minimum and maximum implementation + // dependent values before being stored. + + if (interval < minSwapInterval) + interval = minSwapInterval; + + if (interval > maxSwapInterval) + interval = maxSwapInterval; + + mSwapIntervalZero = (interval == 0); + + return NO_ERROR; +} + +int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { + ATRACE_CALL(); + ALOGV("Surface::dequeueBuffer"); + + int reqW; + int reqH; + bool swapIntervalZero; + uint32_t reqFormat; + uint32_t reqUsage; + + { + Mutex::Autolock lock(mMutex); + + reqW = mReqWidth ? mReqWidth : mUserWidth; + reqH = mReqHeight ? mReqHeight : mUserHeight; + + swapIntervalZero = mSwapIntervalZero; + reqFormat = mReqFormat; + reqUsage = mReqUsage; + } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer + + int buf = -1; + sp fence; + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero, + reqW, reqH, reqFormat, reqUsage); + + if (result < 0) { + ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)" + "failed: %d", swapIntervalZero, reqW, reqH, reqFormat, reqUsage, + result); + return result; + } + + Mutex::Autolock lock(mMutex); + + sp& gbuf(mSlots[buf].buffer); + + // this should never happen + ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); + + if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { + freeAllBuffers(); + } + + if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { + result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); + if (result != NO_ERROR) { + ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); + mGraphicBufferProducer->cancelBuffer(buf, fence); + return result; + } + } + + if (fence->isValid()) { + *fenceFd = fence->dup(); + if (*fenceFd == -1) { + ALOGE("dequeueBuffer: error duping fence: %d", errno); + // dup() should never fail; something is badly wrong. Soldier on + // and hope for the best; the worst that should happen is some + // visible corruption that lasts until the next frame. + } + } else { + *fenceFd = -1; + } + + *buffer = gbuf.get(); + return OK; +} + +int Surface::cancelBuffer(android_native_buffer_t* buffer, + int fenceFd) { + ATRACE_CALL(); + ALOGV("Surface::cancelBuffer"); + Mutex::Autolock lock(mMutex); + int i = getSlotFromBufferLocked(buffer); + if (i < 0) { + return i; + } + sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + mGraphicBufferProducer->cancelBuffer(i, fence); + return OK; +} + +int Surface::getSlotFromBufferLocked( + android_native_buffer_t* buffer) const { + bool dumpedState = false; + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + if (mSlots[i].buffer != NULL && + mSlots[i].buffer->handle == buffer->handle) { + return i; + } + } + ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); + return BAD_VALUE; +} + +int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer __attribute__((unused))) { + ALOGV("Surface::lockBuffer"); + Mutex::Autolock lock(mMutex); + return OK; +} + +int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { + ATRACE_CALL(); + ALOGV("Surface::queueBuffer"); + Mutex::Autolock lock(mMutex); + int64_t timestamp; + bool isAutoTimestamp = false; + if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + isAutoTimestamp = true; + ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", + timestamp / 1000000.f); + } else { + timestamp = mTimestamp; + } + int i = getSlotFromBufferLocked(buffer); + if (i < 0) { + return i; + } + + + // Make sure the crop rectangle is entirely inside the buffer. + Rect crop; + mCrop.intersect(Rect(buffer->width, buffer->height), &crop); + + sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + IGraphicBufferProducer::QueueBufferOutput output; + IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, + crop, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero, + fence, mStickyTransform); + status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); + if (err != OK) { + ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); + } + uint32_t numPendingBuffers = 0; + uint32_t hint = 0; + output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, + &numPendingBuffers); + + // Disable transform hint if sticky transform is set. + if (mStickyTransform == 0) { + mTransformHint = hint; + } + + mConsumerRunningBehind = (numPendingBuffers >= 2); + + return err; +} + +int Surface::query(int what, int* value) const { + ATRACE_CALL(); + ALOGV("Surface::query"); + { // scope for the lock + Mutex::Autolock lock(mMutex); + switch (what) { + case NATIVE_WINDOW_FORMAT: + if (mReqFormat) { + *value = mReqFormat; + return NO_ERROR; + } + break; + case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { + sp composer( + ComposerService::getComposerService()); + if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) { + *value = 1; + } else { + *value = 0; + } + return NO_ERROR; + } + case NATIVE_WINDOW_CONCRETE_TYPE: + *value = NATIVE_WINDOW_SURFACE; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_WIDTH: + *value = mUserWidth ? mUserWidth : mDefaultWidth; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_HEIGHT: + *value = mUserHeight ? mUserHeight : mDefaultHeight; + return NO_ERROR; + case NATIVE_WINDOW_TRANSFORM_HINT: + *value = mTransformHint; + return NO_ERROR; + case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { + status_t err = NO_ERROR; + if (!mConsumerRunningBehind) { + *value = 0; + } else { + err = mGraphicBufferProducer->query(what, value); + if (err == NO_ERROR) { + mConsumerRunningBehind = *value; + } + } + return err; + } + } + } + return mGraphicBufferProducer->query(what, value); +} + +int Surface::perform(int operation, va_list args) +{ + int res = NO_ERROR; + switch (operation) { + case NATIVE_WINDOW_CONNECT: + // deprecated. must return NO_ERROR. + break; + case NATIVE_WINDOW_DISCONNECT: + // deprecated. must return NO_ERROR. + break; + case NATIVE_WINDOW_SET_USAGE: + res = dispatchSetUsage(args); + break; + case NATIVE_WINDOW_SET_CROP: + res = dispatchSetCrop(args); + break; + case NATIVE_WINDOW_SET_BUFFER_COUNT: + res = dispatchSetBufferCount(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + res = dispatchSetBuffersGeometry(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: + res = dispatchSetBuffersTransform(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM: + res = dispatchSetBuffersStickyTransform(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatchSetBuffersTimestamp(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: + res = dispatchSetBuffersDimensions(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: + res = dispatchSetBuffersUserDimensions(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + res = dispatchSetBuffersFormat(args); + break; + case NATIVE_WINDOW_LOCK: + res = dispatchLock(args); + break; + case NATIVE_WINDOW_UNLOCK_AND_POST: + res = dispatchUnlockAndPost(args); + break; + case NATIVE_WINDOW_SET_SCALING_MODE: + res = dispatchSetScalingMode(args); + break; + case NATIVE_WINDOW_API_CONNECT: + res = dispatchConnect(args); + break; + case NATIVE_WINDOW_API_DISCONNECT: + res = dispatchDisconnect(args); + break; + case NATIVE_WINDOW_SET_SIDEBAND_STREAM: + res = dispatchSetSidebandStream(args); + break; + default: + res = NAME_NOT_FOUND; + break; + } + return res; +} + +int Surface::dispatchConnect(va_list args) { + int api = va_arg(args, int); + return connect(api); +} + +int Surface::dispatchDisconnect(va_list args) { + int api = va_arg(args, int); + return disconnect(api); +} + +int Surface::dispatchSetUsage(va_list args) { + int usage = va_arg(args, int); + return setUsage(usage); +} + +int Surface::dispatchSetCrop(va_list args) { + android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); + return setCrop(reinterpret_cast(rect)); +} + +int Surface::dispatchSetBufferCount(va_list args) { + size_t bufferCount = va_arg(args, size_t); + return setBufferCount(bufferCount); +} + +int Surface::dispatchSetBuffersGeometry(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + int err = setBuffersDimensions(w, h); + if (err != 0) { + return err; + } + return setBuffersFormat(f); +} + +int Surface::dispatchSetBuffersDimensions(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + return setBuffersDimensions(w, h); +} + +int Surface::dispatchSetBuffersUserDimensions(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + return setBuffersUserDimensions(w, h); +} + +int Surface::dispatchSetBuffersFormat(va_list args) { + int f = va_arg(args, int); + return setBuffersFormat(f); +} + +int Surface::dispatchSetScalingMode(va_list args) { + int m = va_arg(args, int); + return setScalingMode(m); +} + +int Surface::dispatchSetBuffersTransform(va_list args) { + int transform = va_arg(args, int); + return setBuffersTransform(transform); +} + +int Surface::dispatchSetBuffersStickyTransform(va_list args) { + int transform = va_arg(args, int); + return setBuffersStickyTransform(transform); +} + +int Surface::dispatchSetBuffersTimestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + +int Surface::dispatchLock(va_list args) { + ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); + ARect* inOutDirtyBounds = va_arg(args, ARect*); + return lock(outBuffer, inOutDirtyBounds); +} + +int Surface::dispatchUnlockAndPost(va_list args __attribute__((unused))) { + return unlockAndPost(); +} + +int Surface::dispatchSetSidebandStream(va_list args) { + native_handle_t* sH = va_arg(args, native_handle_t*); + sp sidebandHandle = NativeHandle::create(sH, false); + setSidebandStream(sidebandHandle); + return OK; +} + +int Surface::connect(int api) { + ATRACE_CALL(); + ALOGV("Surface::connect"); + static sp listener = new DummyProducerListener(); + Mutex::Autolock lock(mMutex); + IGraphicBufferProducer::QueueBufferOutput output; + int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); + if (err == NO_ERROR) { + uint32_t numPendingBuffers = 0; + uint32_t hint = 0; + output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, + &numPendingBuffers); + + // Disable transform hint if sticky transform is set. + if (mStickyTransform == 0) { + mTransformHint = hint; + } + + mConsumerRunningBehind = (numPendingBuffers >= 2); + } + if (!err && api == NATIVE_WINDOW_API_CPU) { + mConnectedToCpu = true; + } + return err; +} + + +int Surface::disconnect(int api) { + ATRACE_CALL(); + ALOGV("Surface::disconnect"); + Mutex::Autolock lock(mMutex); + freeAllBuffers(); + int err = mGraphicBufferProducer->disconnect(api); + if (!err) { + mReqFormat = 0; + mReqWidth = 0; + mReqHeight = 0; + mReqUsage = 0; + mCrop.clear(); + mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; + mTransform = 0; + mStickyTransform = 0; + + if (api == NATIVE_WINDOW_API_CPU) { + mConnectedToCpu = false; + } + } + return err; +} + +int Surface::setUsage(uint32_t reqUsage) +{ + ALOGV("Surface::setUsage"); + Mutex::Autolock lock(mMutex); + mReqUsage = reqUsage; + return OK; +} + +int Surface::setCrop(Rect const* rect) +{ + ATRACE_CALL(); + + Rect realRect; + if (rect == NULL || rect->isEmpty()) { + realRect.clear(); + } else { + realRect = *rect; + } + + ALOGV("Surface::setCrop rect=[%d %d %d %d]", + realRect.left, realRect.top, realRect.right, realRect.bottom); + + Mutex::Autolock lock(mMutex); + mCrop = realRect; + return NO_ERROR; +} + +int Surface::setBufferCount(int bufferCount) +{ + ATRACE_CALL(); + ALOGV("Surface::setBufferCount"); + Mutex::Autolock lock(mMutex); + + status_t err = mGraphicBufferProducer->setBufferCount(bufferCount); + ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s", + bufferCount, strerror(-err)); + + if (err == NO_ERROR) { + freeAllBuffers(); + } + + return err; +} + +int Surface::setBuffersDimensions(int w, int h) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersDimensions"); + + if (w<0 || h<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock lock(mMutex); + mReqWidth = w; + mReqHeight = h; + return NO_ERROR; +} + +int Surface::setBuffersUserDimensions(int w, int h) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersUserDimensions"); + + if (w<0 || h<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock lock(mMutex); + mUserWidth = w; + mUserHeight = h; + return NO_ERROR; +} + +int Surface::setBuffersFormat(int format) +{ + ALOGV("Surface::setBuffersFormat"); + + if (format<0) + return BAD_VALUE; + + Mutex::Autolock lock(mMutex); + mReqFormat = format; + return NO_ERROR; +} + +int Surface::setScalingMode(int mode) +{ + ATRACE_CALL(); + ALOGV("Surface::setScalingMode(%d)", mode); + + switch (mode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + break; + default: + ALOGE("unknown scaling mode: %d", mode); + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + mScalingMode = mode; + return NO_ERROR; +} + +int Surface::setBuffersTransform(int transform) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersTransform"); + Mutex::Autolock lock(mMutex); + mTransform = transform; + return NO_ERROR; +} + +int Surface::setBuffersStickyTransform(int transform) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersStickyTransform"); + Mutex::Autolock lock(mMutex); + mStickyTransform = transform; + return NO_ERROR; +} + +int Surface::setBuffersTimestamp(int64_t timestamp) +{ + ALOGV("Surface::setBuffersTimestamp"); + Mutex::Autolock lock(mMutex); + mTimestamp = timestamp; + return NO_ERROR; +} + +void Surface::freeAllBuffers() { + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + mSlots[i].buffer = 0; + } +} + +// ---------------------------------------------------------------------- +// the lock/unlock APIs must be used from the same thread + +static status_t copyBlt( + const sp& dst, + const sp& src, + const Region& reg) +{ + // src and dst with, height and format must be identical. no verification + // is done here. + status_t err; + uint8_t const * src_bits = NULL; + err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); + ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); + + uint8_t* dst_bits = NULL; + err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits); + ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); + + Region::const_iterator head(reg.begin()); + Region::const_iterator tail(reg.end()); + if (head != tail && src_bits && dst_bits) { + const size_t bpp = bytesPerPixel(src->format); + const size_t dbpr = dst->stride * bpp; + const size_t sbpr = src->stride * bpp; + + while (head != tail) { + const Rect& r(*head++); + ssize_t h = r.height(); + if (h <= 0) continue; + size_t size = r.width() * bpp; + uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; + uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; + if (dbpr==sbpr && size==sbpr) { + size *= h; + h = 1; + } + do { + memcpy(d, s, size); + d += dbpr; + s += sbpr; + } while (--h > 0); + } + } + + if (src_bits) + src->unlock(); + + if (dst_bits) + dst->unlock(); + + return err; +} + +// ---------------------------------------------------------------------------- + +status_t Surface::lock( + ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) +{ + if (mLockedBuffer != 0) { + ALOGE("Surface::lock failed, already locked"); + return INVALID_OPERATION; + } + + if (!mConnectedToCpu) { + int err = Surface::connect(NATIVE_WINDOW_API_CPU); + if (err) { + return err; + } + // we're intending to do software rendering from this point + setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + } + + ANativeWindowBuffer* out; + int fenceFd = -1; + status_t err = dequeueBuffer(&out, &fenceFd); + ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); + if (err == NO_ERROR) { + sp backBuffer(GraphicBuffer::getSelf(out)); + const Rect bounds(backBuffer->width, backBuffer->height); + + Region newDirtyRegion; + if (inOutDirtyBounds) { + newDirtyRegion.set(static_cast(*inOutDirtyBounds)); + newDirtyRegion.andSelf(bounds); + } else { + newDirtyRegion.set(bounds); + } + + // figure out if we can copy the frontbuffer back + const sp& frontBuffer(mPostedBuffer); + const bool canCopyBack = (frontBuffer != 0 && + backBuffer->width == frontBuffer->width && + backBuffer->height == frontBuffer->height && + backBuffer->format == frontBuffer->format); + + if (canCopyBack) { + // copy the area that is invalid and not repainted this round + const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); + if (!copyback.isEmpty()) + copyBlt(backBuffer, frontBuffer, copyback); + } else { + // if we can't copy-back anything, modify the user's dirty + // region to make sure they redraw the whole buffer + newDirtyRegion.set(bounds); + mDirtyRegion.clear(); + Mutex::Autolock lock(mMutex); + for (size_t i=0 ; i= 0) { + Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); + mDirtyRegion.subtract(dirtyRegion); + dirtyRegion = newDirtyRegion; + } + } + + mDirtyRegion.orSelf(newDirtyRegion); + if (inOutDirtyBounds) { + *inOutDirtyBounds = newDirtyRegion.getBounds(); + } + + void* vaddr; + status_t res = backBuffer->lockAsync( + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + newDirtyRegion.bounds(), &vaddr, fenceFd); + + ALOGW_IF(res, "failed locking buffer (handle = %p)", + backBuffer->handle); + + if (res != 0) { + err = INVALID_OPERATION; + } else { + mLockedBuffer = backBuffer; + outBuffer->width = backBuffer->width; + outBuffer->height = backBuffer->height; + outBuffer->stride = backBuffer->stride; + outBuffer->format = backBuffer->format; + outBuffer->bits = vaddr; + } + } + return err; +} + +status_t Surface::unlockAndPost() +{ + if (mLockedBuffer == 0) { + ALOGE("Surface::unlockAndPost failed, no locked buffer"); + return INVALID_OPERATION; + } + + int fd = -1; + status_t err = mLockedBuffer->unlockAsync(&fd); + ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); + + err = queueBuffer(mLockedBuffer.get(), fd); + ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)", + mLockedBuffer->handle, strerror(-err)); + + mPostedBuffer = mLockedBuffer; + mLockedBuffer = 0; + return err; +} + +}; // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientLL.h b/widget/gonk/nativewindow/GonkNativeWindowClientLL.h new file mode 100644 index 000000000000..f2cf018a9fd1 --- /dev/null +++ b/widget/gonk/nativewindow/GonkNativeWindowClientLL.h @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_SURFACE_H +#define ANDROID_GUI_SURFACE_H + +#include +#include + +#include +#include + +#include +#include +#include + +struct ANativeWindow_Buffer; + +namespace android { + +/* + * An implementation of ANativeWindow that feeds graphics buffers into a + * BufferQueue. + * + * This is typically used by programs that want to render frames through + * some means (maybe OpenGL, a software renderer, or a hardware decoder) + * and have the frames they create forwarded to SurfaceFlinger for + * compositing. For example, a video decoder could render a frame and call + * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by + * Surface. Surface then forwards the buffers through Binder IPC + * to the BufferQueue's producer interface, providing the new frame to a + * consumer such as GLConsumer. + */ +class Surface + : public ANativeObjectBase +{ +public: + + /* + * creates a Surface from the given IGraphicBufferProducer (which concrete + * implementation is a BufferQueue). + * + * Surface is mainly state-less while it's disconnected, it can be + * viewed as a glorified IGraphicBufferProducer holder. It's therefore + * safe to create other Surfaces from the same IGraphicBufferProducer. + * + * However, once a Surface is connected, it'll prevent other Surfaces + * referring to the same IGraphicBufferProducer to become connected and + * therefore prevent them to be used as actual producers of buffers. + * + * the controlledByApp flag indicates that this Surface (producer) is + * controlled by the application. This flag is used at connect time. + */ + Surface(const sp& bufferProducer, bool controlledByApp = false); + + /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this + * Surface was created with. Usually it's an error to use the + * IGraphicBufferProducer while the Surface is connected. + */ + sp getIGraphicBufferProducer() const; + + /* convenience function to check that the given surface is non NULL as + * well as its IGraphicBufferProducer */ + static bool isValid(const sp& surface) { + return surface != NULL && surface->getIGraphicBufferProducer() != NULL; + } + + /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer. + * + * A sideband stream is a device-specific mechanism for passing buffers + * from the producer to the consumer without using dequeueBuffer/ + * queueBuffer. If a sideband stream is present, the consumer can choose + * whether to acquire buffers from the sideband stream or from the queued + * buffers. + * + * Passing NULL or a different stream handle will detach the previous + * handle if any. + */ + void setSidebandStream(const sp& stream); + + /* Allocates buffers based on the current dimensions/format. + * + * This function will allocate up to the maximum number of buffers + * permitted by the current BufferQueue configuration. It will use the + * default format and dimensions. This is most useful to avoid an allocation + * delay during dequeueBuffer. If there are already the maximum number of + * buffers allocated, this function has no effect. + */ + void allocateBuffers(); + +protected: + virtual ~Surface(); + +private: + // can't be copied + Surface& operator = (const Surface& rhs); + Surface(const Surface& rhs); + + // ANativeWindow hooks + static int hook_cancelBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd); + static int hook_dequeueBuffer(ANativeWindow* window, + ANativeWindowBuffer** buffer, int* fenceFd); + static int hook_perform(ANativeWindow* window, int operation, ...); + static int hook_query(const ANativeWindow* window, int what, int* value); + static int hook_queueBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd); + static int hook_setSwapInterval(ANativeWindow* window, int interval); + + static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer); + static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer** buffer); + static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer); + static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer); + + int dispatchConnect(va_list args); + int dispatchDisconnect(va_list args); + int dispatchSetBufferCount(va_list args); + int dispatchSetBuffersGeometry(va_list args); + int dispatchSetBuffersDimensions(va_list args); + int dispatchSetBuffersUserDimensions(va_list args); + int dispatchSetBuffersFormat(va_list args); + int dispatchSetScalingMode(va_list args); + int dispatchSetBuffersTransform(va_list args); + int dispatchSetBuffersStickyTransform(va_list args); + int dispatchSetBuffersTimestamp(va_list args); + int dispatchSetCrop(va_list args); + int dispatchSetPostTransformCrop(va_list args); + int dispatchSetUsage(va_list args); + int dispatchLock(va_list args); + int dispatchUnlockAndPost(va_list args); + int dispatchSetSidebandStream(va_list args); + +protected: + virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); + virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); + virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); + virtual int perform(int operation, va_list args); + virtual int query(int what, int* value) const; + virtual int setSwapInterval(int interval); + + virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer); + + virtual int connect(int api); + virtual int disconnect(int api); + virtual int setBufferCount(int bufferCount); + virtual int setBuffersDimensions(int w, int h); + virtual int setBuffersUserDimensions(int w, int h); + virtual int setBuffersFormat(int format); + virtual int setScalingMode(int mode); + virtual int setBuffersTransform(int transform); + virtual int setBuffersStickyTransform(int transform); + virtual int setBuffersTimestamp(int64_t timestamp); + virtual int setCrop(Rect const* rect); + virtual int setUsage(uint32_t reqUsage); + +public: + virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); + virtual int unlockAndPost(); + +protected: + enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS }; + enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; + +private: + void freeAllBuffers(); + int getSlotFromBufferLocked(android_native_buffer_t* buffer) const; + + struct BufferSlot { + sp buffer; + Region dirtyRegion; + }; + + // mSurfaceTexture is the interface to the surface texture server. All + // operations on the surface texture client ultimately translate into + // interactions with the server using this interface. + // TODO: rename to mBufferProducer + sp mGraphicBufferProducer; + + // mSlots stores the buffers that have been allocated for each buffer slot. + // It is initialized to null pointers, and gets filled in with the result of + // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a + // slot that has not yet been used. The buffer allocated to a slot will also + // be replaced if the requested buffer usage or geometry differs from that + // of the buffer allocated to a slot. + BufferSlot mSlots[NUM_BUFFER_SLOTS]; + + // mReqWidth is the buffer width that will be requested at the next dequeue + // operation. It is initialized to 1. + uint32_t mReqWidth; + + // mReqHeight is the buffer height that will be requested at the next + // dequeue operation. It is initialized to 1. + uint32_t mReqHeight; + + // mReqFormat is the buffer pixel format that will be requested at the next + // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. + uint32_t mReqFormat; + + // mReqUsage is the set of buffer usage flags that will be requested + // at the next deuque operation. It is initialized to 0. + uint32_t mReqUsage; + + // mTimestamp is the timestamp that will be used for the next buffer queue + // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that + // a timestamp is auto-generated when queueBuffer is called. + int64_t mTimestamp; + + // mCrop is the crop rectangle that will be used for the next buffer + // that gets queued. It is set by calling setCrop. + Rect mCrop; + + // mScalingMode is the scaling mode that will be used for the next + // buffers that get queued. It is set by calling setScalingMode. + int mScalingMode; + + // mTransform is the transform identifier that will be used for the next + // buffer that gets queued. It is set by calling setTransform. + uint32_t mTransform; + + // mStickyTransform is a transform that is applied on top of mTransform + // in each buffer that is queued. This is typically used to force the + // compositor to apply a transform, and will prevent the transform hint + // from being set by the compositor. + uint32_t mStickyTransform; + + // mDefaultWidth is default width of the buffers, regardless of the + // native_window_set_buffers_dimensions call. + uint32_t mDefaultWidth; + + // mDefaultHeight is default height of the buffers, regardless of the + // native_window_set_buffers_dimensions call. + uint32_t mDefaultHeight; + + // mUserWidth, if non-zero, is an application-specified override + // of mDefaultWidth. This is lower priority than the width set by + // native_window_set_buffers_dimensions. + uint32_t mUserWidth; + + // mUserHeight, if non-zero, is an application-specified override + // of mDefaultHeight. This is lower priority than the height set + // by native_window_set_buffers_dimensions. + uint32_t mUserHeight; + + // mTransformHint is the transform probably applied to buffers of this + // window. this is only a hint, actual transform may differ. + uint32_t mTransformHint; + + // mProducerControlledByApp whether this buffer producer is controlled + // by the application + bool mProducerControlledByApp; + + // mSwapIntervalZero set if we should drop buffers at queue() time to + // achieve an asynchronous swap interval + bool mSwapIntervalZero; + + // mConsumerRunningBehind whether the consumer is running more than + // one buffer behind the producer. + mutable bool mConsumerRunningBehind; + + // mMutex is the mutex used to prevent concurrent access to the member + // variables of Surface objects. It must be locked whenever the + // member variables are accessed. + mutable Mutex mMutex; + + // must be used from the lock/unlock thread + sp mLockedBuffer; + sp mPostedBuffer; + bool mConnectedToCpu; + + // must be accessed from lock/unlock thread only + Region mDirtyRegion; +}; + +}; // namespace android + +#endif // ANDROID_GUI_SURFACE_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowJB.cpp b/widget/gonk/nativewindow/GonkNativeWindowJB.cpp old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkNativeWindowJB.h b/widget/gonk/nativewindow/GonkNativeWindowJB.h old mode 100755 new mode 100644 diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowLL.cpp new file mode 100644 index 000000000000..fe50c55f51a0 --- /dev/null +++ b/widget/gonk/nativewindow/GonkNativeWindowLL.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "BufferItemConsumer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include + +#include + +#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) + +namespace android { + +BufferItemConsumer::BufferItemConsumer( + const sp& consumer, uint32_t consumerUsage, + int bufferCount, bool controlledByApp) : + ConsumerBase(consumer, controlledByApp) +{ + status_t err = mConsumer->setConsumerUsageBits(consumerUsage); + LOG_ALWAYS_FATAL_IF(err != OK, + "Failed to set consumer usage bits to %#x", consumerUsage); + if (bufferCount != DEFAULT_MAX_BUFFERS) { + err = mConsumer->setMaxAcquiredBufferCount(bufferCount); + LOG_ALWAYS_FATAL_IF(err != OK, + "Failed to set max acquired buffer count to %d", bufferCount); + } +} + +BufferItemConsumer::~BufferItemConsumer() { +} + +void BufferItemConsumer::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + mName = name; + mConsumer->setConsumerName(name); +} + +status_t BufferItemConsumer::acquireBuffer(BufferItem *item, + nsecs_t presentWhen, bool waitForFence) { + status_t err; + + if (!item) return BAD_VALUE; + + Mutex::Autolock _l(mMutex); + + err = acquireBufferLocked(item, presentWhen); + if (err != OK) { + if (err != NO_BUFFER_AVAILABLE) { + BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); + } + return err; + } + + if (waitForFence) { + err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer"); + if (err != OK) { + BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", + strerror(-err), err); + return err; + } + } + + item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; + + return OK; +} + +status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, + const sp& releaseFence) { + status_t err; + + Mutex::Autolock _l(mMutex); + + err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); + + err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR); + if (err != OK) { + BI_LOGE("Failed to release buffer: %s (%d)", + strerror(-err), err); + } + return err; +} + +status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferSize(w, h); +} + +status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferFormat(defaultFormat); +} + +} // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.h b/widget/gonk/nativewindow/GonkNativeWindowLL.h new file mode 100644 index 000000000000..5494ff1f306d --- /dev/null +++ b/widget/gonk/nativewindow/GonkNativeWindowLL.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H +#define ANDROID_GUI_BUFFERITEMCONSUMER_H + +#include + +#include + +#include +#include +#include + +#define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer" + +namespace android { + +class BufferQueue; + +/** + * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients + * access to the whole BufferItem entry from BufferQueue. Multiple buffers may + * be acquired at once, to be used concurrently by the client. This consumer can + * operate either in synchronous or asynchronous mode. + */ +class BufferItemConsumer: public ConsumerBase +{ + public: + typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; + + typedef BufferQueue::BufferItem BufferItem; + + enum { DEFAULT_MAX_BUFFERS = -1 }; + enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; + enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; + + // Create a new buffer item consumer. The consumerUsage parameter determines + // the consumer usage flags passed to the graphics allocator. The + // bufferCount parameter specifies how many buffers can be locked for user + // access at the same time. + // controlledByApp tells whether this consumer is controlled by the + // application. + BufferItemConsumer(const sp& consumer, + uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, + bool controlledByApp = false); + + virtual ~BufferItemConsumer(); + + // set the name of the BufferItemConsumer that will be used to identify it in + // log messages. + void setName(const String8& name); + + // Gets the next graphics buffer from the producer, filling out the + // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue + // of buffers is empty, and INVALID_OPERATION if the maximum number of + // buffers is already acquired. + // + // Only a fixed number of buffers can be acquired at a time, determined by + // the construction-time bufferCount parameter. If INVALID_OPERATION is + // returned by acquireBuffer, then old buffers must be returned to the + // queue by calling releaseBuffer before more buffers can be acquired. + // + // If waitForFence is true, and the acquired BufferItem has a valid fence object, + // acquireBuffer will wait on the fence with no timeout before returning. + status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, + bool waitForFence = true); + + // Returns an acquired buffer to the queue, allowing it to be reused. Since + // only a fixed number of buffers may be acquired at a time, old buffers + // must be released by calling releaseBuffer to ensure new buffers can be + // acquired by acquireBuffer. Once a BufferItem is released, the caller must + // not access any members of the BufferItem, and should immediately remove + // all of its references to the BufferItem itself. + status_t releaseBuffer(const BufferItem &item, + const sp& releaseFence = Fence::NO_FENCE); + + // setDefaultBufferSize is used to set the size of buffers returned by + // requestBuffers when a with and height of zero is requested. + status_t setDefaultBufferSize(uint32_t w, uint32_t h); + + // setDefaultBufferFormat allows the BufferQueue to create + // GraphicBuffers of a defaultFormat if no format is specified + // in dequeueBuffer + status_t setDefaultBufferFormat(uint32_t defaultFormat); +}; + +} // namespace android + +#endif // ANDROID_GUI_CPUCONSUMER_H diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h new file mode 100644 index 000000000000..c4f6d92af7d9 --- /dev/null +++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h @@ -0,0 +1,18 @@ +/* Copyright 2013 Mozilla Foundation and Mozilla contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 +# include "IGonkGraphicBufferConsumerKK.h" +#endif From 9ac121c9e540895cc02793e821db7b5eec1072cd Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Sun, 21 Dec 2014 22:01:00 +0100 Subject: [PATCH 36/64] Bug 1098970 - Part 4: Fix naming problems and buffer allocation. r=sotaro 1. Fix class naming by adding "Gonk" prefix, and rename Surface & BufferItemConsumer. 2. Revise the buffer allocation --- .../gonk/nativewindow/FakeSurfaceComposer.cpp | 97 +++- .../gonk/nativewindow/FakeSurfaceComposer.h | 36 +- widget/gonk/nativewindow/GonkBufferQueue.h | 4 +- widget/gonk/nativewindow/GonkBufferQueueKK.h | 1 - .../GonkBufferQueueLL/GonkBufferItem.cpp | 23 +- .../GonkBufferQueueLL/GonkBufferItem.h | 18 +- .../GonkBufferQueueConsumer.cpp | 232 +++++---- .../GonkBufferQueueConsumer.h | 74 ++- .../GonkBufferQueueLL/GonkBufferQueueCore.cpp | 104 +++-- .../GonkBufferQueueLL/GonkBufferQueueCore.h | 68 ++- .../GonkBufferQueueLL/GonkBufferQueueDefs.h | 17 +- .../GonkBufferQueueLL/GonkBufferQueueLL.cpp | 43 +- .../GonkBufferQueueLL/GonkBufferQueueLL.h | 39 +- .../GonkBufferQueueProducer.cpp | 440 +++++++----------- .../GonkBufferQueueProducer.h | 41 +- .../GonkBufferQueueLL/GonkBufferSlot.cpp | 13 +- .../GonkBufferQueueLL/GonkBufferSlot.h | 32 +- .../gonk/nativewindow/GonkConsumerBaseLL.cpp | 102 ++-- widget/gonk/nativewindow/GonkConsumerBaseLL.h | 95 ++-- widget/gonk/nativewindow/GonkNativeWindow.h | 4 +- .../nativewindow/GonkNativeWindowClient.h | 6 +- .../nativewindow/GonkNativeWindowClientLL.cpp | 348 ++++---------- .../nativewindow/GonkNativeWindowClientLL.h | 54 +-- .../gonk/nativewindow/GonkNativeWindowLL.cpp | 130 +++++- widget/gonk/nativewindow/GonkNativeWindowLL.h | 64 ++- .../nativewindow/IGonkGraphicBufferConsumer.h | 4 +- .../IGonkGraphicBufferConsumerKK.cpp | 2 +- .../IGonkGraphicBufferConsumerKK.h | 4 +- .../IGonkGraphicBufferConsumerLL.cpp | 114 +++-- .../IGonkGraphicBufferConsumerLL.h | 34 +- widget/gonk/nativewindow/moz.build | 36 +- 31 files changed, 1125 insertions(+), 1154 deletions(-) diff --git a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp b/widget/gonk/nativewindow/FakeSurfaceComposer.cpp index 82297ae9f2a6..1b34761a9d82 100644 --- a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp +++ b/widget/gonk/nativewindow/FakeSurfaceComposer.cpp @@ -23,6 +23,10 @@ #include #include +#if ANDROID_VERSION >= 21 +#include +#endif + #include "FakeSurfaceComposer.h" namespace android { @@ -89,31 +93,84 @@ sp FakeSurfaceComposer::createDisplayEventConnection() return nullptr; } -status_t FakeSurfaceComposer::captureScreen(const sp& display, - const sp& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, - bool isCpuConsumer) { +status_t +FakeSurfaceComposer::captureScreen(const sp& display + , const sp& producer +#if ANDROID_VERSION >= 21 + , Rect sourceCrop +#endif + , uint32_t reqWidth + , uint32_t reqHeight + , uint32_t minLayerZ + , uint32_t maxLayerZ +#if ANDROID_VERSION >= 21 + , bool useIdentityTransform + , Rotation rotation +#elif ANDROID_VERSION < 19 + , bool isCpuConsumer +#endif + ) +{ return INVALID_OPERATION; } -#if ANDROID_VERSION >= 19 -status_t FakeSurfaceComposer::captureScreen(const sp& display, - const sp& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) { +#if ANDROID_VERSION >= 21 +void +FakeSurfaceComposer::setPowerMode(const sp& display, int mode) +{ +} + +status_t +FakeSurfaceComposer::getDisplayConfigs(const sp& display, Vector* configs) +{ + return INVALID_OPERATION; +} + +status_t +FakeSurfaceComposer::getDisplayStats(const sp& display, DisplayStatInfo* stats) +{ + return INVALID_OPERATION; +} + +int +FakeSurfaceComposer::getActiveConfig(const sp& display) +{ + return INVALID_OPERATION; +} + +status_t +FakeSurfaceComposer::setActiveConfig(const sp& display, int id) +{ + return INVALID_OPERATION; +} + +status_t +FakeSurfaceComposer::clearAnimationFrameStats() +{ + return INVALID_OPERATION; +} + +status_t +FakeSurfaceComposer::getAnimationFrameStats(FrameStats* outStats) const +{ + return INVALID_OPERATION; +} +#else +void +FakeSurfaceComposer::blank(const sp& display) +{ +} + +void +FakeSurfaceComposer::unblank(const sp& display) +{ +} + +status_t +FakeSurfaceComposer::getDisplayInfo(const sp& display, DisplayInfo* info) +{ return INVALID_OPERATION; } #endif -void FakeSurfaceComposer::blank(const sp& display) { -} - -void FakeSurfaceComposer::unblank(const sp& display) { -} - -status_t FakeSurfaceComposer::getDisplayInfo(const sp& display, DisplayInfo* info) { - return INVALID_OPERATION; -} - }; // namespace android diff --git a/widget/gonk/nativewindow/FakeSurfaceComposer.h b/widget/gonk/nativewindow/FakeSurfaceComposer.h index ae47b5c0cb1d..9f6bab654bae 100644 --- a/widget/gonk/nativewindow/FakeSurfaceComposer.h +++ b/widget/gonk/nativewindow/FakeSurfaceComposer.h @@ -45,10 +45,28 @@ public: // Instantiate MediaResourceManagerService and register to service manager. // If service manager is not present, wait until service manager becomes present. static void instantiate(); + #if ANDROID_VERSION >= 19 virtual void destroyDisplay(const sp& display); - virtual status_t captureScreen(const sp& display, const sp& producer, - uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ); +#endif + +#if ANDROID_VERSION >= 21 + virtual status_t captureScreen(const sp& display, + const sp& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, + Rotation rotation = eRotateNone); +#elif ANDROID_VERSION >= 19 + virtual status_t captureScreen(const sp& display, + const sp& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ); +#else + virtual status_t captureScreen(const sp& display, + const sp& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer); #endif private: @@ -69,15 +87,21 @@ private: virtual bool authenticateSurfaceTexture( const sp& bufferProducer) const; virtual sp createDisplayEventConnection(); - virtual status_t captureScreen(const sp& display, - const sp& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer); +#if ANDROID_VERSION >= 21 + virtual void setPowerMode(const sp& display, int mode); + virtual status_t getDisplayConfigs(const sp& display, Vector* configs); + virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats); + virtual int getActiveConfig(const sp& display); + virtual status_t setActiveConfig(const sp& display, int id); + virtual status_t clearAnimationFrameStats(); + virtual status_t getAnimationFrameStats(FrameStats* outStats) const; +#elif ANDROID_VERSION >= 17 // called when screen needs to turn off virtual void blank(const sp& display); // called when screen is turning back on virtual void unblank(const sp& display); virtual status_t getDisplayInfo(const sp& display, DisplayInfo* info); +#endif }; diff --git a/widget/gonk/nativewindow/GonkBufferQueue.h b/widget/gonk/nativewindow/GonkBufferQueue.h index 75cedbef12d3..defdb0ae2f1a 100644 --- a/widget/gonk/nativewindow/GonkBufferQueue.h +++ b/widget/gonk/nativewindow/GonkBufferQueue.h @@ -13,7 +13,9 @@ * limitations under the License. */ -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 +# include "GonkBufferQueueLL.h" +#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 # include "GonkBufferQueueKK.h" #elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 # include "GonkBufferQueueJB.h" diff --git a/widget/gonk/nativewindow/GonkBufferQueueKK.h b/widget/gonk/nativewindow/GonkBufferQueueKK.h index 851b63f9a23c..0209de02c51f 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueKK.h +++ b/widget/gonk/nativewindow/GonkBufferQueueKK.h @@ -334,7 +334,6 @@ private: // freeAllBuffersLocked frees the GraphicBuffer and sync resources for // all slots. - //void freeAllBuffersLocked(); void freeAllBuffersLocked(); // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp index d3fa43e75f08..7df72bf68e31 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +15,7 @@ * limitations under the License. */ -#include +#include "GonkBufferItem.h" #include #include @@ -23,7 +24,7 @@ namespace android { -BufferItem::BufferItem() : +GonkBufferItem::GonkBufferItem() : mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), @@ -36,8 +37,8 @@ BufferItem::BufferItem() : mCrop.makeInvalid(); } -BufferItem::operator IGraphicBufferConsumer::BufferItem() const { - IGraphicBufferConsumer::BufferItem bufferItem; +GonkBufferItem::operator IGonkGraphicBufferConsumer::BufferItem() const { + IGonkGraphicBufferConsumer::BufferItem bufferItem; bufferItem.mGraphicBuffer = mGraphicBuffer; bufferItem.mFence = mFence; bufferItem.mCrop = mCrop; @@ -53,7 +54,7 @@ BufferItem::operator IGraphicBufferConsumer::BufferItem() const { return bufferItem; } -size_t BufferItem::getPodSize() const { +size_t GonkBufferItem::getPodSize() const { size_t c = sizeof(mCrop) + sizeof(mTransform) + sizeof(mScalingMode) + @@ -67,7 +68,7 @@ size_t BufferItem::getPodSize() const { return c; } -size_t BufferItem::getFlattenedSize() const { +size_t GonkBufferItem::getFlattenedSize() const { size_t c = 0; if (mGraphicBuffer != 0) { c += mGraphicBuffer->getFlattenedSize(); @@ -80,7 +81,7 @@ size_t BufferItem::getFlattenedSize() const { return sizeof(int32_t) + c + getPodSize(); } -size_t BufferItem::getFdCount() const { +size_t GonkBufferItem::getFdCount() const { size_t c = 0; if (mGraphicBuffer != 0) { c += mGraphicBuffer->getFdCount(); @@ -91,11 +92,11 @@ size_t BufferItem::getFdCount() const { return c; } -status_t BufferItem::flatten( +status_t GonkBufferItem::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { // make sure we have enough space - if (count < BufferItem::getFlattenedSize()) { + if (count < GonkBufferItem::getFlattenedSize()) { return NO_MEMORY; } @@ -138,7 +139,7 @@ status_t BufferItem::flatten( return NO_ERROR; } -status_t BufferItem::unflatten( +status_t GonkBufferItem::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { if (size < sizeof(uint32_t)) @@ -180,7 +181,7 @@ status_t BufferItem::unflatten( return NO_ERROR; } -const char* BufferItem::scalingModeName(uint32_t scalingMode) { +const char* GonkBufferItem::scalingModeName(uint32_t scalingMode) { switch (scalingMode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h index 5effd10e04cf..b2d6d3068125 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,13 +15,10 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERITEM_H -#define ANDROID_GUI_BUFFERITEM_H +#ifndef NATIVEWINDOW_GONKBUFFERITEM_LL_H +#define NATIVEWINDOW_GONKBUFFERITEM_LL_H -#include -#include - -#include +#include "IGonkGraphicBufferConsumerLL.h" #include @@ -32,8 +30,8 @@ namespace android { class Fence; class GraphicBuffer; -class BufferItem : public Flattenable { - friend class Flattenable; +class GonkBufferItem : public Flattenable { + friend class Flattenable; size_t getPodSize() const; size_t getFlattenedSize() const; size_t getFdCount() const; @@ -43,8 +41,8 @@ class BufferItem : public Flattenable { public: // The default value of mBuf, used to indicate this doesn't correspond to a slot. enum { INVALID_BUFFER_SLOT = -1 }; - BufferItem(); - operator IGraphicBufferConsumer::BufferItem() const; + GonkBufferItem(); + operator IGonkGraphicBufferConsumer::BufferItem() const; static const char* scalingModeName(uint32_t scalingMode); diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp index 36e3c06a5a9f..b9543ed48acd 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,26 +17,26 @@ #include -#define LOG_TAG "BufferQueueConsumer" +#define LOG_TAG "GonkBufferQueueConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 -#include -#include -#include +#include "GonkBufferItem.h" +#include "GonkBufferQueueConsumer.h" +#include "GonkBufferQueueCore.h" #include #include namespace android { -BufferQueueConsumer::BufferQueueConsumer(const sp& core) : +GonkBufferQueueConsumer::GonkBufferQueueConsumer(const sp& core) : mCore(core), mSlots(core->mSlots), mConsumerName() {} -BufferQueueConsumer::~BufferQueueConsumer() {} +GonkBufferQueueConsumer::~GonkBufferQueueConsumer() {} -status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, +status_t GonkBufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, nsecs_t expectedPresent) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); @@ -45,13 +46,13 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // buffer so that the consumer can successfully set up the newly acquired // buffer before releasing the old one. int numAcquiredBuffers = 0; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { + for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == GonkBufferSlot::ACQUIRED) { ++numAcquiredBuffers; } } if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", + ALOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); return INVALID_OPERATION; } @@ -63,7 +64,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, return NO_BUFFER_AVAILABLE; } - BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); + GonkBufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); // If expectedPresent is specified, we may not want to return a buffer yet. // If it's specified and there's more than one buffer queued, we may want @@ -106,7 +107,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // This buffer is set to display in the near future, or // desiredPresent is garbage. Either way we don't want to drop // the previous buffer just to get this on the screen sooner. - BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" + ALOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" PRId64 " (%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, @@ -114,12 +115,12 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, break; } - BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 + ALOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 " size=%zu", desiredPresent, expectedPresent, mCore->mQueue.size()); if (mCore->stillTracking(front)) { // Front buffer is still in mSlots, so mark the slot as free - mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + mSlots[front->mSlot].mBufferState = GonkBufferSlot::FREE; } mCore->mQueue.erase(front); front = mCore->mQueue.begin(); @@ -129,7 +130,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, nsecs_t desiredPresent = front->mTimestamp; if (desiredPresent > expectedPresent && desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { - BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 + ALOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 " (%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, @@ -137,32 +138,37 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, return PRESENT_LATER; } - BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " + ALOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC)); } int slot = front->mSlot; - *outBuffer = *front; + //*outBuffer = *front; + outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer; + outBuffer->mFrameNumber = mSlots[slot].mFrameNumber; + outBuffer->mBuf = slot; + outBuffer->mFence = mSlots[slot].mFence; + ATRACE_BUFFER_INDEX(slot); - BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", + ALOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", slot, front->mFrameNumber, front->mGraphicBuffer->handle); // If the front buffer is still being tracked, update its slot state if (mCore->stillTracking(front)) { mSlots[slot].mAcquireCalled = true; mSlots[slot].mNeedsCleanupOnRelease = false; - mSlots[slot].mBufferState = BufferSlot::ACQUIRED; + mSlots[slot].mBufferState = GonkBufferSlot::ACQUIRED; mSlots[slot].mFence = Fence::NO_FENCE; } // If the buffer has previously been acquired by the consumer, set // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer // on the consumer side - if (outBuffer->mAcquireCalled) { - outBuffer->mGraphicBuffer = NULL; - } + //if (outBuffer->mAcquireCalled) { + // outBuffer->mGraphicBuffer = NULL; + //} mCore->mQueue.erase(front); @@ -171,28 +177,26 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // decrease. mCore->mDequeueCondition.broadcast(); - ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); - return NO_ERROR; } -status_t BufferQueueConsumer::detachBuffer(int slot) { +status_t GonkBufferQueueConsumer::detachBuffer(int slot) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); - BQ_LOGV("detachBuffer(C): slot %d", slot); + ALOGV("detachBuffer(C): slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("detachBuffer(C): BufferQueue has been abandoned"); + ALOGE("detachBuffer(C): GonkBufferQueue has been abandoned"); return NO_INIT; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("detachBuffer(C): slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { + ALOGE("detachBuffer(C): slot index %d out of range [0, %d)", + slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::ACQUIRED) { - BQ_LOGE("detachBuffer(C): slot %d is not owned by the consumer " + } else if (mSlots[slot].mBufferState != GonkBufferSlot::ACQUIRED) { + ALOGE("detachBuffer(C): slot %d is not owned by the consumer " "(state = %d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; } @@ -203,15 +207,15 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { return NO_ERROR; } -status_t BufferQueueConsumer::attachBuffer(int* outSlot, +status_t GonkBufferQueueConsumer::attachBuffer(int* outSlot, const sp& buffer) { ATRACE_CALL(); if (outSlot == NULL) { - BQ_LOGE("attachBuffer(P): outSlot must not be NULL"); + ALOGE("attachBuffer(P): outSlot must not be NULL"); return BAD_VALUE; } else if (buffer == NULL) { - BQ_LOGE("attachBuffer(P): cannot attach NULL buffer"); + ALOGE("attachBuffer(P): cannot attach NULL buffer"); return BAD_VALUE; } @@ -220,12 +224,12 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, // Make sure we don't have too many acquired buffers and find a free slot // to put the buffer into (the oldest if there are multiple). int numAcquiredBuffers = 0; - int found = BufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { + int found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; + for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == GonkBufferSlot::ACQUIRED) { ++numAcquiredBuffers; - } else if (mSlots[s].mBufferState == BufferSlot::FREE) { - if (found == BufferQueueCore::INVALID_BUFFER_SLOT || + } else if (mSlots[s].mBufferState == GonkBufferSlot::FREE) { + if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { found = s; } @@ -233,28 +237,28 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, } if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - BQ_LOGE("attachBuffer(P): max acquired buffer count reached: %d " + ALOGE("attachBuffer(P): max acquired buffer count reached: %d " "(max %d)", numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); return INVALID_OPERATION; } - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - BQ_LOGE("attachBuffer(P): could not find free buffer slot"); + if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { + ALOGE("attachBuffer(P): could not find free buffer slot"); return NO_MEMORY; } *outSlot = found; ATRACE_BUFFER_INDEX(*outSlot); - BQ_LOGV("attachBuffer(C): returning slot %d", *outSlot); + ALOGV("attachBuffer(C): returning slot %d", *outSlot); mSlots[*outSlot].mGraphicBuffer = buffer; - mSlots[*outSlot].mBufferState = BufferSlot::ACQUIRED; + mSlots[*outSlot].mBufferState = GonkBufferSlot::ACQUIRED; mSlots[*outSlot].mAttachedByConsumer = true; mSlots[*outSlot].mNeedsCleanupOnRelease = false; mSlots[*outSlot].mFence = Fence::NO_FENCE; mSlots[*outSlot].mFrameNumber = 0; - // mAcquireCalled tells BufferQueue that it doesn't need to send a valid + // mAcquireCalled tells GonkBufferQueue that it doesn't need to send a valid // GraphicBuffer pointer on the next acquireBuffer call, which decreases // Binder traffic by not un/flattening the GraphicBuffer. However, it // requires that the consumer maintain a cached copy of the slot <--> buffer @@ -274,13 +278,11 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, return NO_ERROR; } -status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, - const sp& releaseFence, EGLDisplay eglDisplay, - EGLSyncKHR eglFence) { +status_t GonkBufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, + const sp& releaseFence) { ATRACE_CALL(); - ATRACE_BUFFER_INDEX(slot); - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || + if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS || releaseFence == NULL) { return BAD_VALUE; } @@ -291,35 +293,33 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, // If the frame number has changed because the buffer has been reallocated, // we can ignore this releaseBuffer for the old buffer - if (frameNumber != mSlots[slot].mFrameNumber) { - return STALE_BUFFER_SLOT; - } + //if (frameNumber != mSlots[slot].mFrameNumber) { + // return STALE_BUFFER_SLOT; + //} // Make sure this buffer hasn't been queued while acquired by the consumer - BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); + GonkBufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); while (current != mCore->mQueue.end()) { if (current->mSlot == slot) { - BQ_LOGE("releaseBuffer: buffer slot %d pending release is " + ALOGE("releaseBuffer: buffer slot %d pending release is " "currently queued", slot); return BAD_VALUE; } ++current; } - if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { - mSlots[slot].mEglDisplay = eglDisplay; - mSlots[slot].mEglFence = eglFence; + if (mSlots[slot].mBufferState == GonkBufferSlot::ACQUIRED) { mSlots[slot].mFence = releaseFence; - mSlots[slot].mBufferState = BufferSlot::FREE; + mSlots[slot].mBufferState = GonkBufferSlot::FREE; listener = mCore->mConnectedProducerListener; - BQ_LOGV("releaseBuffer: releasing slot %d", slot); + ALOGV("releaseBuffer: releasing slot %d", slot); } else if (mSlots[slot].mNeedsCleanupOnRelease) { - BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d " + ALOGV("releaseBuffer: releasing a stale buffer slot %d " "(state = %d)", slot, mSlots[slot].mBufferState); mSlots[slot].mNeedsCleanupOnRelease = false; return STALE_BUFFER_SLOT; } else { - BQ_LOGV("releaseBuffer: attempted to release buffer slot %d " + ALOGV("releaseBuffer: attempted to release buffer slot %d " "but its state was %d", slot, mSlots[slot].mBufferState); return BAD_VALUE; } @@ -335,22 +335,22 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, return NO_ERROR; } -status_t BufferQueueConsumer::connect( +status_t GonkBufferQueueConsumer::connect( const sp& consumerListener, bool controlledByApp) { ATRACE_CALL(); if (consumerListener == NULL) { - BQ_LOGE("connect(C): consumerListener may not be NULL"); + ALOGE("connect(C): consumerListener may not be NULL"); return BAD_VALUE; } - BQ_LOGV("connect(C): controlledByApp=%s", + ALOGV("connect(C): controlledByApp=%s", controlledByApp ? "true" : "false"); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("connect(C): BufferQueue has been abandoned"); + ALOGE("connect(C): GonkBufferQueue has been abandoned"); return NO_INIT; } @@ -360,15 +360,15 @@ status_t BufferQueueConsumer::connect( return NO_ERROR; } -status_t BufferQueueConsumer::disconnect() { +status_t GonkBufferQueueConsumer::disconnect() { ATRACE_CALL(); - BQ_LOGV("disconnect(C)"); + ALOGV("disconnect(C)"); Mutex::Autolock lock(mCore->mMutex); if (mCore->mConsumerListener == NULL) { - BQ_LOGE("disconnect(C): no consumer is connected"); + ALOGE("disconnect(C): no consumer is connected"); return BAD_VALUE; } @@ -380,23 +380,23 @@ status_t BufferQueueConsumer::disconnect() { return NO_ERROR; } -status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { +status_t GonkBufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { ATRACE_CALL(); if (outSlotMask == NULL) { - BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL"); + ALOGE("getReleasedBuffers: outSlotMask may not be NULL"); return BAD_VALUE; } Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned"); + ALOGE("getReleasedBuffers: GonkBufferQueue has been abandoned"); return NO_INIT; } uint64_t mask = 0; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { if (!mSlots[s].mAcquireCalled) { mask |= (1ULL << s); } @@ -405,7 +405,7 @@ status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { // Remove from the mask queued buffers for which acquire has been called, // since the consumer will not receive their buffer addresses and so must // retain their cached information - BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); + GonkBufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); while (current != mCore->mQueue.end()) { if (current->mAcquireCalled) { mask &= ~(1ULL << current->mSlot); @@ -413,22 +413,22 @@ status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { ++current; } - BQ_LOGV("getReleasedBuffers: returning mask %#" PRIx64, mask); + ALOGV("getReleasedBuffers: returning mask %#" PRIx64, mask); *outSlotMask = mask; return NO_ERROR; } -status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, +status_t GonkBufferQueueConsumer::setDefaultBufferSize(uint32_t width, uint32_t height) { ATRACE_CALL(); if (width == 0 || height == 0) { - BQ_LOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u " + ALOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u " "height=%u)", width, height); return BAD_VALUE; } - BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height); + ALOGV("setDefaultBufferSize: width=%u height=%u", width, height); Mutex::Autolock lock(mCore->mMutex); mCore->mDefaultWidth = width; @@ -436,88 +436,122 @@ status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width, return NO_ERROR; } -status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) { +status_t GonkBufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); return mCore->setDefaultMaxBufferCountLocked(bufferCount); } -status_t BufferQueueConsumer::disableAsyncBuffer() { +status_t GonkBufferQueueConsumer::disableAsyncBuffer() { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); if (mCore->mConsumerListener != NULL) { - BQ_LOGE("disableAsyncBuffer: consumer already connected"); + ALOGE("disableAsyncBuffer: consumer already connected"); return INVALID_OPERATION; } - BQ_LOGV("disableAsyncBuffer"); + ALOGV("disableAsyncBuffer"); mCore->mUseAsyncBuffer = false; return NO_ERROR; } -status_t BufferQueueConsumer::setMaxAcquiredBufferCount( +status_t GonkBufferQueueConsumer::setMaxAcquiredBufferCount( int maxAcquiredBuffers) { ATRACE_CALL(); if (maxAcquiredBuffers < 1 || - maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { - BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d", + maxAcquiredBuffers > GonkBufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { + ALOGE("setMaxAcquiredBufferCount: invalid count %d", maxAcquiredBuffers); return BAD_VALUE; } Mutex::Autolock lock(mCore->mMutex); - if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { - BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected"); + if (mCore->mConnectedApi != GonkBufferQueueCore::NO_CONNECTED_API) { + ALOGE("setMaxAcquiredBufferCount: producer is already connected"); return INVALID_OPERATION; } - BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); + ALOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; return NO_ERROR; } -void BufferQueueConsumer::setConsumerName(const String8& name) { +void GonkBufferQueueConsumer::setConsumerName(const String8& name) { ATRACE_CALL(); - BQ_LOGV("setConsumerName: '%s'", name.string()); + ALOGV("setConsumerName: '%s'", name.string()); Mutex::Autolock lock(mCore->mMutex); mCore->mConsumerName = name; mConsumerName = name; } -status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { +status_t GonkBufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { ATRACE_CALL(); - BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat); + ALOGV("setDefaultBufferFormat: %u", defaultFormat); Mutex::Autolock lock(mCore->mMutex); mCore->mDefaultBufferFormat = defaultFormat; return NO_ERROR; } -status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { +status_t GonkBufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { ATRACE_CALL(); - BQ_LOGV("setConsumerUsageBits: %#x", usage); + ALOGV("setConsumerUsageBits: %#x", usage); Mutex::Autolock lock(mCore->mMutex); mCore->mConsumerUsageBits = usage; return NO_ERROR; } -status_t BufferQueueConsumer::setTransformHint(uint32_t hint) { +status_t GonkBufferQueueConsumer::setTransformHint(uint32_t hint) { ATRACE_CALL(); - BQ_LOGV("setTransformHint: %#x", hint); + ALOGV("setTransformHint: %#x", hint); Mutex::Autolock lock(mCore->mMutex); mCore->mTransformHint = hint; return NO_ERROR; } -sp BufferQueueConsumer::getSidebandStream() const { +sp GonkBufferQueueConsumer::getSidebandStream() const { return mCore->mSidebandStream; } -void BufferQueueConsumer::dump(String8& result, const char* prefix) const { +void GonkBufferQueueConsumer::dump(String8& result, const char* prefix) const { mCore->dump(result, prefix); } +TemporaryRef +GonkBufferQueueConsumer::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) +{ + Mutex::Autolock _l(mCore->mMutex); + if (buffer == NULL) { + ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); + return nullptr; + } + + for (int i = 0; i < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; i++) { + if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { + return mSlots[i].mTextureClient; + } + } + ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); + return nullptr; +} + +int +GonkBufferQueueConsumer::getSlotFromTextureClientLocked(GonkBufferSlot::TextureClient* client) const +{ + if (client == NULL) { + ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); + return BAD_VALUE; + } + + for (int i = 0; i < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; i++) { + if (mSlots[i].mTextureClient == client) { + return i; + } + } + ALOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); + return BAD_VALUE; +} } // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h index 1912ed03da63..1bd49a924672 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,27 +15,24 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERQUEUECONSUMER_H -#define ANDROID_GUI_BUFFERQUEUECONSUMER_H +#ifndef NATIVEWINDOW_GONKBUFFERQUEUECONSUMER_LL_H +#define NATIVEWINDOW_GONKBUFFERQUEUECONSUMER_LL_H -#include -#include - -#include -#include +#include "GonkBufferQueueDefs.h" +#include "IGonkGraphicBufferConsumerLL.h" namespace android { -class BufferQueueCore; +class GonkBufferQueueCore; -class BufferQueueConsumer : public BnGraphicBufferConsumer { +class GonkBufferQueueConsumer : public BnGonkGraphicBufferConsumer { public: - BufferQueueConsumer(const sp& core); - virtual ~BufferQueueConsumer(); + GonkBufferQueueConsumer(const sp& core); + virtual ~GonkBufferQueueConsumer(); // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the BufferQueue. If no buffer is pending then it returns + // the GonkBufferQueue. If no buffer is pending then it returns // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the // information about the buffer is returned in BufferItem. If the buffer // returned had previously been acquired then the BufferItem::mGraphicBuffer @@ -49,14 +47,14 @@ public: virtual status_t acquireBuffer(BufferItem* outBuffer, nsecs_t expectedPresent); - // See IGraphicBufferConsumer::detachBuffer + // See IGonkGraphicBufferConsumer::detachBuffer virtual status_t detachBuffer(int slot); - // See IGraphicBufferConsumer::attachBuffer + // See IGonkGraphicBufferConsumer::attachBuffer virtual status_t attachBuffer(int* slot, const sp& buffer); // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue. This may be done while the buffer's contents are still + // GonkBufferQueue. This may be done while the buffer's contents are still // being accessed. The fence will signal when the buffer is no longer // in use. frameNumber is used to indentify the exact buffer returned. // @@ -64,17 +62,13 @@ public: // any references to the just-released buffer that it might have, as if it // had received a onBuffersReleased() call with a mask set for the released // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. virtual status_t releaseBuffer(int slot, uint64_t frameNumber, - const sp& releaseFence, EGLDisplay display, - EGLSyncKHR fence); + const sp& releaseFence); - // connect connects a consumer to the BufferQueue. Only one + // connect connects a consumer to the GonkBufferQueue. Only one // consumer may be connected, and when that consumer disconnects the - // BufferQueue is placed into the "abandoned" state, causing most - // interactions with the BufferQueue by the producer to fail. + // GonkBufferQueue is placed into the "abandoned" state, causing most + // interactions with the GonkBufferQueue by the producer to fail. // controlledByApp indicates whether the consumer is controlled by // the application. // @@ -82,14 +76,14 @@ public: virtual status_t connect(const sp& consumerListener, bool controlledByApp); - // disconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed and the BufferQueue is placed in the "abandoned" - // state, causing most interactions with the BufferQueue by the producer to + // disconnect disconnects a consumer from the GonkBufferQueue. All + // buffers will be freed and the GonkBufferQueue is placed in the "abandoned" + // state, causing most interactions with the GonkBufferQueue by the producer to // fail. virtual status_t disconnect(); // getReleasedBuffers sets the value pointed to by outSlotMask to a bit mask - // indicating which buffer slots have been released by the BufferQueue + // indicating which buffer slots have been released by the GonkBufferQueue // but have not yet been released by the consumer. // // This should be called from the onBuffersReleased() callback. @@ -117,13 +111,13 @@ public: // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the BufferQueue. + // fail if a producer is connected to the GonkBufferQueue. virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // setConsumerName sets the name used in logging virtual void setConsumerName(const String8& name); - // setDefaultBufferFormat allows the BufferQueue to create + // setDefaultBufferFormat allows the GonkBufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified // in dequeueBuffer. Formats are enumerated in graphics.h; the // initial default is HAL_PIXEL_FORMAT_RGBA_8888. @@ -145,16 +139,14 @@ public: // dump our state in a String virtual void dump(String8& result, const char* prefix) const; + // Added by mozilla + virtual mozilla::TemporaryRef getTextureClientFromBuffer(ANativeWindowBuffer* buffer); + + virtual int getSlotFromTextureClientLocked(GonkBufferSlot::TextureClient* client) const; + // Functions required for backwards compatibility. - // These will be modified/renamed in IGraphicBufferConsumer and will be + // These will be modified/renamed in IGonkGraphicBufferConsumer and will be // removed from this class at that time. See b/13306289. - - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, - EGLDisplay display, EGLSyncKHR fence, - const sp& releaseFence) { - return releaseBuffer(buf, frameNumber, releaseFence, display, fence); - } - virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { return connect(consumer, controlledByApp); @@ -165,16 +157,16 @@ public: // End functions required for backwards compatibility private: - sp mCore; + sp mCore; // This references mCore->mSlots. Lock mCore->mMutex while accessing. - BufferQueueDefs::SlotsType& mSlots; + GonkBufferQueueDefs::SlotsType& mSlots; - // This is a cached copy of the name stored in the BufferQueueCore. + // This is a cached copy of the name stored in the GonkBufferQueueCore. // It's updated during setConsumerName. String8 mConsumerName; -}; // class BufferQueueConsumer +}; // class GonkBufferQueueConsumer } // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp index ec1e63112d71..3b539b9c4346 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,22 +15,24 @@ * limitations under the License. */ -#define LOG_TAG "BufferQueueCore" +#define LOG_TAG "GonkBufferQueueCore" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 -#define EGL_EGLEXT_PROTOTYPES - #include -#include -#include +#include "GonkBufferItem.h" +#include "GonkBufferQueueCore.h" #include #include #include #include #include +#include +#include "mozilla/layers/GrallocTextureClient.h" +#include "mozilla/layers/ImageBridgeChild.h" + template static inline T max(T a, T b) { return a > b ? a : b; } @@ -41,7 +44,7 @@ static String8 getUniqueName() { android_atomic_inc(&counter)); } -BufferQueueCore::BufferQueueCore(const sp& allocator) : +GonkBufferQueueCore::GonkBufferQueueCore(const sp& allocator) : mAllocator(allocator), mMutex(), mIsAbandoned(false), @@ -68,18 +71,12 @@ BufferQueueCore::BufferQueueCore(const sp& allocator) : mIsAllocating(false), mIsAllocatingCondition() { - if (allocator == NULL) { - sp composer(ComposerService::getComposerService()); - mAllocator = composer->createGraphicBufferAlloc(); - if (mAllocator == NULL) { - BQ_LOGE("createGraphicBufferAlloc failed"); - } - } + ALOGV("GonkBufferQueueCore"); } -BufferQueueCore::~BufferQueueCore() {} +GonkBufferQueueCore::~GonkBufferQueueCore() {} -void BufferQueueCore::dump(String8& result, const char* prefix) const { +void GonkBufferQueueCore::dump(String8& result, const char* prefix) const { Mutex::Autolock lock(mMutex); String8 fifo; @@ -90,11 +87,11 @@ void BufferQueueCore::dump(String8& result, const char* prefix) const { current->mSlot, current->mGraphicBuffer.get(), current->mCrop.left, current->mCrop.top, current->mCrop.right, current->mCrop.bottom, current->mTransform, current->mTimestamp, - BufferItem::scalingModeName(current->mScalingMode)); + GonkBufferItem::scalingModeName(current->mScalingMode)); ++current; } - result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, " + result.appendFormat("%s-GonkBufferQueue mMaxAcquiredBufferCount=%d, " "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n", prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, @@ -103,9 +100,9 @@ void BufferQueueCore::dump(String8& result, const char* prefix) const { // Trim the free buffers so as to not spam the dump int maxBufferCount = 0; - for (int s = BufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) { - const BufferSlot& slot(mSlots[s]); - if (slot.mBufferState != BufferSlot::FREE || + for (int s = GonkBufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) { + const GonkBufferSlot& slot(mSlots[s]); + if (slot.mBufferState != GonkBufferSlot::FREE || slot.mGraphicBuffer != NULL) { maxBufferCount = s + 1; break; @@ -113,12 +110,12 @@ void BufferQueueCore::dump(String8& result, const char* prefix) const { } for (int s = 0; s < maxBufferCount; ++s) { - const BufferSlot& slot(mSlots[s]); + const GonkBufferSlot& slot(mSlots[s]); const sp& buffer(slot.mGraphicBuffer); result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix, - (slot.mBufferState == BufferSlot::ACQUIRED) ? ">" : " ", + (slot.mBufferState == GonkBufferSlot::ACQUIRED) ? ">" : " ", s, buffer.get(), - BufferSlot::bufferStateName(slot.mBufferState)); + GonkBufferSlot::bufferStateName(slot.mBufferState)); if (buffer != NULL) { result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle, @@ -130,7 +127,7 @@ void BufferQueueCore::dump(String8& result, const char* prefix) const { } } -int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const { +int GonkBufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const { // If dequeueBuffer is allowed to error out, we don't have to add an // extra buffer. if (!mUseAsyncBuffer) { @@ -144,11 +141,11 @@ int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const { return mMaxAcquiredBufferCount; } -int BufferQueueCore::getMinMaxBufferCountLocked(bool async) const { +int GonkBufferQueueCore::getMinMaxBufferCountLocked(bool async) const { return getMinUndequeuedBufferCountLocked(async) + 1; } -int BufferQueueCore::getMaxBufferCountLocked(bool async) const { +int GonkBufferQueueCore::getMaxBufferCountLocked(bool async) const { int minMaxBufferCount = getMinMaxBufferCountLocked(async); int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount); @@ -161,9 +158,9 @@ int BufferQueueCore::getMaxBufferCountLocked(bool async) const { // waiting to be consumed need to have their slots preserved. Such buffers // will temporarily keep the max buffer count up until the slots no longer // need to be preserved. - for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - BufferSlot::BufferState state = mSlots[s].mBufferState; - if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { + for (int s = maxBufferCount; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + GonkBufferSlot::BufferState state = mSlots[s].mBufferState; + if (state == GonkBufferSlot::QUEUED || state == GonkBufferSlot::DEQUEUED) { maxBufferCount = s + 1; } } @@ -171,51 +168,58 @@ int BufferQueueCore::getMaxBufferCountLocked(bool async) const { return maxBufferCount; } -status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) { - const int minBufferCount = mUseAsyncBuffer ? 2 : 1; - if (count < minBufferCount || count > BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGV("setDefaultMaxBufferCount: invalid count %d, should be in " +status_t GonkBufferQueueCore::setDefaultMaxBufferCountLocked(int count) { + const int minBufferCount = 2; + if (count < minBufferCount || count > GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { + ALOGV("setDefaultMaxBufferCount: invalid count %d, should be in " "[%d, %d]", - count, minBufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); + count, minBufferCount, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } - BQ_LOGV("setDefaultMaxBufferCount: setting count to %d", count); + ALOGV("setDefaultMaxBufferCount: setting count to %d", count); mDefaultMaxBufferCount = count; mDequeueCondition.broadcast(); return NO_ERROR; } -void BufferQueueCore::freeBufferLocked(int slot) { - BQ_LOGV("freeBufferLocked: slot %d", slot); +void GonkBufferQueueCore::freeBufferLocked(int slot) { + ALOGV("freeBufferLocked: slot %d", slot); + + if (mSlots[slot].mTextureClient) { + mSlots[slot].mTextureClient->ClearRecycleCallback(); + // release TextureClient in ImageBridge thread + TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[slot].mTextureClient); + mSlots[slot].mTextureClient = NULL; + ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); + } mSlots[slot].mGraphicBuffer.clear(); - if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { + if (mSlots[slot].mBufferState == GonkBufferSlot::ACQUIRED) { mSlots[slot].mNeedsCleanupOnRelease = true; } - mSlots[slot].mBufferState = BufferSlot::FREE; + mSlots[slot].mBufferState = GonkBufferSlot::FREE; mSlots[slot].mFrameNumber = UINT32_MAX; mSlots[slot].mAcquireCalled = false; - // Destroy fence as BufferQueue now takes ownership - if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence); - mSlots[slot].mEglFence = EGL_NO_SYNC_KHR; - } + // Destroy fence as GonkBufferQueue now takes ownership mSlots[slot].mFence = Fence::NO_FENCE; } -void BufferQueueCore::freeAllBuffersLocked() { +void GonkBufferQueueCore::freeAllBuffersLocked() { + ALOGW_IF(!mQueue.isEmpty(), + "freeAllBuffersLocked called but mQueue is not empty"); + mQueue.clear(); mBufferHasBeenQueued = false; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { freeBufferLocked(s); } } -bool BufferQueueCore::stillTracking(const BufferItem* item) const { - const BufferSlot& slot = mSlots[item->mSlot]; +bool GonkBufferQueueCore::stillTracking(const GonkBufferItem* item) const { + const GonkBufferSlot& slot = mSlots[item->mSlot]; - BQ_LOGV("stillTracking: item { slot=%d/%" PRIu64 " buffer=%p } " + ALOGV("stillTracking: item { slot=%d/%" PRIu64 " buffer=%p } " "slot { slot=%d/%" PRIu64 " buffer=%p }", item->mSlot, item->mFrameNumber, (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), @@ -228,7 +232,7 @@ bool BufferQueueCore::stillTracking(const BufferItem* item) const { (item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); } -void BufferQueueCore::waitWhileAllocatingLocked() const { +void GonkBufferQueueCore::waitWhileAllocatingLocked() const { ATRACE_CALL(); while (mIsAllocating) { mIsAllocatingCondition.wait(mMutex); diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h index 1050e3b6ca2a..936e11686cd3 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +15,11 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERQUEUECORE_H -#define ANDROID_GUI_BUFFERQUEUECORE_H +#ifndef NATIVEWINDOW_GONKBUFFERQUEUECORE_LL_H +#define NATIVEWINDOW_GONKBUFFERQUEUECORE_LL_H -#include -#include +#include "GonkBufferQueueDefs.h" +#include "GonkBufferSlot.h" #include #include @@ -29,31 +30,25 @@ #include #include -#define BQ_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#include "mozilla/layers/TextureClient.h" -#define ATRACE_BUFFER_INDEX(index) \ - if (ATRACE_ENABLED()) { \ - char ___traceBuf[1024]; \ - snprintf(___traceBuf, 1024, "%s: %d", \ - mCore->mConsumerName.string(), (index)); \ - android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ - } +#define ATRACE_BUFFER_INDEX(index) + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace mozilla::layers; namespace android { -class BufferItem; +class GonkBufferItem; class IConsumerListener; class IGraphicBufferAlloc; class IProducerListener; -class BufferQueueCore : public virtual RefBase { +class GonkBufferQueueCore : public virtual RefBase { - friend class BufferQueueProducer; - friend class BufferQueueConsumer; + friend class GonkBufferQueueProducer; + friend class GonkBufferQueueConsumer; public: // Used as a placeholder slot number when the value isn't pointing to an @@ -62,30 +57,33 @@ public: // We reserve two slots in order to guarantee that the producer and // consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; + enum { MAX_MAX_ACQUIRED_BUFFERS = GonkBufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; // The default API number used to indicate that no producer is connected enum { NO_CONNECTED_API = 0 }; - typedef Vector Fifo; + typedef Vector Fifo; + typedef mozilla::layers::TextureClient TextureClient; - // BufferQueueCore manages a pool of gralloc memory slots to be used by + // GonkBufferQueueCore manages a pool of gralloc memory slots to be used by // producers and consumers. allocator is used to allocate all the needed // gralloc buffers. - BufferQueueCore(const sp& allocator = NULL); - virtual ~BufferQueueCore(); + GonkBufferQueueCore(const sp& allocator = NULL); + virtual ~GonkBufferQueueCore(); private: // Dump our state in a string void dump(String8& result, const char* prefix) const; + int getSlotFromTextureClientLocked(TextureClient* client) const; + // getMinUndequeuedBufferCountLocked returns the minimum number of buffers // that must remain in a state other than DEQUEUED. The async parameter // tells whether we're in asynchronous mode. int getMinUndequeuedBufferCountLocked(bool async) const; // getMinMaxBufferCountLocked returns the minimum number of buffers allowed - // given the current BufferQueue state. The async parameter tells whether + // given the current GonkBufferQueue state. The async parameter tells whether // we're in asynchonous mode. int getMinMaxBufferCountLocked(bool async) const; @@ -118,7 +116,7 @@ private: // stillTracking returns true iff the buffer item is still being tracked // in one of the slots. - bool stillTracking(const BufferItem* item) const; + bool stillTracking(const GonkBufferItem* item) const; // waitWhileAllocatingLocked blocks until mIsAllocating is false. void waitWhileAllocatingLocked() const; @@ -128,14 +126,14 @@ private: sp mAllocator; // mMutex is the mutex used to prevent concurrent access to the member - // variables of BufferQueueCore objects. It must be locked whenever any + // variables of GonkBufferQueueCore objects. It must be locked whenever any // member variable is accessed. mutable Mutex mMutex; - // mIsAbandoned indicates that the BufferQueue will no longer be used to + // mIsAbandoned indicates that the GonkBufferQueue will no longer be used to // consume image buffers pushed to it using the IGraphicBufferProducer // interface. It is initialized to false, and set to true in the - // consumerDisconnect method. A BufferQueue that is abandoned will return + // consumerDisconnect method. A GonkBufferQueue that is abandoned will return // the NO_INIT error from all IGraphicBufferProducer methods capable of // returning an error. bool mIsAbandoned; @@ -144,7 +142,7 @@ private: // controlled by the application. bool mConsumerControlledByApp; - // mConsumerName is a string used to identify the BufferQueue in log + // mConsumerName is a string used to identify the GonkBufferQueue in log // messages. It is set by the IGraphicBufferConsumer::setConsumerName // method. String8 mConsumerName; @@ -159,7 +157,7 @@ private: uint32_t mConsumerUsageBits; // mConnectedApi indicates the producer API that is currently connected - // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated + // to this GonkBufferQueue. It defaults to NO_CONNECTED_API, and gets updated // by the connect and disconnect methods. int mConnectedApi; @@ -172,7 +170,7 @@ private: // and consumer without sending a GraphicBuffer over Binder. The entire // array is initialized to NULL at construction time, and buffers are // allocated for a slot when requestBuffer is called with that slot's index. - BufferQueueDefs::SlotsType mSlots; + GonkBufferQueueDefs::SlotsType mSlots; // mQueue is a FIFO of queued buffers used in synchronous mode. Fifo mQueue; @@ -218,7 +216,7 @@ private: // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1, and can be changed by the consumer // via setMaxAcquiredBufferCount, but this may only be done while no - // producer is connected to the BufferQueue. This value is used to derive + // producer is connected to the GonkBufferQueue. This value is used to derive // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. int mMaxAcquiredBufferCount; @@ -246,7 +244,7 @@ private: // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating // becomes false. mutable Condition mIsAllocatingCondition; -}; // class BufferQueueCore +}; // class GonkBufferQueueCore } // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h index 83e958003780..60085706f5e6 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,22 +15,22 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERQUEUECOREDEFS_H -#define ANDROID_GUI_BUFFERQUEUECOREDEFS_H +#ifndef NATIVEWINDOW_BUFFERQUEUECOREDEFS_H +#define NATIVEWINDOW_BUFFERQUEUECOREDEFS_H -#include +#include "GonkBufferSlot.h" namespace android { - class BufferQueueCore; + class GonkBufferQueueCore; - namespace BufferQueueDefs { - // BufferQueue will keep track of at most this value of buffers. + namespace GonkBufferQueueDefs { + // GonkBufferQueue will keep track of at most this value of buffers. // Attempts at runtime to increase the number of buffers past this // will fail. enum { NUM_BUFFER_SLOTS = 64 }; - typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS]; - } // namespace BufferQueueDefs + typedef GonkBufferSlot SlotsType[NUM_BUFFER_SLOTS]; + } // namespace GonkBufferQueueDefs } // namespace android #endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp index c49a8868f0f7..1056c3b0a5ee 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,63 +15,63 @@ * limitations under the License. */ -#define LOG_TAG "BufferQueue" +#define LOG_TAG "GonkBufferQueue" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 -#include -#include -#include -#include +#include "GonkBufferQueue.h" +#include "GonkBufferQueueConsumer.h" +#include "GonkBufferQueueCore.h" +#include "GonkBufferQueueProducer.h" namespace android { -BufferQueue::ProxyConsumerListener::ProxyConsumerListener( +GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( const wp& consumerListener): mConsumerListener(consumerListener) {} -BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} +GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} -void BufferQueue::ProxyConsumerListener::onFrameAvailable() { +void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onFrameAvailable(); } } -void BufferQueue::ProxyConsumerListener::onBuffersReleased() { +void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onBuffersReleased(); } } -void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { +void GonkBufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onSidebandStreamChanged(); } } -void BufferQueue::createBufferQueue(sp* outProducer, - sp* outConsumer, +void GonkBufferQueue::createBufferQueue(sp* outProducer, + sp* outConsumer, const sp& allocator) { LOG_ALWAYS_FATAL_IF(outProducer == NULL, - "BufferQueue: outProducer must not be NULL"); + "GonkBufferQueue: outProducer must not be NULL"); LOG_ALWAYS_FATAL_IF(outConsumer == NULL, - "BufferQueue: outConsumer must not be NULL"); + "GonkBufferQueue: outConsumer must not be NULL"); - sp core(new BufferQueueCore(allocator)); + sp core(new GonkBufferQueueCore(allocator)); LOG_ALWAYS_FATAL_IF(core == NULL, - "BufferQueue: failed to create BufferQueueCore"); + "GonkBufferQueue: failed to create GonkBufferQueueCore"); - sp producer(new BufferQueueProducer(core)); + sp producer(new GonkBufferQueueProducer(core)); LOG_ALWAYS_FATAL_IF(producer == NULL, - "BufferQueue: failed to create BufferQueueProducer"); + "GonkBufferQueue: failed to create GonkBufferQueueProducer"); - sp consumer(new BufferQueueConsumer(core)); + sp consumer(new GonkBufferQueueConsumer(core)); LOG_ALWAYS_FATAL_IF(consumer == NULL, - "BufferQueue: failed to create BufferQueueConsumer"); + "GonkBufferQueue: failed to create GonkBufferQueueConsumer"); *outProducer = producer; *outConsumer = consumer; diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h index 3297b10443db..9fb740af5f0e 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +15,11 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERQUEUE_H -#define ANDROID_GUI_BUFFERQUEUE_H +#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_LL_H +#define NATIVEWINDOW_GONKBUFFERQUEUE_LL_H -#include -#include +#include "GonkBufferQueueDefs.h" +#include "IGonkGraphicBufferConsumerLL.h" #include #include @@ -28,17 +29,17 @@ namespace android { -class BufferQueue { +class GonkBufferQueue { public: - // BufferQueue will keep track of at most this value of buffers. + // GonkBufferQueue will keep track of at most this value of buffers. // Attempts at runtime to increase the number of buffers past this will fail. - enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; + enum { NUM_BUFFER_SLOTS = GonkBufferQueueDefs::NUM_BUFFER_SLOTS }; // Used as a placeholder slot# when the value isn't pointing to an existing buffer. - enum { INVALID_BUFFER_SLOT = IGraphicBufferConsumer::BufferItem::INVALID_BUFFER_SLOT }; - // Alias to -- please scope from there in future code! + enum { INVALID_BUFFER_SLOT = IGonkGraphicBufferConsumer::BufferItem::INVALID_BUFFER_SLOT }; + // Alias to -- please scope from there in future code! enum { - NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE, - PRESENT_LATER = IGraphicBufferConsumer::PRESENT_LATER, + NO_BUFFER_AVAILABLE = IGonkGraphicBufferConsumer::NO_BUFFER_AVAILABLE, + PRESENT_LATER = IGonkGraphicBufferConsumer::PRESENT_LATER, }; // When in async mode we reserve two slots in order to guarantee that the @@ -47,16 +48,16 @@ public: // for backward source compatibility typedef ::android::ConsumerListener ConsumerListener; - typedef IGraphicBufferConsumer::BufferItem BufferItem; + typedef IGonkGraphicBufferConsumer::BufferItem BufferItem; // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak // reference to the actual consumer object. It forwards all calls to that // consumer object so long as it exists. // // This class exists to avoid having a circular reference between the - // BufferQueue object and the consumer object. The reason this can't be a weak - // reference in the BufferQueue class is because we're planning to expose the - // consumer side of a BufferQueue as a binder interface, which doesn't support + // GonkBufferQueue object and the consumer object. The reason this can't be a weak + // reference in the GonkBufferQueue class is because we're planning to expose the + // consumer side of a GonkBufferQueue as a binder interface, which doesn't support // weak references. class ProxyConsumerListener : public BnConsumerListener { public: @@ -71,18 +72,18 @@ public: wp mConsumerListener; }; - // BufferQueue manages a pool of gralloc memory slots to be used by + // GonkBufferQueue manages a pool of gralloc memory slots to be used by // producers and consumers. allocator is used to allocate all the // needed gralloc buffers. static void createBufferQueue(sp* outProducer, - sp* outConsumer, + sp* outConsumer, const sp& allocator = NULL); private: - BufferQueue(); // Create through createBufferQueue + GonkBufferQueue(); // Create through createBufferQueue }; // ---------------------------------------------------------------------------- }; // namespace android -#endif // ANDROID_GUI_BUFFERQUEUE_H +#endif // NATIVEWINDOW_GONKBUFFERQUEUE_LL_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp index d2fd3b025541..5d3bbedb2c12 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,48 +17,51 @@ #include -#define LOG_TAG "BufferQueueProducer" +#define LOG_TAG "GonkBufferQueueProducer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 -#define EGL_EGLEXT_PROTOTYPES - -#include -#include -#include +#include "GonkBufferItem.h" +#include "GonkBufferQueueCore.h" +#include "GonkBufferQueueProducer.h" #include #include #include +#include #include #include +#include "mozilla/layers/GrallocTextureClient.h" +#include "mozilla/layers/ImageBridgeChild.h" +#include "mozilla/layers/TextureClient.h" + namespace android { -BufferQueueProducer::BufferQueueProducer(const sp& core) : +GonkBufferQueueProducer::GonkBufferQueueProducer(const sp& core) : mCore(core), mSlots(core->mSlots), mConsumerName(), mStickyTransform(0) {} -BufferQueueProducer::~BufferQueueProducer() {} +GonkBufferQueueProducer::~GonkBufferQueueProducer() {} -status_t BufferQueueProducer::requestBuffer(int slot, sp* buf) { +status_t GonkBufferQueueProducer::requestBuffer(int slot, sp* buf) { ATRACE_CALL(); - BQ_LOGV("requestBuffer: slot %d", slot); + ALOGV("requestBuffer: slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("requestBuffer: BufferQueue has been abandoned"); + ALOGE("requestBuffer: GonkBufferQueue has been abandoned"); return NO_INIT; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { + ALOGE("requestBuffer: slot index %d out of range [0, %d)", + slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - BQ_LOGE("requestBuffer: slot %d is not owned by the producer " + } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { + ALOGE("requestBuffer: slot %d is not owned by the producer " "(state = %d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; } @@ -67,9 +71,9 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp* buf) { return NO_ERROR; } -status_t BufferQueueProducer::setBufferCount(int bufferCount) { +status_t GonkBufferQueueProducer::setBufferCount(int bufferCount) { ATRACE_CALL(); - BQ_LOGV("setBufferCount: count = %d", bufferCount); + ALOGV("setBufferCount: count = %d", bufferCount); sp listener; { // Autolock scope @@ -77,20 +81,20 @@ status_t BufferQueueProducer::setBufferCount(int bufferCount) { mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { - BQ_LOGE("setBufferCount: BufferQueue has been abandoned"); + ALOGE("setBufferCount: GonkBufferQueue has been abandoned"); return NO_INIT; } - if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("setBufferCount: bufferCount %d too large (max %d)", - bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS); + if (bufferCount > GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { + ALOGE("setBufferCount: bufferCount %d too large (max %d)", + bufferCount, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } // There must be no dequeued buffers when changing the buffer count. - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) { - BQ_LOGE("setBufferCount: buffer owned by producer"); + for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == GonkBufferSlot::DEQUEUED) { + ALOGE("setBufferCount: buffer owned by producer"); return BAD_VALUE; } } @@ -103,7 +107,7 @@ status_t BufferQueueProducer::setBufferCount(int bufferCount) { const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false); if (bufferCount < minBufferSlots) { - BQ_LOGE("setBufferCount: requested buffer count %d is less than " + ALOGE("setBufferCount: requested buffer count %d is less than " "minimum %d", bufferCount, minBufferSlots); return BAD_VALUE; } @@ -126,12 +130,12 @@ status_t BufferQueueProducer::setBufferCount(int bufferCount) { return NO_ERROR; } -status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, +status_t GonkBufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, bool async, int* found, status_t* returnFlags) const { bool tryAgain = true; while (tryAgain) { if (mCore->mIsAbandoned) { - BQ_LOGE("%s: BufferQueue has been abandoned", caller); + ALOGE("%s: GonkBufferQueue has been abandoned", caller); return NO_INIT; } @@ -141,38 +145,38 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, // (which they shouldn't), so we do this extra test here to // handle that case. This is TEMPORARY until we get this fixed. if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - BQ_LOGE("%s: async mode is invalid with buffer count override", + ALOGE("%s: async mode is invalid with buffer count override", caller); return BAD_VALUE; } } // Free up any buffers that are in slots beyond the max buffer count - for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - assert(mSlots[s].mBufferState == BufferSlot::FREE); - if (mSlots[s].mGraphicBuffer != NULL) { - mCore->freeBufferLocked(s); - *returnFlags |= RELEASE_ALL_BUFFERS; - } - } + //for (int s = maxBufferCount; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + // assert(mSlots[s].mBufferState == GonkBufferSlot::FREE); + // if (mSlots[s].mGraphicBuffer != NULL) { + // mCore->freeBufferLocked(s); + // *returnFlags |= RELEASE_ALL_BUFFERS; + // } + //} // Look for a free buffer to give to the client - *found = BufferQueueCore::INVALID_BUFFER_SLOT; + *found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; int dequeuedCount = 0; int acquiredCount = 0; for (int s = 0; s < maxBufferCount; ++s) { switch (mSlots[s].mBufferState) { - case BufferSlot::DEQUEUED: + case GonkBufferSlot::DEQUEUED: ++dequeuedCount; break; - case BufferSlot::ACQUIRED: + case GonkBufferSlot::ACQUIRED: ++acquiredCount; break; - case BufferSlot::FREE: + case GonkBufferSlot::FREE: // We return the oldest of the free buffers to avoid // stalling the producer if possible, since the consumer // may still have pending reads of in-flight buffers - if (*found == BufferQueueCore::INVALID_BUFFER_SLOT || + if (*found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) { *found = s; } @@ -185,7 +189,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, // Producers are not allowed to dequeue more than one buffer if they // did not set a buffer count if (!mCore->mOverrideMaxBufferCount && dequeuedCount) { - BQ_LOGE("%s: can't dequeue multiple buffers without setting the " + ALOGE("%s: can't dequeue multiple buffers without setting the " "buffer count", caller); return INVALID_OPERATION; } @@ -201,7 +205,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, const int minUndequeuedCount = mCore->getMinUndequeuedBufferCountLocked(async); if (newUndequeuedCount < minUndequeuedCount) { - BQ_LOGE("%s: min undequeued buffer count (%d) exceeded " + ALOGE("%s: min undequeued buffer count (%d) exceeded " "(dequeued=%d undequeued=%d)", caller, minUndequeuedCount, dequeuedCount, newUndequeuedCount); @@ -216,14 +220,14 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, bool tooManyBuffers = mCore->mQueue.size() > static_cast(maxBufferCount); if (tooManyBuffers) { - BQ_LOGV("%s: queue size is %zu, waiting", caller, + ALOGV("%s: queue size is %zu, waiting", caller, mCore->mQueue.size()); } // If no buffer is found, or if the queue has too many buffers // outstanding, wait for a buffer to be acquired or released, or for the // max buffer count to change. - tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || + tryAgain = (*found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) || tooManyBuffers; if (tryAgain) { // Return an error if we're in non-blocking mode (producer and @@ -243,7 +247,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, return NO_ERROR; } -status_t BufferQueueProducer::dequeueBuffer(int *outSlot, +status_t GonkBufferQueueProducer::dequeueBuffer(int *outSlot, sp *outFence, bool async, uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { ATRACE_CALL(); @@ -252,17 +256,18 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, mConsumerName = mCore->mConsumerName; } // Autolock scope - BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x", + ALOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x", async ? "true" : "false", width, height, format, usage); if ((width && !height) || (!width && height)) { - BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); + ALOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); return BAD_VALUE; } status_t returnFlags = NO_ERROR; - EGLDisplay eglDisplay = EGL_NO_DISPLAY; - EGLSyncKHR eglFence = EGL_NO_SYNC_KHR; + // Reset slot + *outSlot = GonkBufferQueueCore::INVALID_BUFFER_SLOT; + bool attachedByConsumer = false; { // Autolock scope @@ -284,13 +289,12 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, } // This should not happen - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - BQ_LOGE("dequeueBuffer: no available buffer slots"); + if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { + ALOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } *outSlot = found; - ATRACE_BUFFER_INDEX(found); attachedByConsumer = mSlots[found].mAttachedByConsumer; @@ -300,7 +304,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, height = mCore->mDefaultHeight; } - mSlots[found].mBufferState = BufferSlot::DEQUEUED; + mSlots[found].mBufferState = GonkBufferSlot::DEQUEUED; const sp& buffer(mSlots[found].mGraphicBuffer); if ((buffer == NULL) || @@ -312,46 +316,55 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, mSlots[found].mAcquireCalled = false; mSlots[found].mGraphicBuffer = NULL; mSlots[found].mRequestBufferCalled = false; - mSlots[found].mEglDisplay = EGL_NO_DISPLAY; - mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; + if (mSlots[found].mTextureClient) { + mSlots[found].mTextureClient->ClearRecycleCallback(); + // release TextureClient in ImageBridge thread + TextureClientReleaseTask* task = new TextureClientReleaseTask(mSlots[found].mTextureClient); + mSlots[found].mTextureClient = NULL; + ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); + } + returnFlags |= BUFFER_NEEDS_REALLOCATION; } if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { - BQ_LOGE("dequeueBuffer: about to return a NULL fence - " + ALOGE("dequeueBuffer: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", found, buffer->width, buffer->height, buffer->format); } - eglDisplay = mSlots[found].mEglDisplay; - eglFence = mSlots[found].mEglFence; *outFence = mSlots[found].mFence; - mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; } // Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) { - status_t error; - BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); - sp graphicBuffer(mCore->mAllocator->createGraphicBuffer( - width, height, format, usage, &error)); - if (graphicBuffer == NULL) { - BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); - return error; + RefPtr textureClient = + new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(), + gfx::SurfaceFormat::UNKNOWN, + gfx::BackendType::NONE, + TextureFlags::DEALLOCATE_CLIENT); + textureClient->SetIsOpaque(true); + usage |= GraphicBuffer::USAGE_HW_TEXTURE; + bool result = textureClient->AllocateGralloc(IntSize(width, height), format, usage); + sp graphicBuffer = textureClient->GetGraphicBuffer(); + if (!result || !graphicBuffer.get()) { + ALOGE("dequeueBuffer: failed to alloc gralloc buffer"); + return -ENOMEM; } { // Autolock scope Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); + ALOGE("dequeueBuffer: GonkBufferQueue has been abandoned"); return NO_INIT; } mSlots[*outSlot].mFrameNumber = UINT32_MAX; mSlots[*outSlot].mGraphicBuffer = graphicBuffer; + mSlots[*outSlot].mTextureClient = textureClient; } // Autolock scope } @@ -359,22 +372,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, returnFlags |= BUFFER_NEEDS_REALLOCATION; } - if (eglFence != EGL_NO_SYNC_KHR) { - EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0, - 1000000000); - // If something goes wrong, log the error, but return the buffer without - // synchronizing access to it. It's too late at this point to abort the - // dequeue operation. - if (result == EGL_FALSE) { - BQ_LOGE("dequeueBuffer: error %#x waiting for fence", - eglGetError()); - } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - BQ_LOGE("dequeueBuffer: timeout waiting for fence"); - } - eglDestroySyncKHR(eglDisplay, eglFence); - } - - BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", + ALOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", *outSlot, mSlots[*outSlot].mFrameNumber, mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); @@ -382,27 +380,27 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, return returnFlags; } -status_t BufferQueueProducer::detachBuffer(int slot) { +status_t GonkBufferQueueProducer::detachBuffer(int slot) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); - BQ_LOGV("detachBuffer(P): slot %d", slot); + ALOGV("detachBuffer(P): slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("detachBuffer(P): BufferQueue has been abandoned"); + ALOGE("detachBuffer(P): GonkBufferQueue has been abandoned"); return NO_INIT; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("detachBuffer(P): slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { + ALOGE("detachBuffer(P): slot index %d out of range [0, %d)", + slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - BQ_LOGE("detachBuffer(P): slot %d is not owned by the producer " + } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { + ALOGE("detachBuffer(P): slot %d is not owned by the producer " "(state = %d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; } else if (!mSlots[slot].mRequestBufferCalled) { - BQ_LOGE("detachBuffer(P): buffer in slot %d has not been requested", + ALOGE("detachBuffer(P): buffer in slot %d has not been requested", slot); return BAD_VALUE; } @@ -413,15 +411,15 @@ status_t BufferQueueProducer::detachBuffer(int slot) { return NO_ERROR; } -status_t BufferQueueProducer::detachNextBuffer(sp* outBuffer, +status_t GonkBufferQueueProducer::detachNextBuffer(sp* outBuffer, sp* outFence) { ATRACE_CALL(); if (outBuffer == NULL) { - BQ_LOGE("detachNextBuffer: outBuffer must not be NULL"); + ALOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; } else if (outFence == NULL) { - BQ_LOGE("detachNextBuffer: outFence must not be NULL"); + ALOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } @@ -429,27 +427,27 @@ status_t BufferQueueProducer::detachNextBuffer(sp* outBuffer, mCore->waitWhileAllocatingLocked(); if (mCore->mIsAbandoned) { - BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned"); + ALOGE("detachNextBuffer: GonkBufferQueue has been abandoned"); return NO_INIT; } // Find the oldest valid slot - int found = BufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::FREE && + int found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; + for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == GonkBufferSlot::FREE && mSlots[s].mGraphicBuffer != NULL) { - if (found == BufferQueueCore::INVALID_BUFFER_SLOT || + if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { found = s; } } } - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { return NO_MEMORY; } - BQ_LOGV("detachNextBuffer detached slot %d", found); + ALOGV("detachNextBuffer detached slot %d", found); *outBuffer = mSlots[found].mGraphicBuffer; *outFence = mSlots[found].mFence; @@ -458,15 +456,15 @@ status_t BufferQueueProducer::detachNextBuffer(sp* outBuffer, return NO_ERROR; } -status_t BufferQueueProducer::attachBuffer(int* outSlot, +status_t GonkBufferQueueProducer::attachBuffer(int* outSlot, const sp& buffer) { ATRACE_CALL(); if (outSlot == NULL) { - BQ_LOGE("attachBuffer(P): outSlot must not be NULL"); + ALOGE("attachBuffer(P): outSlot must not be NULL"); return BAD_VALUE; } else if (buffer == NULL) { - BQ_LOGE("attachBuffer(P): cannot attach NULL buffer"); + ALOGE("attachBuffer(P): cannot attach NULL buffer"); return BAD_VALUE; } @@ -476,7 +474,7 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, status_t returnFlags = NO_ERROR; int found; // TODO: Should we provide an async flag to attachBuffer? It seems - // unlikely that buffers which we are attaching to a BufferQueue will + // unlikely that buffers which we are attaching to a GonkBufferQueue will // be asynchronous (droppable), but it may not be impossible. status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false, &found, &returnFlags); @@ -485,29 +483,27 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, } // This should not happen - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - BQ_LOGE("attachBuffer(P): no available buffer slots"); + if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { + ALOGE("attachBuffer(P): no available buffer slots"); return -EBUSY; } *outSlot = found; ATRACE_BUFFER_INDEX(*outSlot); - BQ_LOGV("attachBuffer(P): returning slot %d flags=%#x", + ALOGV("attachBuffer(P): returning slot %d flags=%#x", *outSlot, returnFlags); mSlots[*outSlot].mGraphicBuffer = buffer; - mSlots[*outSlot].mBufferState = BufferSlot::DEQUEUED; - mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR; + mSlots[*outSlot].mBufferState = GonkBufferSlot::DEQUEUED; mSlots[*outSlot].mFence = Fence::NO_FENCE; mSlots[*outSlot].mRequestBufferCalled = true; return returnFlags; } -status_t BufferQueueProducer::queueBuffer(int slot, +status_t GonkBufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) { ATRACE_CALL(); - ATRACE_BUFFER_INDEX(slot); int64_t timestamp; bool isAutoTimestamp; @@ -521,7 +517,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, &async, &fence, &stickyTransform); if (fence == NULL) { - BQ_LOGE("queueBuffer: fence is NULL"); + ALOGE("queueBuffer: fence is NULL"); // Temporary workaround for b/17946343: soldier-on instead of returning an error. This // prevents the client from dying, at the risk of visible corruption due to hwcomposer // reading the buffer before the producer is done rendering it. Unless the buffer is the @@ -537,7 +533,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: break; default: - BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode); + ALOGE("queueBuffer: unknown scaling mode %d", scalingMode); return BAD_VALUE; } @@ -546,7 +542,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("queueBuffer: BufferQueue has been abandoned"); + ALOGE("queueBuffer: GonkBufferQueue has been abandoned"); return NO_INIT; } @@ -556,48 +552,48 @@ status_t BufferQueueProducer::queueBuffer(int slot, // (which they shouldn't), so we do this extra test here to // handle that case. This is TEMPORARY until we get this fixed. if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - BQ_LOGE("queueBuffer: async mode is invalid with " + ALOGE("queueBuffer: async mode is invalid with " "buffer count override"); return BAD_VALUE; } } if (slot < 0 || slot >= maxBufferCount) { - BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", + ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, maxBufferCount); return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - BQ_LOGE("queueBuffer: slot %d is not owned by the producer " + } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { + ALOGE("queueBuffer: slot %d is not owned by the producer " "(state = %d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; } else if (!mSlots[slot].mRequestBufferCalled) { - BQ_LOGE("queueBuffer: slot %d was queued without requesting " + ALOGE("queueBuffer: slot %d was queued without requesting " "a buffer", slot); return BAD_VALUE; } - BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 + ALOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " crop=[%d,%d,%d,%d] transform=%#x scale=%s", slot, mCore->mFrameCounter + 1, timestamp, crop.left, crop.top, crop.right, crop.bottom, - transform, BufferItem::scalingModeName(scalingMode)); + transform, GonkBufferItem::scalingModeName(scalingMode)); const sp& graphicBuffer(mSlots[slot].mGraphicBuffer); Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); Rect croppedRect; crop.intersect(bufferRect, &croppedRect); if (croppedRect != crop) { - BQ_LOGE("queueBuffer: crop rect is not contained within the " + ALOGE("queueBuffer: crop rect is not contained within the " "buffer in slot %d", slot); return BAD_VALUE; } mSlots[slot].mFence = fence; - mSlots[slot].mBufferState = BufferSlot::QUEUED; + mSlots[slot].mBufferState = GonkBufferSlot::QUEUED; ++mCore->mFrameCounter; mSlots[slot].mFrameNumber = mCore->mFrameCounter; - BufferItem item; + GonkBufferItem item; item.mAcquireCalled = mSlots[slot].mAcquireCalled; item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; item.mCrop = crop; @@ -622,12 +618,12 @@ status_t BufferQueueProducer::queueBuffer(int slot, } else { // When the queue is not empty, we need to look at the front buffer // state to see if we need to replace it - BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); + GonkBufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); if (front->mIsDroppable) { // If the front queued buffer is still being tracked, we first // mark it as freed if (mCore->stillTracking(front)) { - mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + mSlots[front->mSlot].mBufferState = GonkBufferSlot::FREE; // Reset the frame number of the freed buffer so that it is // the first in line to be dequeued again mSlots[front->mSlot].mFrameNumber = 0; @@ -645,8 +641,6 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, mCore->mTransformHint, mCore->mQueue.size()); - - ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); } // Autolock scope // Call back without lock held @@ -657,46 +651,46 @@ status_t BufferQueueProducer::queueBuffer(int slot, return NO_ERROR; } -void BufferQueueProducer::cancelBuffer(int slot, const sp& fence) { +void GonkBufferQueueProducer::cancelBuffer(int slot, const sp& fence) { ATRACE_CALL(); - BQ_LOGV("cancelBuffer: slot %d", slot); + ALOGV("cancelBuffer: slot %d", slot); Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) { - BQ_LOGE("cancelBuffer: BufferQueue has been abandoned"); + ALOGE("cancelBuffer: GonkBufferQueue has been abandoned"); return; } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { + ALOGE("cancelBuffer: slot index %d out of range [0, %d)", + slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); return; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " + } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { + ALOGE("cancelBuffer: slot %d is not owned by the producer " "(state = %d)", slot, mSlots[slot].mBufferState); return; } else if (fence == NULL) { - BQ_LOGE("cancelBuffer: fence is NULL"); + ALOGE("cancelBuffer: fence is NULL"); return; } - mSlots[slot].mBufferState = BufferSlot::FREE; + mSlots[slot].mBufferState = GonkBufferSlot::FREE; mSlots[slot].mFrameNumber = 0; mSlots[slot].mFence = fence; mCore->mDequeueCondition.broadcast(); } -int BufferQueueProducer::query(int what, int *outValue) { +int GonkBufferQueueProducer::query(int what, int *outValue) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); if (outValue == NULL) { - BQ_LOGE("query: outValue was NULL"); + ALOGE("query: outValue was NULL"); return BAD_VALUE; } if (mCore->mIsAbandoned) { - BQ_LOGE("query: BufferQueue has been abandoned"); + ALOGE("query: GonkBufferQueue has been abandoned"); return NO_INIT; } @@ -727,37 +721,37 @@ int BufferQueueProducer::query(int what, int *outValue) { return BAD_VALUE; } - BQ_LOGV("query: %d? %d", what, value); + ALOGV("query: %d? %d", what, value); *outValue = value; return NO_ERROR; } -status_t BufferQueueProducer::connect(const sp& listener, +status_t GonkBufferQueueProducer::connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput *output) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); mConsumerName = mCore->mConsumerName; - BQ_LOGV("connect(P): api=%d producerControlledByApp=%s", api, + ALOGV("connect(P): api=%d producerControlledByApp=%s", api, producerControlledByApp ? "true" : "false"); if (mCore->mIsAbandoned) { - BQ_LOGE("connect(P): BufferQueue has been abandoned"); + ALOGE("connect(P): GonkBufferQueue has been abandoned"); return NO_INIT; } if (mCore->mConsumerListener == NULL) { - BQ_LOGE("connect(P): BufferQueue has no consumer"); + ALOGE("connect(P): GonkBufferQueue has no consumer"); return NO_INIT; } if (output == NULL) { - BQ_LOGE("connect(P): output was NULL"); + ALOGE("connect(P): output was NULL"); return BAD_VALUE; } - if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { - BQ_LOGE("connect(P): already connected (cur=%d req=%d)", - mCore->mConnectedApi, api); + if (mCore->mConnectedApi != GonkBufferQueueCore::NO_CONNECTED_API) { + ALOGE("connect(P): already connected (cur=%d req=%d)", mCore->mConnectedApi, + api); return BAD_VALUE; } @@ -778,14 +772,14 @@ status_t BufferQueueProducer::connect(const sp& listener, status = listener->asBinder()->linkToDeath( static_cast(this)); if (status != NO_ERROR) { - BQ_LOGE("connect(P): linkToDeath failed: %s (%d)", + ALOGE("connect(P): linkToDeath failed: %s (%d)", strerror(-status), status); } } mCore->mConnectedProducerListener = listener; break; default: - BQ_LOGE("connect(P): unknown API %d", api); + ALOGE("connect(P): unknown API %d", api); status = BAD_VALUE; break; } @@ -797,9 +791,9 @@ status_t BufferQueueProducer::connect(const sp& listener, return status; } -status_t BufferQueueProducer::disconnect(int api) { +status_t GonkBufferQueueProducer::disconnect(int api) { ATRACE_CALL(); - BQ_LOGV("disconnect(P): api %d", api); + ALOGV("disconnect(P): api %d", api); int status = NO_ERROR; sp listener; @@ -820,29 +814,18 @@ status_t BufferQueueProducer::disconnect(int api) { case NATIVE_WINDOW_API_CAMERA: if (mCore->mConnectedApi == api) { mCore->freeAllBuffersLocked(); - - // Remove our death notification callback if we have one - if (mCore->mConnectedProducerListener != NULL) { - sp token = - mCore->mConnectedProducerListener->asBinder(); - // This can fail if we're here because of the death - // notification, but we just ignore it - token->unlinkToDeath( - static_cast(this)); - } - mCore->mConnectedProducerListener = NULL; - mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; + mCore->mConnectedApi = GonkBufferQueueCore::NO_CONNECTED_API; mCore->mSidebandStream.clear(); mCore->mDequeueCondition.broadcast(); listener = mCore->mConsumerListener; } else { - BQ_LOGE("disconnect(P): connected to another API " + ALOGE("disconnect(P): connected to another API " "(cur=%d req=%d)", mCore->mConnectedApi, api); status = BAD_VALUE; } break; default: - BQ_LOGE("disconnect(P): unknown API %d", api); + ALOGE("disconnect(P): unknown API %d", api); status = BAD_VALUE; break; } @@ -856,121 +839,16 @@ status_t BufferQueueProducer::disconnect(int api) { return status; } -status_t BufferQueueProducer::setSidebandStream(const sp& stream) { - sp listener; - { // Autolock scope - Mutex::Autolock _l(mCore->mMutex); - mCore->mSidebandStream = stream; - listener = mCore->mConsumerListener; - } // Autolock scope - - if (listener != NULL) { - listener->onSidebandStreamChanged(); - } - return NO_ERROR; +status_t GonkBufferQueueProducer::setSidebandStream(const sp& stream) { + return INVALID_OPERATION; } -void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, +void GonkBufferQueueProducer::allocateBuffers(bool async, uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { - ATRACE_CALL(); - while (true) { - Vector freeSlots; - size_t newBufferCount = 0; - uint32_t allocWidth = 0; - uint32_t allocHeight = 0; - uint32_t allocFormat = 0; - uint32_t allocUsage = 0; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - int currentBufferCount = 0; - for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { - if (mSlots[slot].mGraphicBuffer != NULL) { - ++currentBufferCount; - } else { - if (mSlots[slot].mBufferState != BufferSlot::FREE) { - BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE", - slot); - continue; - } - - freeSlots.push_back(slot); - } - } - - int maxBufferCount = mCore->getMaxBufferCountLocked(async); - BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers", - currentBufferCount, maxBufferCount); - if (maxBufferCount <= currentBufferCount) - return; - newBufferCount = maxBufferCount - currentBufferCount; - if (freeSlots.size() < newBufferCount) { - BQ_LOGE("allocateBuffers: ran out of free slots"); - return; - } - allocWidth = width > 0 ? width : mCore->mDefaultWidth; - allocHeight = height > 0 ? height : mCore->mDefaultHeight; - allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; - allocUsage = usage | mCore->mConsumerUsageBits; - - mCore->mIsAllocating = true; - } // Autolock scope - - Vector > buffers; - for (size_t i = 0; i < newBufferCount; ++i) { - status_t result = NO_ERROR; - sp graphicBuffer(mCore->mAllocator->createGraphicBuffer( - allocWidth, allocHeight, allocFormat, allocUsage, &result)); - if (result != NO_ERROR) { - BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format" - " %u, usage %u)", width, height, format, usage); - Mutex::Autolock lock(mCore->mMutex); - mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.broadcast(); - return; - } - buffers.push_back(graphicBuffer); - } - - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; - uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; - uint32_t checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; - uint32_t checkUsage = usage | mCore->mConsumerUsageBits; - if (checkWidth != allocWidth || checkHeight != allocHeight || - checkFormat != allocFormat || checkUsage != allocUsage) { - // Something changed while we released the lock. Retry. - BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying."); - mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.broadcast(); - continue; - } - - for (size_t i = 0; i < newBufferCount; ++i) { - int slot = freeSlots[i]; - if (mSlots[slot].mBufferState != BufferSlot::FREE) { - // A consumer allocated the FREE slot with attachBuffer. Discard the buffer we - // allocated. - BQ_LOGV("allocateBuffers: slot %d was acquired while allocating. " - "Dropping allocated buffer.", slot); - continue; - } - mCore->freeBufferLocked(slot); // Clean up the slot first - mSlots[slot].mGraphicBuffer = buffers[i]; - mSlots[slot].mFrameNumber = 0; - mSlots[slot].mFence = Fence::NO_FENCE; - BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot); - } - - mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.broadcast(); - } // Autolock scope - } + ALOGE("allocateBuffers: no op"); } -void BufferQueueProducer::binderDied(const wp& /* who */) { +void GonkBufferQueueProducer::binderDied(const wp& /* who */) { // If we're here, it means that a producer we were connected to died. // We're guaranteed that we are still connected to it because we remove // this callback upon disconnect. It's therefore safe to read mConnectedApi diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h index 3fc5de2dd1ee..ef3b70a413b6 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +15,23 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERQUEUEPRODUCER_H -#define ANDROID_GUI_BUFFERQUEUEPRODUCER_H +#ifndef NATIVEWINDOW_GONKBUFFERQUEUEPRODUCER_LL_H +#define NATIVEWINDOW_GONKBUFFERQUEUEPRODUCER_LL_H -#include +#include "GonkBufferQueueDefs.h" #include namespace android { -class BufferSlot; +class GonkBufferSlot; -class BufferQueueProducer : public BnGraphicBufferProducer, +class GonkBufferQueueProducer : public BnGraphicBufferProducer, private IBinder::DeathRecipient { public: - friend class BufferQueue; // Needed to access binderDied + friend class GonkBufferQueue; // Needed to access binderDied - BufferQueueProducer(const sp& core); - virtual ~BufferQueueProducer(); + GonkBufferQueueProducer(const sp& core); + virtual ~GonkBufferQueueProducer(); // requestBuffer returns the GraphicBuffer for slot N. // @@ -41,7 +42,7 @@ public: // setBufferCount updates the number of available buffer slots. If this // method succeeds, buffer slots will be both unallocated and owned by - // the BufferQueue object (i.e. they are not owned by the producer or + // the GonkBufferQueue object (i.e. they are not owned by the producer or // consumer). // // This will fail if the producer has dequeued any buffers, or if @@ -106,7 +107,7 @@ public: // See IGraphicBufferProducer::attachBuffer virtual status_t attachBuffer(int* outSlot, const sp& buffer); - // queueBuffer returns a filled buffer to the BufferQueue. + // queueBuffer returns a filled buffer to the GonkBufferQueue. // // Additional data is provided in the QueueBufferInput struct. Notably, // a timestamp must be provided for the buffer. The timestamp is in @@ -124,7 +125,7 @@ public: virtual status_t queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* output); - // cancelBuffer returns a dequeued buffer to the BufferQueue, but doesn't + // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't // queue it for use by the consumer. // // The buffer will not be overwritten until the fence signals. The fence @@ -135,25 +136,25 @@ public: // window.h (e.g. NATIVE_WINDOW_FORMAT). virtual int query(int what, int* outValue); - // connect attempts to connect a producer API to the BufferQueue. This + // connect attempts to connect a producer API to the GonkBufferQueue. This // must be called before any other IGraphicBufferProducer methods are // called except for getAllocator. A consumer must already be connected. // // This method will fail if connect was previously called on the - // BufferQueue and no corresponding disconnect call was made (i.e. if + // GonkBufferQueue and no corresponding disconnect call was made (i.e. if // it's still connected to a producer). // // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). virtual status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output); - // disconnect attempts to disconnect a producer API from the BufferQueue. + // disconnect attempts to disconnect a producer API from the GonkBufferQueue. // Calling this method will cause any subsequent calls to other // IGraphicBufferProducer methods to fail except for getAllocator and connect. // Successfully calling connect after this will allow the other methods to // succeed again. // - // This method will fail if the the BufferQueue is not currently + // This method will fail if the the GonkBufferQueue is not currently // connected to the specified producer API. virtual status_t disconnect(int api); @@ -181,23 +182,23 @@ private: // block if there are no available slots and we are not in non-blocking // mode (producer and consumer controlled by the application). If it blocks, // it will release mCore->mMutex while blocked so that other operations on - // the BufferQueue may succeed. + // the GonkBufferQueue may succeed. status_t waitForFreeSlotThenRelock(const char* caller, bool async, int* found, status_t* returnFlags) const; - sp mCore; + sp mCore; // This references mCore->mSlots. Lock mCore->mMutex while accessing. - BufferQueueDefs::SlotsType& mSlots; + GonkBufferQueueDefs::SlotsType& mSlots; - // This is a cached copy of the name stored in the BufferQueueCore. + // This is a cached copy of the name stored in the GonkBufferQueueCore. // It's updated during connect and dequeueBuffer (which should catch // most updates). String8 mConsumerName; uint32_t mStickyTransform; -}; // class BufferQueueProducer +}; // class GonkBufferQueueProducer } // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp index b8877fef617f..9e4a424a939c 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,16 +15,16 @@ * limitations under the License. */ -#include +#include "GonkBufferSlot.h" namespace android { -const char* BufferSlot::bufferStateName(BufferState state) { +const char* GonkBufferSlot::bufferStateName(BufferState state) { switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; + case GonkBufferSlot::DEQUEUED: return "DEQUEUED"; + case GonkBufferSlot::QUEUED: return "QUEUED"; + case GonkBufferSlot::FREE: return "FREE"; + case GonkBufferSlot::ACQUIRED: return "ACQUIRED"; default: return "Unknown"; } } diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h index 6085e116a3d6..164708851d4a 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h @@ -1,5 +1,6 @@ /* * Copyright 2014 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,29 +15,27 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERSLOT_H -#define ANDROID_GUI_BUFFERSLOT_H +#ifndef NATIVEWINDOW_GONKBUFFERSLOT_LL_H +#define NATIVEWINDOW_GONKBUFFERSLOT_LL_H #include #include -#include -#include - #include +#include "mozilla/layers/TextureClient.h" + namespace android { class Fence; -struct BufferSlot { +struct GonkBufferSlot { + typedef mozilla::layers::TextureClient TextureClient; - BufferSlot() - : mEglDisplay(EGL_NO_DISPLAY), - mBufferState(BufferSlot::FREE), + GonkBufferSlot() + : mBufferState(GonkBufferSlot::FREE), mRequestBufferCalled(false), mFrameNumber(0), - mEglFence(EGL_NO_SYNC_KHR), mAcquireCalled(false), mNeedsCleanupOnRelease(false), mAttachedByConsumer(false) { @@ -46,9 +45,6 @@ struct BufferSlot { // if no buffer has been allocated. sp mGraphicBuffer; - // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects. - EGLDisplay mEglDisplay; - // BufferState represents the different states in which a buffer slot // can be. All slots are initially FREE. enum BufferState { @@ -105,13 +101,6 @@ struct BufferSlot { // may be released before their release fence is signaled). uint64_t mFrameNumber; - // mEglFence is the EGL sync object that must signal before the buffer - // associated with this buffer slot may be dequeued. It is initialized - // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a - // new sync object in releaseBuffer. (This is deprecated in favor of - // mFence, below.) - EGLSyncKHR mEglFence; - // mFence is a fence which will signal when work initiated by the // previous owner of the buffer is finished. When the buffer is FREE, // the fence indicates when the consumer has finished reading @@ -135,6 +124,9 @@ struct BufferSlot { // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued // to prevent the producer from using a stale cached buffer. bool mAttachedByConsumer; + + // mTextureClient is a thin abstraction over remotely allocated GraphicBuffer. + mozilla::RefPtr mTextureClient; }; } // namespace android diff --git a/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp b/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp index f19b6c7737df..8444665354a8 100644 --- a/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp +++ b/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,34 +17,20 @@ #include -#define LOG_TAG "ConsumerBase" +#define LOG_TAG "GonkConsumerBase" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #define EGL_EGLEXT_PROTOTYPES -#include -#include - #include #include -#include -#include -#include - -#include #include #include -#include -// Macros for including the ConsumerBase name in log messages -#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#include "GonkConsumerBaseLL.h" namespace android { @@ -53,7 +40,7 @@ static int32_t createProcessUniqueId() { return android_atomic_inc(&globalCounter); } -ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : +GonkConsumerBase::GonkConsumerBase(const sp& bufferQueue, bool controlledByApp) : mAbandoned(false), mConsumer(bufferQueue) { // Choose a name using the PID and a process-unique ID. @@ -64,42 +51,42 @@ ConsumerBase::ConsumerBase(const sp& bufferQueue, bool c // dropping to 0 at the end of the ctor. Since all we need is a wp<...> // that's what we create. wp listener = static_cast(this); - sp proxy = new BufferQueue::ProxyConsumerListener(listener); + sp proxy = new GonkBufferQueue::ProxyConsumerListener(listener); status_t err = mConsumer->consumerConnect(proxy, controlledByApp); if (err != NO_ERROR) { - CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", + ALOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", strerror(-err), err); } else { mConsumer->setConsumerName(mName); } } -ConsumerBase::~ConsumerBase() { - CB_LOGV("~ConsumerBase"); +GonkConsumerBase::~GonkConsumerBase() { + ALOGV("~GonkConsumerBase"); Mutex::Autolock lock(mMutex); // Verify that abandon() has been called before we get here. This should - // be done by ConsumerBase::onLastStrongRef(), but it's possible for a + // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a // derived class to override that method and not call - // ConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the " + // GonkConsumerBase::onLastStrongRef(). + LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " "consumer is not abandoned!", mName.string()); } -void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { +void GonkConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { abandon(); } -void ConsumerBase::freeBufferLocked(int slotIndex) { - CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); +void GonkConsumerBase::freeBufferLocked(int slotIndex) { + ALOGV("freeBufferLocked: slotIndex=%d", slotIndex); mSlots[slotIndex].mGraphicBuffer = 0; mSlots[slotIndex].mFence = Fence::NO_FENCE; mSlots[slotIndex].mFrameNumber = 0; } -void ConsumerBase::onFrameAvailable() { - CB_LOGV("onFrameAvailable"); +void GonkConsumerBase::onFrameAvailable() { + ALOGV("onFrameAvailable"); sp listener; { // scope for the lock @@ -108,15 +95,15 @@ void ConsumerBase::onFrameAvailable() { } if (listener != NULL) { - CB_LOGV("actually calling onFrameAvailable"); + ALOGV("actually calling onFrameAvailable"); listener->onFrameAvailable(); } } -void ConsumerBase::onBuffersReleased() { +void GonkConsumerBase::onBuffersReleased() { Mutex::Autolock lock(mMutex); - CB_LOGV("onBuffersReleased"); + ALOGV("onBuffersReleased"); if (mAbandoned) { // Nothing to do if we're already abandoned. @@ -125,18 +112,18 @@ void ConsumerBase::onBuffersReleased() { uint64_t mask = 0; mConsumer->getReleasedBuffers(&mask); - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { if (mask & (1ULL << i)) { freeBufferLocked(i); } } } -void ConsumerBase::onSidebandStreamChanged() { +void GonkConsumerBase::onSidebandStreamChanged() { } -void ConsumerBase::abandon() { - CB_LOGV("abandon"); +void GonkConsumerBase::abandon() { + ALOGV("abandon"); Mutex::Autolock lock(mMutex); if (!mAbandoned) { @@ -145,9 +132,9 @@ void ConsumerBase::abandon() { } } -void ConsumerBase::abandonLocked() { - CB_LOGV("abandonLocked"); - for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { +void GonkConsumerBase::abandonLocked() { + ALOGV("abandonLocked"); + for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); } // disconnect from the BufferQueue @@ -155,23 +142,23 @@ void ConsumerBase::abandonLocked() { mConsumer.clear(); } -void ConsumerBase::setFrameAvailableListener( +void GonkConsumerBase::setFrameAvailableListener( const wp& listener) { - CB_LOGV("setFrameAvailableListener"); + ALOGV("setFrameAvailableListener"); Mutex::Autolock lock(mMutex); mFrameAvailableListener = listener; } -void ConsumerBase::dump(String8& result) const { +void GonkConsumerBase::dump(String8& result) const { dump(result, ""); } -void ConsumerBase::dump(String8& result, const char* prefix) const { +void GonkConsumerBase::dump(String8& result, const char* prefix) const { Mutex::Autolock _l(mMutex); dumpLocked(result, prefix); } -void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { +void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const { result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); if (!mAbandoned) { @@ -179,7 +166,7 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { } } -status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item, +status_t GonkConsumerBase::acquireBufferLocked(GonkBufferQueue::BufferItem *item, nsecs_t presentWhen) { status_t err = mConsumer->acquireBuffer(item, presentWhen); if (err != NO_ERROR) { @@ -193,21 +180,21 @@ status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item, mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; mSlots[item->mBuf].mFence = item->mFence; - CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, + ALOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, item->mBuf, item->mFrameNumber); return OK; } -status_t ConsumerBase::addReleaseFence(int slot, +status_t GonkConsumerBase::addReleaseFence(int slot, const sp graphicBuffer, const sp& fence) { Mutex::Autolock lock(mMutex); return addReleaseFenceLocked(slot, graphicBuffer, fence); } -status_t ConsumerBase::addReleaseFenceLocked(int slot, +status_t GonkConsumerBase::addReleaseFenceLocked(int slot, const sp graphicBuffer, const sp& fence) { - CB_LOGV("addReleaseFenceLocked: slot=%d", slot); + ALOGV("addReleaseFenceLocked: slot=%d", slot); // If consumer no longer tracks this graphicBuffer, we can safely // drop this fence, as it will never be received by the producer. @@ -222,7 +209,7 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, String8::format("%.28s:%d", mName.string(), slot), mSlots[slot].mFence, fence); if (!mergedFence.get()) { - CB_LOGE("failed to merge release fences"); + ALOGE("failed to merge release fences"); // synchronization is broken, the best we can do is hope fences // signal in order so the new fence will act like a union mSlots[slot].mFence = fence; @@ -234,9 +221,7 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, return OK; } -status_t ConsumerBase::releaseBufferLocked( - int slot, const sp graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence) { +status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp graphicBuffer) { // If consumer no longer tracks this graphicBuffer (we received a new // buffer on the same slot), the buffer producer is definitely no longer // tracking it. @@ -244,11 +229,10 @@ status_t ConsumerBase::releaseBufferLocked( return OK; } - CB_LOGV("releaseBufferLocked: slot=%d/%" PRIu64, + ALOGV("releaseBufferLocked: slot=%d/%" PRIu64, slot, mSlots[slot].mFrameNumber); - status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, - display, eglFence, mSlots[slot].mFence); - if (err == IGraphicBufferConsumer::STALE_BUFFER_SLOT) { + status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); + if (err == IGonkGraphicBufferConsumer::STALE_BUFFER_SLOT) { freeBufferLocked(slot); } @@ -257,9 +241,9 @@ status_t ConsumerBase::releaseBufferLocked( return err; } -bool ConsumerBase::stillTracking(int slot, +bool GonkConsumerBase::stillTracking(int slot, const sp graphicBuffer) { - if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { + if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) { return false; } return (mSlots[slot].mGraphicBuffer != NULL && diff --git a/widget/gonk/nativewindow/GonkConsumerBaseLL.h b/widget/gonk/nativewindow/GonkConsumerBaseLL.h index 100bb260f918..ba7b6c33badd 100644 --- a/widget/gonk/nativewindow/GonkConsumerBaseLL.h +++ b/widget/gonk/nativewindow/GonkConsumerBaseLL.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +15,8 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_CONSUMERBASE_H -#define ANDROID_GUI_CONSUMERBASE_H - -#include +#ifndef NATIVEWINDOW_GONKCONSUMERBASE_LL_H +#define NATIVEWINDOW_GONKCONSUMERBASE_LL_H #include @@ -26,15 +25,17 @@ #include #include +#include "GonkBufferQueueLL.h" + namespace android { // ---------------------------------------------------------------------------- class String8; -// ConsumerBase is a base class for BufferQueue consumer end-points. It -// handles common tasks like management of the connection to the BufferQueue +// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It +// handles common tasks like management of the connection to the GonkBufferQueue // and the buffer pool. -class ConsumerBase : public virtual RefBase, +class GonkConsumerBase : public virtual RefBase, protected ConsumerListener { public: struct FrameAvailableListener : public virtual RefBase { @@ -49,20 +50,20 @@ public: virtual void onFrameAvailable() = 0; }; - virtual ~ConsumerBase(); + virtual ~GonkConsumerBase(); - // abandon frees all the buffers and puts the ConsumerBase into the - // 'abandoned' state. Once put in this state the ConsumerBase can never + // abandon frees all the buffers and puts the GonkConsumerBase into the + // 'abandoned' state. Once put in this state the GonkConsumerBase can never // leave it. When in the 'abandoned' state, all methods of the // IGraphicBufferProducer interface will fail with the NO_INIT error. // // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the ConsumerBase, if there are additional + // from the perspective of the the GonkConsumerBase, if there are additional // references on the buffers (e.g. if a buffer is referenced by a client // or by OpenGL ES as a texture) then those buffer will remain allocated. void abandon(); - // set the name of the ConsumerBase that will be used to identify it in + // set the name of the GonkConsumerBase that will be used to identify it in // log messages. void setName(const String8& name); @@ -77,34 +78,34 @@ public: void setFrameAvailableListener(const wp& listener); private: - ConsumerBase(const ConsumerBase&); - void operator=(const ConsumerBase&); + GonkConsumerBase(const GonkConsumerBase&); + void operator=(const GonkConsumerBase&); protected: - // ConsumerBase constructs a new ConsumerBase object to consume image - // buffers from the given IGraphicBufferConsumer. + // GonkConsumerBase constructs a new GonkConsumerBase object to consume image + // buffers from the given IGonkGraphicBufferConsumer. // The controlledByApp flag indicates that this consumer is under the application's // control. - ConsumerBase(const sp& consumer, bool controlledByApp = false); + GonkConsumerBase(const sp& consumer, bool controlledByApp = false); // onLastStrongRef gets called by RefBase just before the dtor of the most - // derived class. It is used to clean up the buffers so that ConsumerBase + // derived class. It is used to clean up the buffers so that GonkConsumerBase // can coordinate the clean-up by calling into virtual methods implemented // by the derived classes. This would not be possible from the // ConsuemrBase dtor because by the time that gets called the derived // classes have already been destructed. // // This methods should not need to be overridden by derived classes, but - // if they are overridden the ConsumerBase implementation must be called + // if they are overridden the GonkConsumerBase implementation must be called // from the derived class. virtual void onLastStrongRef(const void* id); // Implementation of the IConsumerListener interface. These - // calls are used to notify the ConsumerBase of asynchronous events in the - // BufferQueue. The onFrameAvailable and onBuffersReleased methods should + // calls are used to notify the GonkConsumerBase of asynchronous events in the + // GonkBufferQueue. The onFrameAvailable and onBuffersReleased methods should // not need to be overridden by derived classes, but if they are overridden - // the ConsumerBase implementation must be called from the derived class. - // The ConsumerBase version of onSidebandStreamChanged does nothing and can + // the GonkConsumerBase implementation must be called from the derived class. + // The GonkConsumerBase version of onSidebandStreamChanged does nothing and can // be overriden by derived classes if they want the notification. virtual void onFrameAvailable(); virtual void onBuffersReleased(); @@ -116,24 +117,24 @@ protected: // // Derived classes should override this method to clean up any state they // keep per slot. If it is overridden, the derived class's implementation - // must call ConsumerBase::freeBufferLocked. + // must call GonkConsumerBase::freeBufferLocked. // // This method must be called with mMutex locked. virtual void freeBufferLocked(int slotIndex); - // abandonLocked puts the BufferQueue into the abandoned state, causing + // abandonLocked puts the GonkBufferQueue into the abandoned state, causing // all future operations on it to fail. This method rather than the public // abandon method should be overridden by child classes to add abandon- // time behavior. // // Derived classes should override this method to clean up any object // state they keep (as opposed to per-slot state). If it is overridden, - // the derived class's implementation must call ConsumerBase::abandonLocked. + // the derived class's implementation must call GonkConsumerBase::abandonLocked. // // This method must be called with mMutex locked. virtual void abandonLocked(); - // dumpLocked dumps the current state of the ConsumerBase object to the + // dumpLocked dumps the current state of the GonkConsumerBase object to the // result string. Each line is prefixed with the string pointed to by the // prefix argument. The buffer argument points to a buffer that may be // used for intermediate formatting data, and the size of that buffer is @@ -141,31 +142,29 @@ protected: // // Derived classes should override this method to dump their internal // state. If this method is overridden the derived class's implementation - // should call ConsumerBase::dumpLocked. + // should call GonkConsumerBase::dumpLocked. // // This method must be called with mMutex locked. virtual void dumpLocked(String8& result, const char* prefix) const; - // acquireBufferLocked fetches the next buffer from the BufferQueue and + // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and // updates the buffer slot for the buffer returned. // // Derived classes should override this method to perform any // initialization that must take place the first time a buffer is assigned // to a slot. If it is overridden the derived class's implementation must - // call ConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(IGraphicBufferConsumer::BufferItem *item, + // call GonkConsumerBase::acquireBufferLocked. + virtual status_t acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, nsecs_t presentWhen); // releaseBufferLocked relinquishes control over a buffer, returning that - // control to the BufferQueue. + // control to the GonkBufferQueue. // // Derived classes should override this method to perform any cleanup that - // must take place when a buffer is released back to the BufferQueue. If + // must take place when a buffer is released back to the GonkBufferQueue. If // it is overridden the derived class's implementation must call - // ConsumerBase::releaseBufferLocked.e - virtual status_t releaseBufferLocked(int slot, - const sp graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence); + // GonkConsumerBase::releaseBufferLocked. + virtual status_t releaseBufferLocked(int slot, const sp graphicBuffer); // returns true iff the slot still has the graphicBuffer in it. bool stillTracking(int slot, const sp graphicBuffer); @@ -181,7 +180,7 @@ protected: const sp graphicBuffer, const sp& fence); // Slot contains the information and object references that - // ConsumerBase maintains about a BufferQueue buffer slot. + // GonkConsumerBase maintains about a GonkBufferQueue buffer slot. struct Slot { // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if // no Gralloc buffer is in the slot. @@ -197,23 +196,23 @@ protected: uint64_t mFrameNumber; }; - // mSlots stores the buffers that have been allocated by the BufferQueue + // mSlots stores the buffers that have been allocated by the GonkBufferQueue // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of BufferQueue::acquire when the + // filled in with the result of GonkBufferQueue::acquire when the // client dequeues a buffer from a // slot that has not yet been used. The buffer allocated to a slot will also // be replaced if the requested buffer usage or geometry differs from that // of the buffer allocated to a slot. - Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS]; + Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS]; - // mAbandoned indicates that the BufferQueue will no longer be used to + // mAbandoned indicates that the GonkBufferQueue will no longer be used to // consume images buffers pushed to it using the IGraphicBufferProducer // interface. It is initialized to false, and set to true in the abandon - // method. A BufferQueue that has been abandoned will return the NO_INIT + // method. A GonkBufferQueue that has been abandoned will return the NO_INIT // error from all IConsumerBase methods capable of returning an error. bool mAbandoned; - // mName is a string used to identify the ConsumerBase in log messages. + // mName is a string used to identify the GonkConsumerBase in log messages. // It can be set by the setName method. String8 mName; @@ -222,12 +221,12 @@ protected: // queueBuffer. wp mFrameAvailableListener; - // The ConsumerBase has-a BufferQueue and is responsible for creating this object + // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object // if none is supplied - sp mConsumer; + sp mConsumer; // mMutex is the mutex used to prevent concurrent access to the member - // variables of ConsumerBase objects. It must be locked whenever the + // variables of GonkConsumerBase objects. It must be locked whenever the // member variables are accessed or when any of the *Locked methods are // called. // @@ -238,4 +237,4 @@ protected: // ---------------------------------------------------------------------------- }; // namespace android -#endif // ANDROID_GUI_CONSUMERBASE_H +#endif // NATIVEWINDOW_GONKCONSUMERBASE_LL_H diff --git a/widget/gonk/nativewindow/GonkNativeWindow.h b/widget/gonk/nativewindow/GonkNativeWindow.h index dfe6a154b998..ed04b9f0dc36 100644 --- a/widget/gonk/nativewindow/GonkNativeWindow.h +++ b/widget/gonk/nativewindow/GonkNativeWindow.h @@ -13,7 +13,9 @@ * limitations under the License. */ -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 +# include "GonkNativeWindowLL.h" +#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 # include "GonkNativeWindowKK.h" #elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 # include "GonkNativeWindowJB.h" diff --git a/widget/gonk/nativewindow/GonkNativeWindowClient.h b/widget/gonk/nativewindow/GonkNativeWindowClient.h index 3b0c8d7261c2..90ca0561dfa6 100644 --- a/widget/gonk/nativewindow/GonkNativeWindowClient.h +++ b/widget/gonk/nativewindow/GonkNativeWindowClient.h @@ -13,9 +13,11 @@ * limitations under the License. */ -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 +# include "GonkNativeWindowClientLL.h" +#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 # include "GonkNativeWindowClientKK.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 +#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 # include "GonkNativeWindowClientJB.h" #elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION == 15 # include "GonkNativeWindowClientICS.h" diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp index 0e2baa28fd4d..4f6fbd50da3d 100644 --- a/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp +++ b/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +15,7 @@ * limitations under the License. */ -#define LOG_TAG "Surface" +#define LOG_TAG "GonkNativeWindowClient" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 @@ -29,16 +30,11 @@ #include #include -#include -#include -#include -#include - -#include +#include "GonkNativeWindowClientLL.h" namespace android { -Surface::Surface( +GonkNativeWindowClient::GonkNativeWindowClient( const sp& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer) @@ -79,53 +75,53 @@ Surface::Surface( mSwapIntervalZero = false; } -Surface::~Surface() { +GonkNativeWindowClient::~GonkNativeWindowClient() { if (mConnectedToCpu) { - Surface::disconnect(NATIVE_WINDOW_API_CPU); + GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU); } } -sp Surface::getIGraphicBufferProducer() const { +sp GonkNativeWindowClient::getIGraphicBufferProducer() const { return mGraphicBufferProducer; } -void Surface::setSidebandStream(const sp& stream) { +void GonkNativeWindowClient::setSidebandStream(const sp& stream) { mGraphicBufferProducer->setSidebandStream(stream); } -void Surface::allocateBuffers() { +void GonkNativeWindowClient::allocateBuffers() { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, mReqWidth, mReqHeight, mReqFormat, mReqUsage); } -int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { - Surface* c = getSelf(window); +int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) { + GonkNativeWindowClient* c = getSelf(window); return c->setSwapInterval(interval); } -int Surface::hook_dequeueBuffer(ANativeWindow* window, +int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) { - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); return c->dequeueBuffer(buffer, fenceFd); } -int Surface::hook_cancelBuffer(ANativeWindow* window, +int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); return c->cancelBuffer(buffer, fenceFd); } -int Surface::hook_queueBuffer(ANativeWindow* window, +int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); return c->queueBuffer(buffer, fenceFd); } -int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, +int GonkNativeWindowClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); ANativeWindowBuffer* buf; int fenceFd = -1; int result = c->dequeueBuffer(&buf, &fenceFd); @@ -141,38 +137,38 @@ int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, return result; } -int Surface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, +int GonkNativeWindowClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); return c->cancelBuffer(buffer, -1); } -int Surface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, +int GonkNativeWindowClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); return c->lockBuffer_DEPRECATED(buffer); } -int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, +int GonkNativeWindowClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); return c->queueBuffer(buffer, -1); } -int Surface::hook_query(const ANativeWindow* window, +int GonkNativeWindowClient::hook_query(const ANativeWindow* window, int what, int* value) { - const Surface* c = getSelf(window); + const GonkNativeWindowClient* c = getSelf(window); return c->query(what, value); } -int Surface::hook_perform(ANativeWindow* window, int operation, ...) { +int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) { va_list args; va_start(args, operation); - Surface* c = getSelf(window); + GonkNativeWindowClient* c = getSelf(window); return c->perform(operation, args); } -int Surface::setSwapInterval(int interval) { +int GonkNativeWindowClient::setSwapInterval(int interval) { ATRACE_CALL(); // EGL specification states: // interval is silently clamped to minimum and maximum implementation @@ -184,14 +180,12 @@ int Surface::setSwapInterval(int interval) { if (interval > maxSwapInterval) interval = maxSwapInterval; - mSwapIntervalZero = (interval == 0); - return NO_ERROR; } -int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { +int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ATRACE_CALL(); - ALOGV("Surface::dequeueBuffer"); + ALOGV("GonkNativeWindowClient::dequeueBuffer"); int reqW; int reqH; @@ -208,7 +202,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { swapIntervalZero = mSwapIntervalZero; reqFormat = mReqFormat; reqUsage = mReqUsage; - } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer + } // Drop the lock so that we can still touch the GonkNativeWindowClient while blocking in IGBP::dequeueBuffer int buf = -1; sp fence; @@ -227,7 +221,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { sp& gbuf(mSlots[buf].buffer); // this should never happen - ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); + ALOGE_IF(fence == NULL, "GonkNativeWindowClient::dequeueBuffer: received null Fence! buf=%d", buf); if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { freeAllBuffers(); @@ -258,10 +252,10 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { return OK; } -int Surface::cancelBuffer(android_native_buffer_t* buffer, +int GonkNativeWindowClient::cancelBuffer(android_native_buffer_t* buffer, int fenceFd) { ATRACE_CALL(); - ALOGV("Surface::cancelBuffer"); + ALOGV("GonkNativeWindowClient::cancelBuffer"); Mutex::Autolock lock(mMutex); int i = getSlotFromBufferLocked(buffer); if (i < 0) { @@ -272,7 +266,7 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, return OK; } -int Surface::getSlotFromBufferLocked( +int GonkNativeWindowClient::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { bool dumpedState = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { @@ -285,22 +279,22 @@ int Surface::getSlotFromBufferLocked( return BAD_VALUE; } -int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer __attribute__((unused))) { - ALOGV("Surface::lockBuffer"); +int GonkNativeWindowClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer __attribute__((unused))) { + ALOGV("GonkNativeWindowClient::lockBuffer"); Mutex::Autolock lock(mMutex); return OK; } -int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { +int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { ATRACE_CALL(); - ALOGV("Surface::queueBuffer"); + ALOGV("GonkNativeWindowClient::queueBuffer"); Mutex::Autolock lock(mMutex); int64_t timestamp; bool isAutoTimestamp = false; if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { timestamp = systemTime(SYSTEM_TIME_MONOTONIC); isAutoTimestamp = true; - ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", + ALOGV("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms", timestamp / 1000000.f); } else { timestamp = mTimestamp; @@ -339,9 +333,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { return err; } -int Surface::query(int what, int* value) const { +int GonkNativeWindowClient::query(int what, int* value) const { ATRACE_CALL(); - ALOGV("Surface::query"); + ALOGV("GonkNativeWindowClient::query"); { // scope for the lock Mutex::Autolock lock(mMutex); switch (what) { @@ -352,13 +346,7 @@ int Surface::query(int what, int* value) const { } break; case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { - sp composer( - ComposerService::getComposerService()); - if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) { - *value = 1; - } else { *value = 0; - } return NO_ERROR; } case NATIVE_WINDOW_CONCRETE_TYPE: @@ -390,7 +378,7 @@ int Surface::query(int what, int* value) const { return mGraphicBufferProducer->query(what, value); } -int Surface::perform(int operation, va_list args) +int GonkNativeWindowClient::perform(int operation, va_list args) { int res = NO_ERROR; switch (operation) { @@ -455,32 +443,32 @@ int Surface::perform(int operation, va_list args) return res; } -int Surface::dispatchConnect(va_list args) { +int GonkNativeWindowClient::dispatchConnect(va_list args) { int api = va_arg(args, int); return connect(api); } -int Surface::dispatchDisconnect(va_list args) { +int GonkNativeWindowClient::dispatchDisconnect(va_list args) { int api = va_arg(args, int); return disconnect(api); } -int Surface::dispatchSetUsage(va_list args) { +int GonkNativeWindowClient::dispatchSetUsage(va_list args) { int usage = va_arg(args, int); return setUsage(usage); } -int Surface::dispatchSetCrop(va_list args) { +int GonkNativeWindowClient::dispatchSetCrop(va_list args) { android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); return setCrop(reinterpret_cast(rect)); } -int Surface::dispatchSetBufferCount(va_list args) { +int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) { size_t bufferCount = va_arg(args, size_t); return setBufferCount(bufferCount); } -int Surface::dispatchSetBuffersGeometry(va_list args) { +int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) { int w = va_arg(args, int); int h = va_arg(args, int); int f = va_arg(args, int); @@ -491,67 +479,67 @@ int Surface::dispatchSetBuffersGeometry(va_list args) { return setBuffersFormat(f); } -int Surface::dispatchSetBuffersDimensions(va_list args) { +int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) { int w = va_arg(args, int); int h = va_arg(args, int); return setBuffersDimensions(w, h); } -int Surface::dispatchSetBuffersUserDimensions(va_list args) { +int GonkNativeWindowClient::dispatchSetBuffersUserDimensions(va_list args) { int w = va_arg(args, int); int h = va_arg(args, int); return setBuffersUserDimensions(w, h); } -int Surface::dispatchSetBuffersFormat(va_list args) { +int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) { int f = va_arg(args, int); return setBuffersFormat(f); } -int Surface::dispatchSetScalingMode(va_list args) { +int GonkNativeWindowClient::dispatchSetScalingMode(va_list args) { int m = va_arg(args, int); return setScalingMode(m); } -int Surface::dispatchSetBuffersTransform(va_list args) { +int GonkNativeWindowClient::dispatchSetBuffersTransform(va_list args) { int transform = va_arg(args, int); return setBuffersTransform(transform); } -int Surface::dispatchSetBuffersStickyTransform(va_list args) { +int GonkNativeWindowClient::dispatchSetBuffersStickyTransform(va_list args) { int transform = va_arg(args, int); return setBuffersStickyTransform(transform); } -int Surface::dispatchSetBuffersTimestamp(va_list args) { +int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) { int64_t timestamp = va_arg(args, int64_t); return setBuffersTimestamp(timestamp); } -int Surface::dispatchLock(va_list args) { +int GonkNativeWindowClient::dispatchLock(va_list args) { ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); ARect* inOutDirtyBounds = va_arg(args, ARect*); return lock(outBuffer, inOutDirtyBounds); } -int Surface::dispatchUnlockAndPost(va_list args __attribute__((unused))) { +int GonkNativeWindowClient::dispatchUnlockAndPost(va_list args __attribute__((unused))) { return unlockAndPost(); } -int Surface::dispatchSetSidebandStream(va_list args) { +int GonkNativeWindowClient::dispatchSetSidebandStream(va_list args) { native_handle_t* sH = va_arg(args, native_handle_t*); sp sidebandHandle = NativeHandle::create(sH, false); setSidebandStream(sidebandHandle); return OK; } -int Surface::connect(int api) { +int GonkNativeWindowClient::connect(int api) { ATRACE_CALL(); - ALOGV("Surface::connect"); + ALOGV("GonkNativeWindowClient::connect"); static sp listener = new DummyProducerListener(); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; - int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); + int err = mGraphicBufferProducer->connect(listener, api, true, &output); if (err == NO_ERROR) { uint32_t numPendingBuffers = 0; uint32_t hint = 0; @@ -572,9 +560,9 @@ int Surface::connect(int api) { } -int Surface::disconnect(int api) { +int GonkNativeWindowClient::disconnect(int api) { ATRACE_CALL(); - ALOGV("Surface::disconnect"); + ALOGV("GonkNativeWindowClient::disconnect"); Mutex::Autolock lock(mMutex); freeAllBuffers(); int err = mGraphicBufferProducer->disconnect(api); @@ -595,15 +583,15 @@ int Surface::disconnect(int api) { return err; } -int Surface::setUsage(uint32_t reqUsage) +int GonkNativeWindowClient::setUsage(uint32_t reqUsage) { - ALOGV("Surface::setUsage"); + ALOGV("GonkNativeWindowClient::setUsage"); Mutex::Autolock lock(mMutex); mReqUsage = reqUsage; return OK; } -int Surface::setCrop(Rect const* rect) +int GonkNativeWindowClient::setCrop(Rect const* rect) { ATRACE_CALL(); @@ -614,7 +602,7 @@ int Surface::setCrop(Rect const* rect) realRect = *rect; } - ALOGV("Surface::setCrop rect=[%d %d %d %d]", + ALOGV("GonkNativeWindowClient::setCrop rect=[%d %d %d %d]", realRect.left, realRect.top, realRect.right, realRect.bottom); Mutex::Autolock lock(mMutex); @@ -622,10 +610,10 @@ int Surface::setCrop(Rect const* rect) return NO_ERROR; } -int Surface::setBufferCount(int bufferCount) +int GonkNativeWindowClient::setBufferCount(int bufferCount) { ATRACE_CALL(); - ALOGV("Surface::setBufferCount"); + ALOGV("GonkNativeWindowClient::setBufferCount"); Mutex::Autolock lock(mMutex); status_t err = mGraphicBufferProducer->setBufferCount(bufferCount); @@ -639,10 +627,10 @@ int Surface::setBufferCount(int bufferCount) return err; } -int Surface::setBuffersDimensions(int w, int h) +int GonkNativeWindowClient::setBuffersDimensions(int w, int h) { ATRACE_CALL(); - ALOGV("Surface::setBuffersDimensions"); + ALOGV("GonkNativeWindowClient::setBuffersDimensions"); if (w<0 || h<0) return BAD_VALUE; @@ -656,10 +644,10 @@ int Surface::setBuffersDimensions(int w, int h) return NO_ERROR; } -int Surface::setBuffersUserDimensions(int w, int h) +int GonkNativeWindowClient::setBuffersUserDimensions(int w, int h) { ATRACE_CALL(); - ALOGV("Surface::setBuffersUserDimensions"); + ALOGV("GonkNativeWindowClient::setBuffersUserDimensions"); if (w<0 || h<0) return BAD_VALUE; @@ -673,9 +661,9 @@ int Surface::setBuffersUserDimensions(int w, int h) return NO_ERROR; } -int Surface::setBuffersFormat(int format) +int GonkNativeWindowClient::setBuffersFormat(int format) { - ALOGV("Surface::setBuffersFormat"); + ALOGV("GonkNativeWindowClient::setBuffersFormat"); if (format<0) return BAD_VALUE; @@ -685,10 +673,10 @@ int Surface::setBuffersFormat(int format) return NO_ERROR; } -int Surface::setScalingMode(int mode) +int GonkNativeWindowClient::setScalingMode(int mode) { ATRACE_CALL(); - ALOGV("Surface::setScalingMode(%d)", mode); + ALOGV("GonkNativeWindowClient::setScalingMode(%d)", mode); switch (mode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: @@ -705,33 +693,33 @@ int Surface::setScalingMode(int mode) return NO_ERROR; } -int Surface::setBuffersTransform(int transform) +int GonkNativeWindowClient::setBuffersTransform(int transform) { ATRACE_CALL(); - ALOGV("Surface::setBuffersTransform"); + ALOGV("GonkNativeWindowClient::setBuffersTransform"); Mutex::Autolock lock(mMutex); mTransform = transform; return NO_ERROR; } -int Surface::setBuffersStickyTransform(int transform) +int GonkNativeWindowClient::setBuffersStickyTransform(int transform) { ATRACE_CALL(); - ALOGV("Surface::setBuffersStickyTransform"); + ALOGV("GonkNativeWindowClient::setBuffersStickyTransform"); Mutex::Autolock lock(mMutex); mStickyTransform = transform; return NO_ERROR; } -int Surface::setBuffersTimestamp(int64_t timestamp) +int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp) { - ALOGV("Surface::setBuffersTimestamp"); + ALOGV("GonkNativeWindowClient::setBuffersTimestamp"); Mutex::Autolock lock(mMutex); mTimestamp = timestamp; return NO_ERROR; } -void Surface::freeAllBuffers() { +void GonkNativeWindowClient::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].buffer = 0; } @@ -740,171 +728,17 @@ void Surface::freeAllBuffers() { // ---------------------------------------------------------------------- // the lock/unlock APIs must be used from the same thread -static status_t copyBlt( - const sp& dst, - const sp& src, - const Region& reg) -{ - // src and dst with, height and format must be identical. no verification - // is done here. - status_t err; - uint8_t const * src_bits = NULL; - err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); - ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); - - uint8_t* dst_bits = NULL; - err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits); - ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); - - Region::const_iterator head(reg.begin()); - Region::const_iterator tail(reg.end()); - if (head != tail && src_bits && dst_bits) { - const size_t bpp = bytesPerPixel(src->format); - const size_t dbpr = dst->stride * bpp; - const size_t sbpr = src->stride * bpp; - - while (head != tail) { - const Rect& r(*head++); - ssize_t h = r.height(); - if (h <= 0) continue; - size_t size = r.width() * bpp; - uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; - uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; - if (dbpr==sbpr && size==sbpr) { - size *= h; - h = 1; - } - do { - memcpy(d, s, size); - d += dbpr; - s += sbpr; - } while (--h > 0); - } - } - - if (src_bits) - src->unlock(); - - if (dst_bits) - dst->unlock(); - - return err; -} - // ---------------------------------------------------------------------------- -status_t Surface::lock( +status_t GonkNativeWindowClient::lock( ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) { - if (mLockedBuffer != 0) { - ALOGE("Surface::lock failed, already locked"); - return INVALID_OPERATION; - } - - if (!mConnectedToCpu) { - int err = Surface::connect(NATIVE_WINDOW_API_CPU); - if (err) { - return err; - } - // we're intending to do software rendering from this point - setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - } - - ANativeWindowBuffer* out; - int fenceFd = -1; - status_t err = dequeueBuffer(&out, &fenceFd); - ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); - if (err == NO_ERROR) { - sp backBuffer(GraphicBuffer::getSelf(out)); - const Rect bounds(backBuffer->width, backBuffer->height); - - Region newDirtyRegion; - if (inOutDirtyBounds) { - newDirtyRegion.set(static_cast(*inOutDirtyBounds)); - newDirtyRegion.andSelf(bounds); - } else { - newDirtyRegion.set(bounds); - } - - // figure out if we can copy the frontbuffer back - const sp& frontBuffer(mPostedBuffer); - const bool canCopyBack = (frontBuffer != 0 && - backBuffer->width == frontBuffer->width && - backBuffer->height == frontBuffer->height && - backBuffer->format == frontBuffer->format); - - if (canCopyBack) { - // copy the area that is invalid and not repainted this round - const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); - if (!copyback.isEmpty()) - copyBlt(backBuffer, frontBuffer, copyback); - } else { - // if we can't copy-back anything, modify the user's dirty - // region to make sure they redraw the whole buffer - newDirtyRegion.set(bounds); - mDirtyRegion.clear(); - Mutex::Autolock lock(mMutex); - for (size_t i=0 ; i= 0) { - Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); - mDirtyRegion.subtract(dirtyRegion); - dirtyRegion = newDirtyRegion; - } - } - - mDirtyRegion.orSelf(newDirtyRegion); - if (inOutDirtyBounds) { - *inOutDirtyBounds = newDirtyRegion.getBounds(); - } - - void* vaddr; - status_t res = backBuffer->lockAsync( - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - newDirtyRegion.bounds(), &vaddr, fenceFd); - - ALOGW_IF(res, "failed locking buffer (handle = %p)", - backBuffer->handle); - - if (res != 0) { - err = INVALID_OPERATION; - } else { - mLockedBuffer = backBuffer; - outBuffer->width = backBuffer->width; - outBuffer->height = backBuffer->height; - outBuffer->stride = backBuffer->stride; - outBuffer->format = backBuffer->format; - outBuffer->bits = vaddr; - } - } - return err; + return INVALID_OPERATION; } -status_t Surface::unlockAndPost() +status_t GonkNativeWindowClient::unlockAndPost() { - if (mLockedBuffer == 0) { - ALOGE("Surface::unlockAndPost failed, no locked buffer"); - return INVALID_OPERATION; - } - - int fd = -1; - status_t err = mLockedBuffer->unlockAsync(&fd); - ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); - - err = queueBuffer(mLockedBuffer.get(), fd); - ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)", - mLockedBuffer->handle, strerror(-err)); - - mPostedBuffer = mLockedBuffer; - mLockedBuffer = 0; - return err; + return INVALID_OPERATION; } }; // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientLL.h b/widget/gonk/nativewindow/GonkNativeWindowClientLL.h index f2cf018a9fd1..d20314524c1b 100644 --- a/widget/gonk/nativewindow/GonkNativeWindowClientLL.h +++ b/widget/gonk/nativewindow/GonkNativeWindowClientLL.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +15,10 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_SURFACE_H -#define ANDROID_GUI_SURFACE_H +#ifndef NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_LL_H +#define NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_LL_H #include -#include #include #include @@ -27,58 +27,60 @@ #include #include +#include "GonkBufferQueueLL.h" + struct ANativeWindow_Buffer; namespace android { /* * An implementation of ANativeWindow that feeds graphics buffers into a - * BufferQueue. + * GonkBufferQueue. * * This is typically used by programs that want to render frames through * some means (maybe OpenGL, a software renderer, or a hardware decoder) * and have the frames they create forwarded to SurfaceFlinger for * compositing. For example, a video decoder could render a frame and call * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by - * Surface. Surface then forwards the buffers through Binder IPC - * to the BufferQueue's producer interface, providing the new frame to a + * GonkNativeWindowClient. GonkNativeWindowClient then forwards the buffers through Binder IPC + * to the GonkBufferQueue's producer interface, providing the new frame to a * consumer such as GLConsumer. */ -class Surface - : public ANativeObjectBase +class GonkNativeWindowClient + : public ANativeObjectBase { public: /* - * creates a Surface from the given IGraphicBufferProducer (which concrete - * implementation is a BufferQueue). + * creates a GonkNativeWindowClient from the given IGraphicBufferProducer (which concrete + * implementation is a GonkBufferQueue). * - * Surface is mainly state-less while it's disconnected, it can be + * GonkNativeWindowClient is mainly state-less while it's disconnected, it can be * viewed as a glorified IGraphicBufferProducer holder. It's therefore - * safe to create other Surfaces from the same IGraphicBufferProducer. + * safe to create other GonkNativeWindowClients from the same IGraphicBufferProducer. * - * However, once a Surface is connected, it'll prevent other Surfaces + * However, once a GonkNativeWindowClient is connected, it'll prevent other GonkNativeWindowClients * referring to the same IGraphicBufferProducer to become connected and * therefore prevent them to be used as actual producers of buffers. * - * the controlledByApp flag indicates that this Surface (producer) is + * the controlledByApp flag indicates that this GonkNativeWindowClient (producer) is * controlled by the application. This flag is used at connect time. */ - Surface(const sp& bufferProducer, bool controlledByApp = false); + GonkNativeWindowClient(const sp& bufferProducer, bool controlledByApp = false); /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this - * Surface was created with. Usually it's an error to use the - * IGraphicBufferProducer while the Surface is connected. + * GonkNativeWindowClient was created with. Usually it's an error to use the + * IGraphicBufferProducer while the GonkNativeWindowClient is connected. */ sp getIGraphicBufferProducer() const; /* convenience function to check that the given surface is non NULL as * well as its IGraphicBufferProducer */ - static bool isValid(const sp& surface) { + static bool isValid(const sp& surface) { return surface != NULL && surface->getIGraphicBufferProducer() != NULL; } - /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer. + /* Attaches a sideband buffer stream to the GonkNativeWindowClient's IGraphicBufferProducer. * * A sideband stream is a device-specific mechanism for passing buffers * from the producer to the consumer without using dequeueBuffer/ @@ -94,7 +96,7 @@ public: /* Allocates buffers based on the current dimensions/format. * * This function will allocate up to the maximum number of buffers - * permitted by the current BufferQueue configuration. It will use the + * permitted by the current GonkBufferQueue configuration. It will use the * default format and dimensions. This is most useful to avoid an allocation * delay during dequeueBuffer. If there are already the maximum number of * buffers allocated, this function has no effect. @@ -102,12 +104,12 @@ public: void allocateBuffers(); protected: - virtual ~Surface(); + virtual ~GonkNativeWindowClient(); private: // can't be copied - Surface& operator = (const Surface& rhs); - Surface(const Surface& rhs); + GonkNativeWindowClient& operator = (const GonkNativeWindowClient& rhs); + GonkNativeWindowClient(const GonkNativeWindowClient& rhs); // ANativeWindow hooks static int hook_cancelBuffer(ANativeWindow* window, @@ -175,7 +177,7 @@ public: virtual int unlockAndPost(); protected: - enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS }; + enum { NUM_BUFFER_SLOTS = GonkBufferQueue::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; private: @@ -275,7 +277,7 @@ private: mutable bool mConsumerRunningBehind; // mMutex is the mutex used to prevent concurrent access to the member - // variables of Surface objects. It must be locked whenever the + // variables of GonkNativeWindowClient objects. It must be locked whenever the // member variables are accessed. mutable Mutex mMutex; @@ -290,4 +292,4 @@ private: }; // namespace android -#endif // ANDROID_GUI_SURFACE_H +#endif // NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_LL_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowLL.cpp index fe50c55f51a0..ee939ce740ba 100644 --- a/widget/gonk/nativewindow/GonkNativeWindowLL.cpp +++ b/widget/gonk/nativewindow/GonkNativeWindowLL.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,24 +16,33 @@ */ //#define LOG_NDEBUG 0 -#define LOG_TAG "BufferItemConsumer" +#define LOG_TAG "GonkNativeWindow" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include -#include +#include "GonkNativeWindowLL.h" -#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +using namespace mozilla; +using namespace mozilla::layers; namespace android { -BufferItemConsumer::BufferItemConsumer( - const sp& consumer, uint32_t consumerUsage, +GonkNativeWindow::GonkNativeWindow( + const sp& consumer, int bufferCount) : + GonkConsumerBase(consumer, false), + mNewFrameCallback(nullptr) +{ + if (bufferCount != DEFAULT_MAX_BUFFERS) { + status_t err = mConsumer->setMaxAcquiredBufferCount(bufferCount); + LOG_ALWAYS_FATAL_IF(err != OK, + "Failed to set max acquired buffer count to %d", bufferCount); + } +} + +GonkNativeWindow::GonkNativeWindow( + const sp& consumer, uint32_t consumerUsage, int bufferCount, bool controlledByApp) : - ConsumerBase(consumer, controlledByApp) + GonkConsumerBase(consumer, controlledByApp) { status_t err = mConsumer->setConsumerUsageBits(consumerUsage); LOG_ALWAYS_FATAL_IF(err != OK, @@ -44,16 +54,16 @@ BufferItemConsumer::BufferItemConsumer( } } -BufferItemConsumer::~BufferItemConsumer() { +GonkNativeWindow::~GonkNativeWindow() { } -void BufferItemConsumer::setName(const String8& name) { +void GonkNativeWindow::setName(const String8& name) { Mutex::Autolock _l(mMutex); mName = name; mConsumer->setConsumerName(name); } -status_t BufferItemConsumer::acquireBuffer(BufferItem *item, +status_t GonkNativeWindow::acquireBuffer(BufferItem *item, nsecs_t presentWhen, bool waitForFence) { status_t err; @@ -64,15 +74,15 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, err = acquireBufferLocked(item, presentWhen); if (err != OK) { if (err != NO_BUFFER_AVAILABLE) { - BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); + ALOGE("Error acquiring buffer: %s (%d)", strerror(err), err); } return err; } if (waitForFence) { - err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer"); + err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); if (err != OK) { - BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", + ALOGE("Failed to wait for fence of acquired buffer: %s (%d)", strerror(-err), err); return err; } @@ -83,7 +93,7 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, return OK; } -status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, +status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, const sp& releaseFence) { status_t err; @@ -91,23 +101,99 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); - err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); + err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer); if (err != OK) { - BI_LOGE("Failed to release buffer: %s (%d)", + ALOGE("Failed to release buffer: %s (%d)", strerror(-err), err); } return err; } -status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { +status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock _l(mMutex); return mConsumer->setDefaultBufferSize(w, h); } -status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { +status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) { Mutex::Autolock _l(mMutex); return mConsumer->setDefaultBufferFormat(defaultFormat); } +TemporaryRef +GonkNativeWindow::getCurrentBuffer() { + Mutex::Autolock _l(mMutex); + BufferItem item; + + // In asynchronous mode the list is guaranteed to be one buffer + // deep, while in synchronous mode we use the oldest buffer. + status_t err = acquireBufferLocked(&item, 0); //??? + if (err != NO_ERROR) { + return NULL; + } + + RefPtr textureClient = + mConsumer->getTextureClientFromBuffer(item.mGraphicBuffer.get()); + if (!textureClient) { + return NULL; + } + textureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); + return textureClient; +} + +/* static */ void +GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { + GonkNativeWindow* nativeWindow = + static_cast(closure); + + client->ClearRecycleCallback(); + nativeWindow->returnBuffer(client); +} + +void GonkNativeWindow::returnBuffer(TextureClient* client) { + ALOGD("GonkNativeWindow::returnBuffer"); + Mutex::Autolock lock(mMutex); + + int index = mConsumer->getSlotFromTextureClientLocked(client); + if (index < 0) { + return; + } + + sp fence = client->GetReleaseFenceHandle().mFence; + if (!fence.get()) { + fence = Fence::NO_FENCE; + } + + status_t err; + err = addReleaseFenceLocked(index, + mSlots[index].mGraphicBuffer, + fence); + + err = releaseBufferLocked(index, mSlots[index].mGraphicBuffer); + + if (err != OK) { + ALOGE("Failed to return buffer: %s (%d)", strerror(-err), err); + } +} + +TemporaryRef +GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) { + Mutex::Autolock lock(mMutex); + return mConsumer->getTextureClientFromBuffer(buffer); +} + +void GonkNativeWindow::setNewFrameCallback( + GonkNativeWindowNewFrameCallback* callback) { + ALOGD("setNewFrameCallback"); + Mutex::Autolock lock(mMutex); + mNewFrameCallback = callback; +} + +void GonkNativeWindow::onFrameAvailable() { + GonkConsumerBase::onFrameAvailable(); + + if (mNewFrameCallback) { + mNewFrameCallback->OnNewFrame(); + } +} + } // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.h b/widget/gonk/nativewindow/GonkNativeWindowLL.h index 5494ff1f306d..a257cc562f37 100644 --- a/widget/gonk/nativewindow/GonkNativeWindowLL.h +++ b/widget/gonk/nativewindow/GonkNativeWindowLL.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +15,8 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H -#define ANDROID_GUI_BUFFERITEMCONSUMER_H - -#include +#ifndef NATIVEWINDOW_GONKNATIVEWINDOW_LL_H +#define NATIVEWINDOW_GONKNATIVEWINDOW_LL_H #include @@ -25,28 +24,34 @@ #include #include -#define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer" +#include "GonkConsumerBaseLL.h" +#include "IGonkGraphicBufferConsumerLL.h" namespace android { -class BufferQueue; +// The user of GonkNativeWindow who wants to receive notification of +// new frames should implement this interface. +class GonkNativeWindowNewFrameCallback { +public: + virtual void OnNewFrame() = 0; +}; /** - * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients - * access to the whole BufferItem entry from BufferQueue. Multiple buffers may + * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients + * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may * be acquired at once, to be used concurrently by the client. This consumer can * operate either in synchronous or asynchronous mode. */ -class BufferItemConsumer: public ConsumerBase +class GonkNativeWindow: public GonkConsumerBase { + typedef mozilla::layers::TextureClient TextureClient; public: - typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; - - typedef BufferQueue::BufferItem BufferItem; + typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener; + typedef GonkBufferQueue::BufferItem BufferItem; enum { DEFAULT_MAX_BUFFERS = -1 }; - enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; - enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; + enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT }; + enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE }; // Create a new buffer item consumer. The consumerUsage parameter determines // the consumer usage flags passed to the graphics allocator. The @@ -54,13 +59,15 @@ class BufferItemConsumer: public ConsumerBase // access at the same time. // controlledByApp tells whether this consumer is controlled by the // application. - BufferItemConsumer(const sp& consumer, + GonkNativeWindow(const sp& consumer, + int bufferCount = DEFAULT_MAX_BUFFERS); + GonkNativeWindow(const sp& consumer, uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, bool controlledByApp = false); - virtual ~BufferItemConsumer(); + virtual ~GonkNativeWindow(); - // set the name of the BufferItemConsumer that will be used to identify it in + // set the name of the GonkNativeWindow that will be used to identify it in // log messages. void setName(const String8& name); @@ -92,12 +99,31 @@ class BufferItemConsumer: public ConsumerBase // requestBuffers when a with and height of zero is requested. status_t setDefaultBufferSize(uint32_t w, uint32_t h); - // setDefaultBufferFormat allows the BufferQueue to create + // setDefaultBufferFormat allows the GonkBufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified // in dequeueBuffer status_t setDefaultBufferFormat(uint32_t defaultFormat); + + // Get next frame from the queue, caller owns the returned buffer. + mozilla::TemporaryRef getCurrentBuffer(); + + // Return the buffer to the queue and mark it as FREE. After that + // the buffer is useable again for the decoder. + void returnBuffer(TextureClient* client); + + mozilla::TemporaryRef getTextureClientFromBuffer(ANativeWindowBuffer* buffer); + + void setNewFrameCallback(GonkNativeWindowNewFrameCallback* callback); + + static void RecycleCallback(TextureClient* client, void* closure); + +protected: + virtual void onFrameAvailable(); + +private: + GonkNativeWindowNewFrameCallback* mNewFrameCallback; }; } // namespace android -#endif // ANDROID_GUI_CPUCONSUMER_H +#endif // NATIVEWINDOW_GONKNATIVEWINDOW_LL_H diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h index c4f6d92af7d9..14541c9b474b 100644 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h +++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h @@ -13,6 +13,8 @@ * limitations under the License. */ -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 +# include "IGonkGraphicBufferConsumerLL.h" +#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 # include "IGonkGraphicBufferConsumerKK.h" #endif diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp index c1fcaee15acd..c4c9f65782f3 100644 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp +++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp @@ -25,7 +25,7 @@ #include #include -#include "IGonkGraphicBufferConsumer.h" +#include "IGonkGraphicBufferConsumerKK.h" #include #include diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h index b933bff4c9e2..ce51e1ef2259 100644 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h +++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_IGONKGRAPHICBUFFERCONSUMER_H -#define ANDROID_GUI_IGONKGRAPHICBUFFERCONSUMER_H +#ifndef NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_KK_H +#define NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_KK_H #include #include diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp index f6d087d3b297..5e570298e1ca 100644 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp +++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp @@ -24,17 +24,19 @@ #include #include -#include +#include "IGonkGraphicBufferConsumerLL.h" #include #include #include +#include "mozilla/layers/TextureClient.h" + namespace android { // --------------------------------------------------------------------------- -IGraphicBufferConsumer::BufferItem::BufferItem() : +IGonkGraphicBufferConsumer::BufferItem::BufferItem() : mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), @@ -47,7 +49,7 @@ IGraphicBufferConsumer::BufferItem::BufferItem() : mCrop.makeInvalid(); } -size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { +size_t IGonkGraphicBufferConsumer::BufferItem::getPodSize() const { size_t c = sizeof(mCrop) + sizeof(mTransform) + sizeof(mScalingMode) + @@ -61,7 +63,7 @@ size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { return c; } -size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const { +size_t IGonkGraphicBufferConsumer::BufferItem::getFlattenedSize() const { size_t c = 0; if (mGraphicBuffer != 0) { c += mGraphicBuffer->getFlattenedSize(); @@ -74,7 +76,7 @@ size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const { return sizeof(int32_t) + c + getPodSize(); } -size_t IGraphicBufferConsumer::BufferItem::getFdCount() const { +size_t IGonkGraphicBufferConsumer::BufferItem::getFdCount() const { size_t c = 0; if (mGraphicBuffer != 0) { c += mGraphicBuffer->getFdCount(); @@ -95,7 +97,7 @@ static bool readBoolFromInt(void const*& buffer, size_t& size) { return static_cast(i); } -status_t IGraphicBufferConsumer::BufferItem::flatten( +status_t IGonkGraphicBufferConsumer::BufferItem::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { // make sure we have enough space @@ -142,7 +144,7 @@ status_t IGraphicBufferConsumer::BufferItem::flatten( return NO_ERROR; } -status_t IGraphicBufferConsumer::BufferItem::unflatten( +status_t IGonkGraphicBufferConsumer::BufferItem::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { if (size < sizeof(uint32_t)) @@ -207,17 +209,17 @@ enum { }; -class BpGraphicBufferConsumer : public BpInterface +class BpGonkGraphicBufferConsumer : public BpInterface { public: - BpGraphicBufferConsumer(const sp& impl) - : BpInterface(impl) + BpGonkGraphicBufferConsumer(const sp& impl) + : BpInterface(impl) { } virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt64(presentWhen); status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); if (result != NO_ERROR) { @@ -232,7 +234,7 @@ public: virtual status_t detachBuffer(int slot) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(slot); status_t result = remote()->transact(DETACH_BUFFER, data, &reply); if (result != NO_ERROR) { @@ -244,7 +246,7 @@ public: virtual status_t attachBuffer(int* slot, const sp& buffer) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.write(*buffer.get()); status_t result = remote()->transact(ATTACH_BUFFER, data, &reply); if (result != NO_ERROR) { @@ -255,11 +257,9 @@ public: return result; } - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, - EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)), - const sp& releaseFence) { + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp& releaseFence) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(buf); data.writeInt64(frameNumber); data.write(*releaseFence); @@ -272,7 +272,7 @@ public: virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeStrongBinder(consumer->asBinder()); data.writeInt32(controlledByApp); status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); @@ -284,7 +284,7 @@ public: virtual status_t consumerDisconnect() { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); if (result != NO_ERROR) { return result; @@ -298,7 +298,7 @@ public: ALOGE("getReleasedBuffers: slotMask must not be NULL"); return BAD_VALUE; } - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); if (result != NO_ERROR) { return result; @@ -309,7 +309,7 @@ public: virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(w); data.writeInt32(h); status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); @@ -321,7 +321,7 @@ public: virtual status_t setDefaultMaxBufferCount(int bufferCount) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(bufferCount); status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); if (result != NO_ERROR) { @@ -332,7 +332,7 @@ public: virtual status_t disableAsyncBuffer() { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); if (result != NO_ERROR) { return result; @@ -342,7 +342,7 @@ public: virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(maxAcquiredBuffers); status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); if (result != NO_ERROR) { @@ -353,14 +353,14 @@ public: virtual void setConsumerName(const String8& name) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeString8(name); remote()->transact(SET_CONSUMER_NAME, data, &reply); } virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(defaultFormat); status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); if (result != NO_ERROR) { @@ -371,7 +371,7 @@ public: virtual status_t setConsumerUsageBits(uint32_t usage) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(usage); status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); if (result != NO_ERROR) { @@ -382,7 +382,7 @@ public: virtual status_t setTransformHint(uint32_t hint) { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(hint); status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); if (result != NO_ERROR) { @@ -394,7 +394,7 @@ public: virtual sp getSidebandStream() const { Parcel data, reply; status_t err; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) { return NULL; } @@ -407,24 +407,37 @@ public: virtual void dump(String8& result, const char* prefix) const { Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); data.writeString8(result); data.writeString8(String8(prefix ? prefix : "")); remote()->transact(DUMP, data, &reply); reply.readString8(); } + + // Added by mozilla + virtual mozilla::TemporaryRef + getTextureClientFromBuffer(ANativeWindowBuffer* buffer) + { + return nullptr; + } + + virtual int + getSlotFromTextureClientLocked(mozilla::layers::TextureClient* client) const + { + return BAD_VALUE; + } }; -IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer"); +IMPLEMENT_META_INTERFACE(GonkGraphicBufferConsumer, "android.gui.IGonkGraphicBufferConsumer"); // ---------------------------------------------------------------------- -status_t BnGraphicBufferConsumer::onTransact( +status_t BnGonkGraphicBufferConsumer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case ACQUIRE_BUFFER: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); BufferItem item; int64_t presentWhen = data.readInt64(); status_t result = acquireBuffer(&item, presentWhen); @@ -434,14 +447,14 @@ status_t BnGraphicBufferConsumer::onTransact( return NO_ERROR; } break; case DETACH_BUFFER: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); int slot = data.readInt32(); int result = detachBuffer(slot); reply->writeInt32(result); return NO_ERROR; } break; case ATTACH_BUFFER: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); sp buffer = new GraphicBuffer(); data.read(*buffer.get()); int slot; @@ -451,19 +464,18 @@ status_t BnGraphicBufferConsumer::onTransact( return NO_ERROR; } break; case RELEASE_BUFFER: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); int buf = data.readInt32(); uint64_t frameNumber = data.readInt64(); sp releaseFence = new Fence(); status_t err = data.read(*releaseFence); if (err) return err; - status_t result = releaseBuffer(buf, frameNumber, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); + status_t result = releaseBuffer(buf, frameNumber, releaseFence); reply->writeInt32(result); return NO_ERROR; } break; case CONSUMER_CONNECT: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); sp consumer = IConsumerListener::asInterface( data.readStrongBinder() ); bool controlledByApp = data.readInt32(); status_t result = consumerConnect(consumer, controlledByApp); @@ -471,13 +483,13 @@ status_t BnGraphicBufferConsumer::onTransact( return NO_ERROR; } break; case CONSUMER_DISCONNECT: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); status_t result = consumerDisconnect(); reply->writeInt32(result); return NO_ERROR; } break; case GET_RELEASED_BUFFERS: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); uint64_t slotMask; status_t result = getReleasedBuffers(&slotMask); reply->writeInt64(slotMask); @@ -485,7 +497,7 @@ status_t BnGraphicBufferConsumer::onTransact( return NO_ERROR; } break; case SET_DEFAULT_BUFFER_SIZE: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); status_t result = setDefaultBufferSize(w, h); @@ -493,56 +505,56 @@ status_t BnGraphicBufferConsumer::onTransact( return NO_ERROR; } break; case SET_DEFAULT_MAX_BUFFER_COUNT: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); uint32_t bufferCount = data.readInt32(); status_t result = setDefaultMaxBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; } break; case DISABLE_ASYNC_BUFFER: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); status_t result = disableAsyncBuffer(); reply->writeInt32(result); return NO_ERROR; } break; case SET_MAX_ACQUIRED_BUFFER_COUNT: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); uint32_t maxAcquiredBuffers = data.readInt32(); status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); reply->writeInt32(result); return NO_ERROR; } break; case SET_CONSUMER_NAME: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); setConsumerName( data.readString8() ); return NO_ERROR; } break; case SET_DEFAULT_BUFFER_FORMAT: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); uint32_t defaultFormat = data.readInt32(); status_t result = setDefaultBufferFormat(defaultFormat); reply->writeInt32(result); return NO_ERROR; } break; case SET_CONSUMER_USAGE_BITS: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); uint32_t usage = data.readInt32(); status_t result = setConsumerUsageBits(usage); reply->writeInt32(result); return NO_ERROR; } break; case SET_TRANSFORM_HINT: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); uint32_t hint = data.readInt32(); status_t result = setTransformHint(hint); reply->writeInt32(result); return NO_ERROR; } break; case DUMP: { - CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); String8 result = data.readString8(); String8 prefix = data.readString8(); - static_cast(this)->dump(result, prefix); + static_cast(this)->dump(result, prefix); reply->writeString8(result); return NO_ERROR; } diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h index 15f51fe8c0f2..c76aa90f19d2 100644 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h +++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H -#define ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H +#ifndef NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_LL_H +#define NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_LL_H #include #include @@ -27,8 +27,15 @@ #include #include -#include -#include +#include "mozilla/RefPtr.h" + +class ANativeWindowBuffer; + +namespace mozilla { +namespace layers { +class TextureClient; +} +} namespace android { // ---------------------------------------------------------------------------- @@ -38,8 +45,7 @@ class GraphicBuffer; class IConsumerListener; class NativeHandle; -class IGraphicBufferConsumer : public IInterface { - +class IGonkGraphicBufferConsumer : public IInterface { public: // public facing structure for BufferSlot @@ -197,9 +203,7 @@ public: // * the buffer slot was invalid // * the fence was NULL // * the buffer slot specified is not in the acquired state - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, - EGLDisplay display, EGLSyncKHR fence, - const sp& releaseFence) = 0; + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp& releaseFence) = 0; // consumerConnect connects a consumer to the BufferQueue. Only one // consumer may be connected, and when that consumer disconnects the @@ -306,13 +310,19 @@ public: // dump state into a string virtual void dump(String8& result, const char* prefix) const = 0; + // Added by mozilla + virtual mozilla::TemporaryRef + getTextureClientFromBuffer(ANativeWindowBuffer* buffer) = 0; + + virtual int getSlotFromTextureClientLocked(mozilla::layers::TextureClient* client) const = 0; + public: - DECLARE_META_INTERFACE(GraphicBufferConsumer); + DECLARE_META_INTERFACE(GonkGraphicBufferConsumer); }; // ---------------------------------------------------------------------------- -class BnGraphicBufferConsumer : public BnInterface +class BnGonkGraphicBufferConsumer : public BnInterface { public: virtual status_t onTransact( uint32_t code, @@ -324,4 +334,4 @@ public: // ---------------------------------------------------------------------------- }; // namespace android -#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H +#endif // ANDROID_GUI_IGONKGRAPHICBUFFERCONSUMER_H diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build index 9691abb2708d..d3c54918fbfd 100644 --- a/widget/gonk/nativewindow/moz.build +++ b/widget/gonk/nativewindow/moz.build @@ -20,13 +20,28 @@ EXPORTS += [ 'GonkNativeWindowClient.h', ] -if CONFIG['ANDROID_VERSION'] == '19': +if CONFIG['ANDROID_VERSION'] >= '19': + EXPORTS += [ + 'IGonkGraphicBufferConsumer.h', + ] + +if CONFIG['ANDROID_VERSION'] >= '21': + EXPORTS += [ + 'GonkBufferQueueLL/GonkBufferQueueDefs.h', + 'GonkBufferQueueLL/GonkBufferQueueLL.h', + 'GonkBufferQueueLL/GonkBufferSlot.h', + 'GonkConsumerBaseLL.h', + 'GonkNativeWindowClientLL.h', + 'GonkNativeWindowLL.h', + 'IGonkGraphicBufferConsumerLL.h', + ] +elif CONFIG['ANDROID_VERSION'] >= '19': EXPORTS += [ 'GonkBufferQueueKK.h', 'GonkConsumerBaseKK.h', 'GonkNativeWindowClientKK.h', 'GonkNativeWindowKK.h', - 'IGonkGraphicBufferConsumer.h', + 'IGonkGraphicBufferConsumerKK.h', ] elif CONFIG['ANDROID_VERSION'] in ('17', '18'): EXPORTS += [ @@ -42,13 +57,26 @@ elif CONFIG['ANDROID_VERSION'] == '15': ] if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER'] or CONFIG['MOZ_WEBRTC']: - if CONFIG['ANDROID_VERSION'] == '19': + if CONFIG['ANDROID_VERSION'] >= '21': + SOURCES += [ + 'GonkBufferQueueLL/GonkBufferItem.cpp', + 'GonkBufferQueueLL/GonkBufferQueueConsumer.cpp', + 'GonkBufferQueueLL/GonkBufferQueueCore.cpp', + 'GonkBufferQueueLL/GonkBufferQueueLL.cpp', + 'GonkBufferQueueLL/GonkBufferQueueProducer.cpp', + 'GonkBufferQueueLL/GonkBufferSlot.cpp', + 'GonkConsumerBaseLL.cpp', + 'GonkNativeWindowClientLL.cpp', + 'GonkNativeWindowLL.cpp', + 'IGonkGraphicBufferConsumerLL.cpp', + ] + elif CONFIG['ANDROID_VERSION'] >= '19': SOURCES += [ 'GonkBufferQueueKK.cpp', 'GonkConsumerBaseKK.cpp', 'GonkNativeWindowClientKK.cpp', 'GonkNativeWindowKK.cpp', - 'IGonkGraphicBufferConsumer.cpp', + 'IGonkGraphicBufferConsumerKK.cpp', ] elif CONFIG['ANDROID_VERSION'] in ('17', '18'): SOURCES += [ From 761afc5ba03f60810ae975e9a193ad1e21268cdb Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Thu, 18 Dec 2014 18:08:00 +0100 Subject: [PATCH 37/64] Bug 1098970 - Part 5: Fix link errors casued by symbol visibility. r=sotaro Use the NO_VISIBILITY_FLAGS flag to fix the hidden symbol visibility and some warnings. --- widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h | 2 -- widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp | 5 ++--- widget/gonk/nativewindow/moz.build | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h index 164708851d4a..c93827eb51ce 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h @@ -27,8 +27,6 @@ namespace android { -class Fence; - struct GonkBufferSlot { typedef mozilla::layers::TextureClient TextureClient; diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp index 4f6fbd50da3d..2eb73f987d7c 100644 --- a/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp +++ b/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp @@ -92,8 +92,8 @@ void GonkNativeWindowClient::setSidebandStream(const sp& stream) { void GonkNativeWindowClient::allocateBuffers() { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; - mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, mReqWidth, - mReqHeight, mReqFormat, mReqUsage); + mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, reqWidth, + reqHeight, mReqFormat, mReqUsage); } int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) { @@ -268,7 +268,6 @@ int GonkNativeWindowClient::cancelBuffer(android_native_buffer_t* buffer, int GonkNativeWindowClient::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { - bool dumpedState = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build index d3c54918fbfd..416ed09ba6d7 100644 --- a/widget/gonk/nativewindow/moz.build +++ b/widget/gonk/nativewindow/moz.build @@ -110,3 +110,5 @@ if CONFIG['GNU_CC']: FINAL_LIBRARY = 'xul' DISABLE_STL_WRAPPING = True + +NO_VISIBILITY_FLAGS = True From ea4203738e22c18d9b307c3cd3b082e2d25761bc Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Wed, 17 Dec 2014 22:31:00 +0100 Subject: [PATCH 38/64] Bug 1098970 - Part 6: Fix the usage of GonkNativeWindow in Omx. r=sotaro Use new APIs for GonkNativeWindowLL. --- dom/media/omx/MediaCodecReader.cpp | 17 +++++++++++++++++ dom/media/omx/MediaCodecReader.h | 3 +++ dom/media/omx/MediaOmxReader.cpp | 2 +- dom/media/omx/OmxDecoder.cpp | 12 +++++++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/dom/media/omx/MediaCodecReader.cpp b/dom/media/omx/MediaCodecReader.cpp index 43cdc4911512..09244072d57c 100644 --- a/dom/media/omx/MediaCodecReader.cpp +++ b/dom/media/omx/MediaCodecReader.cpp @@ -1250,7 +1250,9 @@ MediaCodecReader::DestroyMediaSources() { mAudioTrack.mSource = nullptr; mVideoTrack.mSource = nullptr; +#if ANDROID_VERSION >= 21 mAudioOffloadTrack.mSource = nullptr; +#endif } void @@ -1327,7 +1329,15 @@ MediaCodecReader::CreateMediaCodec(sp& aLooper, if (aTrack.mType == Track::kVideo && aTrack.mCodec->getCapability(&capability) == OK && (capability & MediaCodecProxy::kCanExposeGraphicBuffer) == MediaCodecProxy::kCanExposeGraphicBuffer) { +#if ANDROID_VERSION >= 21 + android::sp producer; + android::sp consumer; + GonkBufferQueue::createBufferQueue(&producer, &consumer); + aTrack.mNativeWindow = new GonkNativeWindow(consumer); + aTrack.mGraphicBufferProducer = producer; +#else aTrack.mNativeWindow = new GonkNativeWindow(); +#endif } if (!aAsync) { @@ -1354,7 +1364,11 @@ MediaCodecReader::ConfigureMediaCodec(Track& aTrack) sp surface; if (aTrack.mNativeWindow != nullptr) { +#if ANDROID_VERSION >= 21 + surface = new Surface(aTrack.mGraphicBufferProducer); +#else surface = new Surface(aTrack.mNativeWindow->getBufferQueue()); +#endif } sp sourceFormat = aTrack.mSource->getFormat(); @@ -1399,6 +1413,9 @@ MediaCodecReader::DestroyMediaCodec(Track& aTrack) { aTrack.mCodec = nullptr; aTrack.mNativeWindow = nullptr; +#if ANDROID_VERSION >= 21 + aTrack.mGraphicBufferProducer = nullptr; +#endif } bool diff --git a/dom/media/omx/MediaCodecReader.h b/dom/media/omx/MediaCodecReader.h index 858a97ccc86b..4e745a10e673 100644 --- a/dom/media/omx/MediaCodecReader.h +++ b/dom/media/omx/MediaCodecReader.h @@ -139,6 +139,9 @@ protected: android::Vector > mInputBuffers; android::Vector > mOutputBuffers; android::sp mNativeWindow; +#if ANDROID_VERSION >= 21 + android::sp mGraphicBufferProducer; +#endif // pipeline copier nsAutoPtr mInputCopier; diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 7ab49a5fe209..8717612be740 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -112,7 +112,7 @@ private: mOffset += length; } - if (mOffset < mFullLength) { + if (static_cast(mOffset) < mFullLength) { // We cannot read data in the main thread because it // might block for too long. Instead we post an IO task // to the IO thread if there is more data available. diff --git a/dom/media/omx/OmxDecoder.cpp b/dom/media/omx/OmxDecoder.cpp index f0fb361c228a..b2c3c0951769 100644 --- a/dom/media/omx/OmxDecoder.cpp +++ b/dom/media/omx/OmxDecoder.cpp @@ -254,8 +254,18 @@ bool OmxDecoder::AllocateMediaResources() NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver."); sp omx = client.interface(); +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 + sp producer; + sp consumer; + GonkBufferQueue::createBufferQueue(&producer, &consumer); + mNativeWindow = new GonkNativeWindow(consumer); +#else mNativeWindow = new GonkNativeWindow(); -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 +#endif + +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 + mNativeWindowClient = new GonkNativeWindowClient(producer); +#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow->getBufferQueue()); #else mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow); From df96b9fc187f8be7cc9d182f45ee1988c5744444 Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Sun, 21 Dec 2014 20:00:00 +0100 Subject: [PATCH 39/64] Bug 1098970 - Part 7: Turn on omx decoder. r=sotaro --- configure.in | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.in b/configure.in index 6d612e1d50e4..26f0ef5ea9e4 100644 --- a/configure.in +++ b/configure.in @@ -286,6 +286,7 @@ if test -n "$gonkdir" ; then 21) GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include" MOZ_AUDIO_OFFLOAD=1 + MOZ_OMX_DECODER=1 AC_SUBST(MOZ_AUDIO_OFFLOAD) AC_DEFINE(MOZ_AUDIO_OFFLOAD) MOZ_FMP4= From dfe2f38bb4a0994517665f684064a31e9d6c2710 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 05:01:13 -0800 Subject: [PATCH 40/64] Bumping manifests a=b2g-bump --- b2g/config/flame-kk/sources.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 13cdc8394db3..825377c58027 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -137,7 +137,7 @@ - + From 5708a14a7fc71316d893e088c1c6e333d0095668 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Fri, 12 Dec 2014 19:04:00 +0800 Subject: [PATCH 41/64] Bug 1098210 - Use WebIDL enums for mvnoType. r=hsinyi --- dom/icc/Assertions.cpp | 12 ++++++++++++ dom/icc/Icc.cpp | 7 +++---- dom/icc/Icc.h | 2 +- dom/icc/interfaces/nsIIccProvider.idl | 9 +++++++-- dom/system/gonk/RadioInterfaceLayer.js | 8 ++++---- dom/system/gonk/ril_consts.js | 5 +++++ dom/webidl/MozIcc.webidl | 13 ++++++++----- 7 files changed, 40 insertions(+), 16 deletions(-) diff --git a/dom/icc/Assertions.cpp b/dom/icc/Assertions.cpp index 4d4c76cf34cd..03f7148d88b1 100644 --- a/dom/icc/Assertions.cpp +++ b/dom/icc/Assertions.cpp @@ -94,6 +94,18 @@ ASSERT_ICC_CONTACT_TYPE_EQUALITY(Sdn, CARD_CONTACT_TYPE_SDN); #undef ASSERT_ICC_CONTACT_TYPE_EQUALITY +/** + * Enum IccMvnoType + */ +#define ASSERT_ICC_MVNO_TYPE_EQUALITY(webidlState, xpidlState) \ + ASSERT_EQUALITY(IccMvnoType, webidlState, xpidlState) + +ASSERT_ICC_MVNO_TYPE_EQUALITY(Imsi, CARD_MVNO_TYPE_IMSI); +ASSERT_ICC_MVNO_TYPE_EQUALITY(Spn, CARD_MVNO_TYPE_SPN); +ASSERT_ICC_MVNO_TYPE_EQUALITY(Gid, CARD_MVNO_TYPE_GID); + +#undef ASSERT_ICC_MVNO_TYPE_EQUALITY + #undef ASSERT_EQUALITY } // namespace icc diff --git a/dom/icc/Icc.cpp b/dom/icc/Icc.cpp index c693837ae970..4199df4f4656 100644 --- a/dom/icc/Icc.cpp +++ b/dom/icc/Icc.cpp @@ -384,8 +384,7 @@ Icc::UpdateContact(const JSContext* aCx, IccContactType aContactType, } already_AddRefed -Icc::MatchMvno(const nsAString& aMvnoType, - const nsAString& aMvnoData, +Icc::MatchMvno(IccMvnoType aMvnoType, const nsAString& aMvnoData, ErrorResult& aRv) { if (!mProvider) { @@ -395,8 +394,8 @@ Icc::MatchMvno(const nsAString& aMvnoType, nsRefPtr request; nsresult rv = mProvider->MatchMvno(mClientId, GetOwner(), - aMvnoType, aMvnoData, - getter_AddRefs(request)); + static_cast(aMvnoType), + aMvnoData, getter_AddRefs(request)); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; diff --git a/dom/icc/Icc.h b/dom/icc/Icc.h index 4bf502480959..cdc34ebe3975 100644 --- a/dom/icc/Icc.h +++ b/dom/icc/Icc.h @@ -98,7 +98,7 @@ public: ErrorResult& aRv); already_AddRefed - MatchMvno(const nsAString& aMvnoType, const nsAString& aMatchData, + MatchMvno(IccMvnoType aMvnoType, const nsAString& aMatchData, ErrorResult& aRv); IMPL_EVENT_HANDLER(iccinfochange) diff --git a/dom/icc/interfaces/nsIIccProvider.idl b/dom/icc/interfaces/nsIIccProvider.idl index 7d7769129e0a..011d84be222a 100644 --- a/dom/icc/interfaces/nsIIccProvider.idl +++ b/dom/icc/interfaces/nsIIccProvider.idl @@ -20,7 +20,7 @@ interface nsIIccListener : nsISupports /** * XPCOM component (in the content process) that provides the ICC information. */ -[scriptable, uuid(937213c3-f64e-4f58-b4e0-3010f219d0c3)] +[scriptable, uuid(c3e3c1a9-6ac4-4916-a777-7d49ffd89c46)] interface nsIIccProvider : nsISupports { // MUST match enum IccCardState in MozIcc.webidl! @@ -85,6 +85,11 @@ interface nsIIccProvider : nsISupports const unsigned long CARD_CONTACT_TYPE_FDN = 1; const unsigned long CARD_CONTACT_TYPE_SDN = 2; + // MUST match with enum IccMvnoType in MozIcc.webidl + const unsigned long CARD_MVNO_TYPE_IMSI = 0; + const unsigned long CARD_MVNO_TYPE_SPN = 1; + const unsigned long CARD_MVNO_TYPE_GID = 2; + /** * Called when a content process registers receiving unsolicited messages from * RadioInterfaceLayer in the chrome process. Only a content process that has @@ -182,6 +187,6 @@ interface nsIIccProvider : nsISupports */ nsIDOMDOMRequest matchMvno(in unsigned long clientId, in nsIDOMWindow window, - in DOMString mvnoType, + in unsigned long mvnoType, in DOMString mvnoData); }; diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 86227fef5bb3..2d2503eae61c 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -1993,20 +1993,20 @@ RadioInterface.prototype = { matchMvno: function(target, message) { if (DEBUG) this.debug("matchMvno: " + JSON.stringify(message)); - if (!message || !message.mvnoType || !message.mvnoData) { + if (!message || !message.mvnoData) { message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER; } if (!message.errorMsg) { switch (message.mvnoType) { - case "imsi": + case RIL.GECKO_CARDMVNO_TYPE_IMSI: if (!this.rilContext.imsi) { message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE; break; } message.result = this.isImsiMatches(message.mvnoData); break; - case "spn": + case RIL.GECKO_CARDMVNO_TYPE_SPN: let spn = this.rilContext.iccInfo && this.rilContext.iccInfo.spn; if (!spn) { message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE; @@ -2014,7 +2014,7 @@ RadioInterface.prototype = { } message.result = spn == message.mvnoData; break; - case "gid": + case RIL.GECKO_CARDMVNO_TYPE_GID: this.workerMessenger.send("getGID1", null, (function(response) { let gid = response.gid1; let mvnoDataLength = message.mvnoData.length; diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index e46d9c0bc177..5851e939bf0a 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -2645,6 +2645,11 @@ this.GECKO_CARDCONTACT_TYPE_ADN = 0; this.GECKO_CARDCONTACT_TYPE_FDN = 1; this.GECKO_CARDCONTACT_TYPE_SDN = 2; +// See nsIIccProvider::CARD_MVNO_TYPE_* +this.GECKO_CARDMVNO_TYPE_IMSI = 0; +this.GECKO_CARDMVNO_TYPE_SPN = 1; +this.GECKO_CARDMVNO_TYPE_GID = 2; + // See ril.h RIL_PersoSubstate this.PERSONSUBSTATE = {}; PERSONSUBSTATE[CARD_PERSOSUBSTATE_UNKNOWN] = GECKO_CARDSTATE_UNKNOWN; diff --git a/dom/webidl/MozIcc.webidl b/dom/webidl/MozIcc.webidl index f21ac6730b05..309b52249f19 100644 --- a/dom/webidl/MozIcc.webidl +++ b/dom/webidl/MozIcc.webidl @@ -82,6 +82,13 @@ enum IccContactType "sdn" // Service Dialling Number. }; +enum IccMvnoType +{ + "imsi", + "spn", + "gid" +}; + dictionary IccUnlockCardLockOptions { required IccLockType lockType; @@ -315,17 +322,13 @@ interface MozIcc : EventTarget * * @param mvnoType * Mvno type to use to compare the match data. - * Currently, we only support 'imsi'. * @param matchData * Data to be compared with ICC's field. * * @return a DOMRequest. * The request's result will be a boolean indicating the matching * result. - * - * TODO: change param mvnoType to WebIDL enum after Bug 864489 - - * B2G RIL: use ipdl as IPC in MozIccManager */ [Throws] - DOMRequest matchMvno(DOMString mvnoType, DOMString matchData); + DOMRequest matchMvno(IccMvnoType mvnoType, DOMString matchData); }; From 81f7e51dc6f23d23bdb391f5642d176a5bef38c2 Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Mon, 22 Dec 2014 03:49:00 -0500 Subject: [PATCH 42/64] Bug 1042696 - Set allocator to TextureClient from constructor. r=nical --- gfx/layers/D3D9SurfaceImage.cpp | 6 +++- gfx/layers/MacIOSurfaceImage.cpp | 4 ++- gfx/layers/TextureDIB.cpp | 9 ++++-- gfx/layers/TextureDIB.h | 4 ++- gfx/layers/basic/TextureClientX11.cpp | 7 +++-- gfx/layers/basic/TextureClientX11.h | 1 - gfx/layers/client/CanvasClient.cpp | 7 +++-- gfx/layers/client/ImageClient.cpp | 12 ++++---- gfx/layers/client/TextureClient.cpp | 28 ++++++++----------- gfx/layers/client/TextureClient.h | 9 +++--- gfx/layers/d3d11/TextureD3D11.cpp | 9 ++++-- gfx/layers/d3d11/TextureD3D11.h | 4 ++- gfx/layers/d3d9/TextureD3D9.cpp | 15 ++++++---- gfx/layers/d3d9/TextureD3D9.h | 7 +++-- .../opengl/MacIOSurfaceTextureClientOGL.cpp | 5 ++-- .../opengl/MacIOSurfaceTextureClientOGL.h | 3 +- gfx/layers/opengl/TextureClientOGL.cpp | 10 ++++--- gfx/layers/opengl/TextureClientOGL.h | 6 ++-- 18 files changed, 86 insertions(+), 60 deletions(-) diff --git a/gfx/layers/D3D9SurfaceImage.cpp b/gfx/layers/D3D9SurfaceImage.cpp index 08b97050f264..9a7efd29ac29 100644 --- a/gfx/layers/D3D9SurfaceImage.cpp +++ b/gfx/layers/D3D9SurfaceImage.cpp @@ -6,6 +6,8 @@ #include "D3D9SurfaceImage.h" #include "gfx2DGlue.h" #include "mozilla/layers/TextureD3D9.h" +#include "mozilla/layers/CompositableClient.h" +#include "mozilla/layers/CompositableForwarder.h" #include "mozilla/gfx/Types.h" namespace mozilla { @@ -132,7 +134,9 @@ D3D9SurfaceImage::GetTextureClient(CompositableClient* aClient) EnsureSynchronized(); if (!mTextureClient) { RefPtr textureClient = - new SharedTextureClientD3D9(gfx::SurfaceFormat::B8G8R8X8, TextureFlags::DEFAULT); + new SharedTextureClientD3D9(aClient->GetForwarder(), + gfx::SurfaceFormat::B8G8R8X8, + TextureFlags::DEFAULT); textureClient->InitWith(mTexture, mShareHandle, mDesc); mTextureClient = textureClient; } diff --git a/gfx/layers/MacIOSurfaceImage.cpp b/gfx/layers/MacIOSurfaceImage.cpp index c8f78afef77b..000a308686ca 100644 --- a/gfx/layers/MacIOSurfaceImage.cpp +++ b/gfx/layers/MacIOSurfaceImage.cpp @@ -4,6 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MacIOSurfaceImage.h" +#include "mozilla/layers/CompositableClient.h" +#include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/MacIOSurfaceTextureClientOGL.h" using namespace mozilla; @@ -14,7 +16,7 @@ MacIOSurfaceImage::GetTextureClient(CompositableClient* aClient) { if (!mTextureClient) { RefPtr buffer = - new MacIOSurfaceTextureClientOGL(TextureFlags::DEFAULT); + new MacIOSurfaceTextureClientOGL(aClient->GetForwarder(), TextureFlags::DEFAULT); buffer->InitWith(mSurface); mTextureClient = buffer; } diff --git a/gfx/layers/TextureDIB.cpp b/gfx/layers/TextureDIB.cpp index 497a2c9c570f..8ad883717d59 100644 --- a/gfx/layers/TextureDIB.cpp +++ b/gfx/layers/TextureDIB.cpp @@ -12,8 +12,10 @@ using namespace gfx; namespace layers { -DIBTextureClient::DIBTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags) - : TextureClient(aFlags) +DIBTextureClient::DIBTextureClient(ISurfaceAllocator* aAllocator, + gfx::SurfaceFormat aFormat, + TextureFlags aFlags) + : TextureClient(aAllocator, aFlags) , mFormat(aFormat) , mIsLocked(false) { @@ -29,7 +31,8 @@ TemporaryRef DIBTextureClient::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { - RefPtr tex = new DIBTextureClient(mFormat, mFlags | aFlags); + RefPtr tex = new DIBTextureClient(mAllocator, mFormat, + mFlags | aFlags); if (!tex->AllocateForSurface(mSize, aAllocFlags)) { return nullptr; diff --git a/gfx/layers/TextureDIB.h b/gfx/layers/TextureDIB.h index f093405c5cec..27df1e93a704 100644 --- a/gfx/layers/TextureDIB.h +++ b/gfx/layers/TextureDIB.h @@ -23,7 +23,9 @@ namespace layers { class DIBTextureClient : public TextureClient { public: - DIBTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags); + DIBTextureClient(ISurfaceAllocator* aAllocator, + gfx::SurfaceFormat aFormat, + TextureFlags aFlags); virtual ~DIBTextureClient(); diff --git a/gfx/layers/basic/TextureClientX11.cpp b/gfx/layers/basic/TextureClientX11.cpp index 2f379c5976bb..6d752b82cbbf 100644 --- a/gfx/layers/basic/TextureClientX11.cpp +++ b/gfx/layers/basic/TextureClientX11.cpp @@ -19,10 +19,11 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::layers; -TextureClientX11::TextureClientX11(ISurfaceAllocator* aAllocator, SurfaceFormat aFormat, TextureFlags aFlags) - : TextureClient(aFlags), +TextureClientX11::TextureClientX11(ISurfaceAllocator* aAllocator, + SurfaceFormat aFormat, + TextureFlags aFlags) + : TextureClient(aAllocator, aFlags), mFormat(aFormat), - mAllocator(aAllocator), mLocked(false) { MOZ_COUNT_CTOR(TextureClientX11); diff --git a/gfx/layers/basic/TextureClientX11.h b/gfx/layers/basic/TextureClientX11.h index b0e53ddcd9ac..3ae4f808a1a0 100644 --- a/gfx/layers/basic/TextureClientX11.h +++ b/gfx/layers/basic/TextureClientX11.h @@ -55,7 +55,6 @@ class TextureClientX11 : public TextureClient gfx::SurfaceFormat mFormat; gfx::IntSize mSize; RefPtr mSurface; - RefPtr mAllocator; RefPtr mDrawTarget; bool mLocked; }; diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index ee4a7456736b..a4435c2b7a96 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -155,7 +155,8 @@ CanvasClientSharedSurface::CanvasClientSharedSurface(CompositableForwarder* aLay // Accelerated backends static TemporaryRef -TexClientFromShSurf(SharedSurface* surf, TextureFlags flags) +TexClientFromShSurf(ISurfaceAllocator* aAllocator, SharedSurface* surf, + TextureFlags flags) { switch (surf->mType) { case SharedSurfaceType::Basic: @@ -167,7 +168,7 @@ TexClientFromShSurf(SharedSurface* surf, TextureFlags flags) #endif default: - return new SharedSurfaceTextureClient(flags, surf); + return new SharedSurfaceTextureClient(aAllocator, flags, surf); } } @@ -364,7 +365,7 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) auto flags = GetTextureFlags() | TextureFlags::IMMUTABLE; // Get a TexClient from our surf. - RefPtr newTex = TexClientFromShSurf(surf, flags); + RefPtr newTex = TexClientFromShSurf(GetForwarder(), surf, flags); if (!newTex) { auto manager = aLayer->ClientManager(); auto shadowForwarder = manager->AsShadowForwarder(); diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index de76542717a6..ec6b438d79e5 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -192,15 +192,17 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = static_cast(image); - texture = new EGLImageTextureClient(mTextureFlags, - typedImage, - size); + texture = new EGLImageTextureClient(GetForwarder(), + mTextureFlags, + typedImage, + size); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = static_cast(image); const SurfaceTextureImage::Data* data = typedImage->GetData(); - texture = new SurfaceTextureClient(mTextureFlags, data->mSurfTex, - size, data->mInverted); + texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags, + data->mSurfTex, size, + data->mInverted); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index b0702cc12e49..4c38bccad8e9 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -235,7 +235,7 @@ TextureClient::SetAddedToCompositableClient() bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) { - MOZ_ASSERT(aForwarder); + MOZ_ASSERT(aForwarder && aForwarder == mAllocator); if (mActor && mActor->GetForwarder() == aForwarder) { return true; } @@ -250,7 +250,6 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) MOZ_ASSERT(mActor); mActor->mForwarder = aForwarder; mActor->mTextureClient = this; - mAllocator = aForwarder; mShared = true; return mActor->IPCOpen(); } @@ -331,7 +330,7 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator, gfxWindowsPlatform::GetPlatform()->GetD2DDevice() && aSize.width <= maxTextureSize && aSize.height <= maxTextureSize) { - texture = new TextureClientD3D11(aFormat, aTextureFlags); + texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags); } if (parentBackend == LayersBackend::LAYERS_D3D9 && aMoz2DBackend == gfx::BackendType::CAIRO && @@ -339,14 +338,14 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator, aSize.width <= maxTextureSize && aSize.height <= maxTextureSize) { if (gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) { - texture = new CairoTextureClientD3D9(aFormat, aTextureFlags); + texture = new CairoTextureClientD3D9(aAllocator, aFormat, aTextureFlags); } } if (!texture && aFormat == SurfaceFormat::B8G8R8X8 && aAllocator->IsSameProcess() && aMoz2DBackend == gfx::BackendType::CAIRO) { - texture = new DIBTextureClient(aFormat, aTextureFlags); + texture = new DIBTextureClient(aAllocator, aFormat, aTextureFlags); } #endif @@ -479,8 +478,9 @@ TextureClient::CreateWithBufferSize(ISurfaceAllocator* aAllocator, return texture; } -TextureClient::TextureClient(TextureFlags aFlags) - : mFlags(aFlags) +TextureClient::TextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags) + : mAllocator(aAllocator) + , mFlags(aFlags) , mShared(false) , mValid(true) , mAddedToCompositableClient(false) @@ -710,8 +710,7 @@ BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend, TextureFlags aFlags) - : TextureClient(aFlags) - , mAllocator(aAllocator) + : TextureClient(aAllocator, aFlags) , mFormat(aFormat) , mBackend(aMoz2DBackend) , mOpenMode(OpenMode::OPEN_NONE) @@ -734,12 +733,6 @@ BufferTextureClient::CreateSimilar(TextureFlags aFlags, return newTex; } -ISurfaceAllocator* -BufferTextureClient::GetAllocator() const -{ - return mAllocator; -} - bool BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) { @@ -907,9 +900,10 @@ BufferTextureClient::GetAsSurface() //////////////////////////////////////////////////////////////////////// // SharedSurfaceTextureClient -SharedSurfaceTextureClient::SharedSurfaceTextureClient(TextureFlags aFlags, +SharedSurfaceTextureClient::SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, + TextureFlags aFlags, gl::SharedSurface* surf) - : TextureClient(aFlags) + : TextureClient(aAllocator, aFlags) , mIsLocked(false) , mSurf(surf) , mGL(mSurf->mGL) diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index bb520c8c217f..27e619560cb2 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -173,7 +173,8 @@ class TextureClient : public AtomicRefCountedWithFinalize { public: - explicit TextureClient(TextureFlags aFlags = TextureFlags::DEFAULT); + explicit TextureClient(ISurfaceAllocator* aAllocator, + TextureFlags aFlags = TextureFlags::DEFAULT); virtual ~TextureClient(); // Creates and allocates a TextureClient usable with Moz2D. @@ -602,15 +603,12 @@ public: virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; } - ISurfaceAllocator* GetAllocator() const; - virtual TemporaryRef CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT, TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const MOZ_OVERRIDE; protected: RefPtr mDrawTarget; - RefPtr mAllocator; gfx::SurfaceFormat mFormat; gfx::IntSize mSize; gfx::BackendType mBackend; @@ -689,7 +687,8 @@ protected: class SharedSurfaceTextureClient : public TextureClient { public: - SharedSurfaceTextureClient(TextureFlags aFlags, gl::SharedSurface* surf); + SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags, + gl::SharedSurface* surf); protected: ~SharedSurfaceTextureClient(); diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index db751944b4e9..cf54d23ee360 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -161,8 +161,10 @@ CreateTextureHostD3D11(const SurfaceDescriptor& aDesc, return result; } -TextureClientD3D11::TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags) - : TextureClient(aFlags) +TextureClientD3D11::TextureClientD3D11(ISurfaceAllocator* aAllocator, + gfx::SurfaceFormat aFormat, + TextureFlags aFlags) + : TextureClient(aAllocator, aFlags) , mFormat(aFormat) , mIsLocked(false) , mNeedsClear(false) @@ -205,7 +207,8 @@ TemporaryRef TextureClientD3D11::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { - RefPtr tex = new TextureClientD3D11(mFormat, mFlags | aFlags); + RefPtr tex = new TextureClientD3D11(mAllocator, mFormat, + mFlags | aFlags); if (!tex->AllocateForSurface(mSize, aAllocFlags)) { return nullptr; diff --git a/gfx/layers/d3d11/TextureD3D11.h b/gfx/layers/d3d11/TextureD3D11.h index ee6d22927c6f..cbf89093afea 100644 --- a/gfx/layers/d3d11/TextureD3D11.h +++ b/gfx/layers/d3d11/TextureD3D11.h @@ -28,7 +28,9 @@ class CompositorD3D11; class TextureClientD3D11 : public TextureClient { public: - TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags); + TextureClientD3D11(ISurfaceAllocator* aAllocator, + gfx::SurfaceFormat aFormat, + TextureFlags aFlags); virtual ~TextureClientD3D11(); diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp index e2fe0db27df5..30d8f2e4aef9 100644 --- a/gfx/layers/d3d9/TextureD3D9.cpp +++ b/gfx/layers/d3d9/TextureD3D9.cpp @@ -550,8 +550,10 @@ DataTextureSourceD3D9::GetTileRect() return ThebesIntRect(GetTileRect(mCurrentTile)); } -CairoTextureClientD3D9::CairoTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags) - : TextureClient(aFlags) +CairoTextureClientD3D9::CairoTextureClientD3D9(ISurfaceAllocator* aAllocator, + gfx::SurfaceFormat aFormat, + TextureFlags aFlags) + : TextureClient(aAllocator, aFlags) , mFormat(aFormat) , mIsLocked(false) , mNeedsClear(false) @@ -569,7 +571,8 @@ CairoTextureClientD3D9::~CairoTextureClientD3D9() TemporaryRef CairoTextureClientD3D9::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { - RefPtr tex = new CairoTextureClientD3D9(mFormat, mFlags | aFlags); + RefPtr tex = new CairoTextureClientD3D9(mAllocator, mFormat, + mFlags | aFlags); if (!tex->AllocateForSurface(mSize, aAllocFlags)) { return nullptr; @@ -722,8 +725,10 @@ CairoTextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocation return true; } -SharedTextureClientD3D9::SharedTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags) - : TextureClient(aFlags) +SharedTextureClientD3D9::SharedTextureClientD3D9(ISurfaceAllocator* aAllocator, + gfx::SurfaceFormat aFormat, + TextureFlags aFlags) + : TextureClient(aAllocator, aFlags) , mFormat(aFormat) , mHandle(0) , mIsLocked(false) diff --git a/gfx/layers/d3d9/TextureD3D9.h b/gfx/layers/d3d9/TextureD3D9.h index 76b80b092b34..19152145edd4 100644 --- a/gfx/layers/d3d9/TextureD3D9.h +++ b/gfx/layers/d3d9/TextureD3D9.h @@ -187,7 +187,8 @@ protected: class CairoTextureClientD3D9 : public TextureClient { public: - CairoTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags); + CairoTextureClientD3D9(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, + TextureFlags aFlags); virtual ~CairoTextureClientD3D9(); @@ -241,7 +242,9 @@ private: class SharedTextureClientD3D9 : public TextureClient { public: - SharedTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags); + SharedTextureClientD3D9(ISurfaceAllocator* aAllocator, + gfx::SurfaceFormat aFormat, + TextureFlags aFlags); virtual ~SharedTextureClientD3D9(); diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp index cdf9601f1bd1..1dd5b1e61690 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp @@ -9,8 +9,9 @@ namespace mozilla { namespace layers { -MacIOSurfaceTextureClientOGL::MacIOSurfaceTextureClientOGL(TextureFlags aFlags) - : TextureClient(aFlags) +MacIOSurfaceTextureClientOGL::MacIOSurfaceTextureClientOGL(ISurfaceAllocator* aAllcator, + TextureFlags aFlags) + : TextureClient(aAllcator, aFlags) , mIsLocked(false) {} diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h index e423ffc95995..6661f8dfeb61 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h @@ -16,7 +16,8 @@ namespace layers { class MacIOSurfaceTextureClientOGL : public TextureClient { public: - explicit MacIOSurfaceTextureClientOGL(TextureFlags aFlags); + explicit MacIOSurfaceTextureClientOGL(ISurfaceAllocator* aAllcator, + TextureFlags aFlags); virtual ~MacIOSurfaceTextureClientOGL(); diff --git a/gfx/layers/opengl/TextureClientOGL.cpp b/gfx/layers/opengl/TextureClientOGL.cpp index c37a3ffa5ebe..8aa64ed73457 100644 --- a/gfx/layers/opengl/TextureClientOGL.cpp +++ b/gfx/layers/opengl/TextureClientOGL.cpp @@ -20,10 +20,11 @@ class CompositableForwarder; //////////////////////////////////////////////////////////////////////// // EGLImageTextureClient -EGLImageTextureClient::EGLImageTextureClient(TextureFlags aFlags, +EGLImageTextureClient::EGLImageTextureClient(ISurfaceAllocator* aAllocator, + TextureFlags aFlags, EGLImageImage* aImage, gfx::IntSize aSize) - : TextureClient(aFlags) + : TextureClient(aAllocator, aFlags) , mImage(aImage) , mSize(aSize) , mIsLocked(false) @@ -72,11 +73,12 @@ EGLImageTextureClient::Unlock() #ifdef MOZ_WIDGET_ANDROID -SurfaceTextureClient::SurfaceTextureClient(TextureFlags aFlags, +SurfaceTextureClient::SurfaceTextureClient(ISurfaceAllocator* aAllocator, + TextureFlags aFlags, AndroidSurfaceTexture* aSurfTex, gfx::IntSize aSize, bool aInverted) - : TextureClient(aFlags) + : TextureClient(aAllocator, aFlags) , mSurfTex(aSurfTex) , mSize(aSize) , mIsLocked(false) diff --git a/gfx/layers/opengl/TextureClientOGL.h b/gfx/layers/opengl/TextureClientOGL.h index d54f520ae1ad..3130a0008e47 100644 --- a/gfx/layers/opengl/TextureClientOGL.h +++ b/gfx/layers/opengl/TextureClientOGL.h @@ -25,7 +25,8 @@ class CompositableForwarder; class EGLImageTextureClient : public TextureClient { public: - EGLImageTextureClient(TextureFlags aFlags, + EGLImageTextureClient(ISurfaceAllocator* aAllocator, + TextureFlags aFlags, EGLImageImage* aImage, gfx::IntSize aSize); @@ -72,7 +73,8 @@ protected: class SurfaceTextureClient : public TextureClient { public: - SurfaceTextureClient(TextureFlags aFlags, + SurfaceTextureClient(ISurfaceAllocator* aAllocator, + TextureFlags aFlags, gl::AndroidSurfaceTexture* aSurfTex, gfx::IntSize aSize, bool aInverted); From e1a327793ec0aa3fc0b2e7cdb44bb5833a573c81 Mon Sep 17 00:00:00 2001 From: Gervase Markham Date: Mon, 22 Dec 2014 06:23:00 -0500 Subject: [PATCH 43/64] Bug 1113728 - Add pagespeedmobilizer.com to PSL. r=gerv --- netwerk/dns/effective_tld_names.dat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat index 857110554315..06944edb5841 100644 --- a/netwerk/dns/effective_tld_names.dat +++ b/netwerk/dns/effective_tld_names.dat @@ -9233,7 +9233,7 @@ githubusercontent.com ro.com // Google, Inc. -// Submitted by Eduardo Vela 2012-10-24 +// Submitted by Eduardo Vela 2014-12-19 appspot.com blogspot.ae blogspot.be @@ -9281,6 +9281,7 @@ blogspot.tw codespot.com googleapis.com googlecode.com +pagespeedmobilizer.com withgoogle.com // Heroku : https://www.heroku.com/ From a62bb17df44139f493e05962e669eaa8c51a6ef1 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Wed, 17 Dec 2014 11:20:09 -0500 Subject: [PATCH 44/64] Bug 1113200 - Use sysconf to get the page size. r=dhylands --- hal/gonk/GonkHal.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index 69b40766f289..15a442da0847 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -27,11 +27,7 @@ #include #include #include -#if ANDROID_VERSION >= 21 -#include -#else -#include -#endif +#include #include "mozilla/DebugOnly.h" @@ -1321,6 +1317,8 @@ EnsureKernelLowMemKillerParamsSet() int32_t lowerBoundOfNextKillUnderKB = 0; int32_t countOfLowmemorykillerParametersSets = 0; + long page_size = sysconf(_SC_PAGESIZE); + for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) { // The system doesn't function correctly if we're missing these prefs, so // crash loudly. @@ -1358,7 +1356,7 @@ EnsureKernelLowMemKillerParamsSet() adjParams.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj)); // minfree is in pages. - minfreeParams.AppendPrintf("%d,", killUnderKB * 1024 / PAGE_SIZE); + minfreeParams.AppendPrintf("%ld,", killUnderKB * 1024 / page_size); lowerBoundOfNextOomScoreAdj = oomScoreAdj; lowerBoundOfNextKillUnderKB = killUnderKB; @@ -1381,7 +1379,7 @@ EnsureKernelLowMemKillerParamsSet() // notify_trigger is in pages. WriteToFile("/sys/module/lowmemorykiller/parameters/notify_trigger", - nsPrintfCString("%d", lowMemNotifyThresholdKB * 1024 / PAGE_SIZE).get()); + nsPrintfCString("%ld", lowMemNotifyThresholdKB * 1024 / page_size).get()); } // Ensure OOM events appear in logcat From 09d0025de03c926eb98890a5bf5c48926e05d166 Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Wed, 17 Dec 2014 16:06:14 +0100 Subject: [PATCH 45/64] Bug 1111607 - Searchplugins should be picked up from en-US, if possible. r=glandium --HG-- extra : transplant_source : %C9%23%D72%E7%EF%88%C8%1F%CFa_%1E%9B%0Cf%22%A0%BFu --- browser/locales/Makefile.in | 2 +- config/config.mk | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index 679c3ef0b67e..c7cb1a39413b 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -77,7 +77,7 @@ SEARCHPLUGINS_PATH := $(FINAL_TARGET)/searchplugins # metro build call a searchplugins target for search engine plugins .PHONY: searchplugins SEARCHPLUGINS_TARGET := libs searchplugins -SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_NAMES)),$(or $(wildcard $(call MERGE_FILE,searchplugins/$(plugin))),$(info Missing searchplugin: $(plugin)))) +SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_NAMES)),$(or $(wildcard $(call EN_US_OR_L10N_FILE,searchplugins/$(plugin))),$(info Missing searchplugin: $(plugin)))) # Some locale-specific search plugins may have preprocessor directives, but the # default en-US ones do not. SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings diff --git a/config/config.mk b/config/config.mk index 948a71af2092..141dda16fa5f 100644 --- a/config/config.mk +++ b/config/config.mk @@ -614,6 +614,13 @@ MERGE_FILE = $(LOCALE_SRCDIR)/$(1) endif MERGE_FILES = $(foreach f,$(1),$(call MERGE_FILE,$(f))) +# These marcros are similar to MERGE_FILE, but no merging, and en-US first. +# They're used for searchplugins, for example. +EN_US_OR_L10N_FILE = $(firstword \ + $(wildcard $(srcdir)/en-US/$(1)) \ + $(LOCALE_SRCDIR)/$(1) ) +EN_US_OR_L10N_FILES = $(foreach f,$(1),$(call EN_US_OR_L10N_FILE,$(f))) + ifneq (WINNT,$(OS_ARCH)) RUN_TEST_PROGRAM = $(LIBXUL_DIST)/bin/run-mozilla.sh endif # ! WINNT From e636229ac641b712ad000f218787aa8576c9c804 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Mon, 22 Dec 2014 07:05:19 -0800 Subject: [PATCH 46/64] Bug 1113769 - Handle out of gralloc in MediaEngineGonkVideoSource::RotateImage() r=jesup --- .../webrtc/MediaEngineGonkVideoSource.cpp | 116 ++++++++++++------ 1 file changed, 78 insertions(+), 38 deletions(-) diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp index a885ceb96675..4dcc4a39ee5c 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp @@ -691,40 +691,72 @@ MediaEngineGonkVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth, gfx::BackendType::NONE, layers::TextureFlags::DEFAULT, layers::ALLOC_DISALLOW_BUFFERTEXTURECLIENT); - if (!textureClient) { - return; + if (textureClient) { + RefPtr grallocTextureClient = + static_cast(textureClient.get()); + + android::sp destBuffer = grallocTextureClient->GetGraphicBuffer(); + + void* destMem = nullptr; + destBuffer->lock(android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destMem); + uint8_t* dstPtr = static_cast(destMem); + + int32_t yStride = destBuffer->getStride(); + // Align to 16 bytes boundary + int32_t uvStride = ((yStride / 2) + 15) & ~0x0F; + + libyuv::ConvertToI420(srcPtr, size, + dstPtr, yStride, + dstPtr + (yStride * dstHeight + (uvStride * dstHeight / 2)), uvStride, + dstPtr + (yStride * dstHeight), uvStride, + 0, 0, + aWidth, aHeight, + aWidth, aHeight, + static_cast(mRotation), + libyuv::FOURCC_NV21); + destBuffer->unlock(); + + layers::GrallocImage::GrallocData data; + + data.mPicSize = gfx::IntSize(dstWidth, dstHeight); + data.mGraphicBuffer = textureClient; + videoImage->SetData(data); + } else { + // Handle out of gralloc case. + image = mImageContainer->CreateImage(ImageFormat::PLANAR_YCBCR); + layers::PlanarYCbCrImage* videoImage = static_cast(image.get()); + uint8_t* dstPtr = videoImage->AllocateAndGetNewBuffer(size); + + libyuv::ConvertToI420(srcPtr, size, + dstPtr, dstWidth, + dstPtr + (dstWidth * dstHeight), half_width, + dstPtr + (dstWidth * dstHeight * 5 / 4), half_width, + 0, 0, + aWidth, aHeight, + aWidth, aHeight, + static_cast(mRotation), + ConvertPixelFormatToFOURCC(graphicBuffer->getPixelFormat())); + + const uint8_t lumaBpp = 8; + const uint8_t chromaBpp = 4; + + layers::PlanarYCbCrData data; + data.mYChannel = dstPtr; + data.mYSize = IntSize(dstWidth, dstHeight); + data.mYStride = dstWidth * lumaBpp / 8; + data.mCbCrStride = dstWidth * chromaBpp / 8; + data.mCbChannel = dstPtr + dstHeight * data.mYStride; + data.mCrChannel = data.mCbChannel + data.mCbCrStride * (dstHeight / 2); + data.mCbCrSize = IntSize(dstWidth / 2, dstHeight / 2); + data.mPicX = 0; + data.mPicY = 0; + data.mPicSize = IntSize(dstWidth, dstHeight); + data.mStereoMode = StereoMode::MONO; + + videoImage->SetDataNoCopy(data); } - RefPtr grallocTextureClient = - static_cast(textureClient.get()); - - android::sp destBuffer = grallocTextureClient->GetGraphicBuffer(); - - void* destMem = nullptr; - destBuffer->lock(android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destMem); - uint8_t* dstPtr = static_cast(destMem); - - int32_t yStride = destBuffer->getStride(); - // Align to 16 bytes boundary - int32_t uvStride = ((yStride / 2) + 15) & ~0x0F; - - libyuv::ConvertToI420(srcPtr, size, - dstPtr, yStride, - dstPtr + (yStride * dstHeight + (uvStride * dstHeight / 2)), uvStride, - dstPtr + (yStride * dstHeight), uvStride, - 0, 0, - aWidth, aHeight, - aWidth, aHeight, - static_cast(mRotation), - libyuv::FOURCC_NV21); - destBuffer->unlock(); graphicBuffer->unlock(); - layers::GrallocImage::GrallocData data; - - data.mPicSize = gfx::IntSize(dstWidth, dstHeight); - data.mGraphicBuffer = textureClient; - videoImage->SetData(data); - // Implicitly releases last preview image. mImage = image.forget(); } @@ -767,9 +799,14 @@ MediaEngineGonkVideoSource::OnNewMediaBufferFrame(MediaBuffer* aBuffer) MonitorAutoLock enter(mMonitor); if (mImage) { - GonkCameraImage* cameraImage = static_cast(mImage.get()); - - cameraImage->SetBuffer(aBuffer); + if (mImage->AsGrallocImage()) { + // MediaEngineGonkVideoSource expects that GrallocImage is GonkCameraImage. + // See Bug 938034. + GonkCameraImage* cameraImage = static_cast(mImage.get()); + cameraImage->SetBuffer(aBuffer); + } else { + LOG(("mImage is non-GrallocImage")); + } uint32_t len = mSources.Length(); for (uint32_t i = 0; i < len; i++) { @@ -780,12 +817,15 @@ MediaEngineGonkVideoSource::OnNewMediaBufferFrame(MediaBuffer* aBuffer) // Unfortunately, clock in gonk camera looks like is a different one // comparing to MSG. As result, it causes time inaccurate. (frames be // queued in MSG longer and longer as time going by in device like Frame) - AppendToTrack(mSources[i], cameraImage, mTrackID, 1); + AppendToTrack(mSources[i], mImage, mTrackID, 1); } } - // Clear MediaBuffer immediately, it prevents MediaBuffer is kept in - // MediaStreamGraph thread. - cameraImage->ClearBuffer(); + if (mImage->AsGrallocImage()) { + GonkCameraImage* cameraImage = static_cast(mImage.get()); + // Clear MediaBuffer immediately, it prevents MediaBuffer is kept in + // MediaStreamGraph thread. + cameraImage->ClearBuffer(); + } } return NS_OK; From c2194dba73c14aa40e9868b54a43a47481d47492 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 22 Dec 2014 08:54:55 -0500 Subject: [PATCH 47/64] Bug 1114348 - Use mozilla::IsNaN() in Web Audio code; r=padenot --HG-- extra : rebase_source : 0acc0643ed6a8800d02557f6e84312955e34a59e --- dom/media/webaudio/AudioBufferSourceNode.cpp | 5 +++-- dom/media/webaudio/WebAudioUtils.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dom/media/webaudio/AudioBufferSourceNode.cpp b/dom/media/webaudio/AudioBufferSourceNode.cpp index cd8df5566c47..ceed1a3988c7 100644 --- a/dom/media/webaudio/AudioBufferSourceNode.cpp +++ b/dom/media/webaudio/AudioBufferSourceNode.cpp @@ -7,6 +7,7 @@ #include "AudioBufferSourceNode.h" #include "mozilla/dom/AudioBufferSourceNodeBinding.h" #include "mozilla/dom/AudioParam.h" +#include "mozilla/FloatingPoint.h" #include "nsMathUtils.h" #include "AudioNodeEngine.h" #include "AudioNodeStream.h" @@ -110,7 +111,7 @@ public: mBeginProcessing = mStart + 0.5; break; case AudioBufferSourceNode::DOPPLERSHIFT: - mDopplerShift = aParam > 0 && aParam == aParam ? aParam : 1.0; + mDopplerShift = (aParam <= 0 || mozilla::IsNaN(aParam)) ? 1.0 : aParam; break; default: NS_ERROR("Bad AudioBufferSourceNodeEngine double parameter."); @@ -415,7 +416,7 @@ public: } else { playbackRate = mPlaybackRateTimeline.GetValueAtTime(mSource->GetCurrentPosition()); } - if (playbackRate <= 0 || playbackRate != playbackRate) { + if (playbackRate <= 0 || mozilla::IsNaN(playbackRate)) { playbackRate = 1.0f; } diff --git a/dom/media/webaudio/WebAudioUtils.h b/dom/media/webaudio/WebAudioUtils.h index ee22ea07e21d..baaa373535c8 100644 --- a/dom/media/webaudio/WebAudioUtils.h +++ b/dom/media/webaudio/WebAudioUtils.h @@ -181,7 +181,7 @@ namespace WebAudioUtils { static_assert(mozilla::IsFloatingPoint::value == true, "FloatType must be a floating point type"); - if (f != f) { + if (mozilla::IsNaN(f)) { // It is the responsibility of the caller to deal with NaN values. // If we ever get to this point, we have a serious bug to fix. NS_RUNTIMEABORT("We should never see a NaN here"); From b51b5f560160be1dbdfec7c8ea08437ba85c26ee Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 22 Dec 2014 11:15:36 -0500 Subject: [PATCH 48/64] Backed out changeset dd9790020b89 (bug 1042696) for B2G debug crashes. --- gfx/layers/D3D9SurfaceImage.cpp | 6 +--- gfx/layers/MacIOSurfaceImage.cpp | 4 +-- gfx/layers/TextureDIB.cpp | 9 ++---- gfx/layers/TextureDIB.h | 4 +-- gfx/layers/basic/TextureClientX11.cpp | 7 ++--- gfx/layers/basic/TextureClientX11.h | 1 + gfx/layers/client/CanvasClient.cpp | 7 ++--- gfx/layers/client/ImageClient.cpp | 12 ++++---- gfx/layers/client/TextureClient.cpp | 28 +++++++++++-------- gfx/layers/client/TextureClient.h | 9 +++--- gfx/layers/d3d11/TextureD3D11.cpp | 9 ++---- gfx/layers/d3d11/TextureD3D11.h | 4 +-- gfx/layers/d3d9/TextureD3D9.cpp | 15 ++++------ gfx/layers/d3d9/TextureD3D9.h | 7 ++--- .../opengl/MacIOSurfaceTextureClientOGL.cpp | 5 ++-- .../opengl/MacIOSurfaceTextureClientOGL.h | 3 +- gfx/layers/opengl/TextureClientOGL.cpp | 10 +++---- gfx/layers/opengl/TextureClientOGL.h | 6 ++-- 18 files changed, 60 insertions(+), 86 deletions(-) diff --git a/gfx/layers/D3D9SurfaceImage.cpp b/gfx/layers/D3D9SurfaceImage.cpp index 9a7efd29ac29..08b97050f264 100644 --- a/gfx/layers/D3D9SurfaceImage.cpp +++ b/gfx/layers/D3D9SurfaceImage.cpp @@ -6,8 +6,6 @@ #include "D3D9SurfaceImage.h" #include "gfx2DGlue.h" #include "mozilla/layers/TextureD3D9.h" -#include "mozilla/layers/CompositableClient.h" -#include "mozilla/layers/CompositableForwarder.h" #include "mozilla/gfx/Types.h" namespace mozilla { @@ -134,9 +132,7 @@ D3D9SurfaceImage::GetTextureClient(CompositableClient* aClient) EnsureSynchronized(); if (!mTextureClient) { RefPtr textureClient = - new SharedTextureClientD3D9(aClient->GetForwarder(), - gfx::SurfaceFormat::B8G8R8X8, - TextureFlags::DEFAULT); + new SharedTextureClientD3D9(gfx::SurfaceFormat::B8G8R8X8, TextureFlags::DEFAULT); textureClient->InitWith(mTexture, mShareHandle, mDesc); mTextureClient = textureClient; } diff --git a/gfx/layers/MacIOSurfaceImage.cpp b/gfx/layers/MacIOSurfaceImage.cpp index 000a308686ca..c8f78afef77b 100644 --- a/gfx/layers/MacIOSurfaceImage.cpp +++ b/gfx/layers/MacIOSurfaceImage.cpp @@ -4,8 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MacIOSurfaceImage.h" -#include "mozilla/layers/CompositableClient.h" -#include "mozilla/layers/CompositableForwarder.h" #include "mozilla/layers/MacIOSurfaceTextureClientOGL.h" using namespace mozilla; @@ -16,7 +14,7 @@ MacIOSurfaceImage::GetTextureClient(CompositableClient* aClient) { if (!mTextureClient) { RefPtr buffer = - new MacIOSurfaceTextureClientOGL(aClient->GetForwarder(), TextureFlags::DEFAULT); + new MacIOSurfaceTextureClientOGL(TextureFlags::DEFAULT); buffer->InitWith(mSurface); mTextureClient = buffer; } diff --git a/gfx/layers/TextureDIB.cpp b/gfx/layers/TextureDIB.cpp index 8ad883717d59..497a2c9c570f 100644 --- a/gfx/layers/TextureDIB.cpp +++ b/gfx/layers/TextureDIB.cpp @@ -12,10 +12,8 @@ using namespace gfx; namespace layers { -DIBTextureClient::DIBTextureClient(ISurfaceAllocator* aAllocator, - gfx::SurfaceFormat aFormat, - TextureFlags aFlags) - : TextureClient(aAllocator, aFlags) +DIBTextureClient::DIBTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags) + : TextureClient(aFlags) , mFormat(aFormat) , mIsLocked(false) { @@ -31,8 +29,7 @@ TemporaryRef DIBTextureClient::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { - RefPtr tex = new DIBTextureClient(mAllocator, mFormat, - mFlags | aFlags); + RefPtr tex = new DIBTextureClient(mFormat, mFlags | aFlags); if (!tex->AllocateForSurface(mSize, aAllocFlags)) { return nullptr; diff --git a/gfx/layers/TextureDIB.h b/gfx/layers/TextureDIB.h index 27df1e93a704..f093405c5cec 100644 --- a/gfx/layers/TextureDIB.h +++ b/gfx/layers/TextureDIB.h @@ -23,9 +23,7 @@ namespace layers { class DIBTextureClient : public TextureClient { public: - DIBTextureClient(ISurfaceAllocator* aAllocator, - gfx::SurfaceFormat aFormat, - TextureFlags aFlags); + DIBTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags); virtual ~DIBTextureClient(); diff --git a/gfx/layers/basic/TextureClientX11.cpp b/gfx/layers/basic/TextureClientX11.cpp index 6d752b82cbbf..2f379c5976bb 100644 --- a/gfx/layers/basic/TextureClientX11.cpp +++ b/gfx/layers/basic/TextureClientX11.cpp @@ -19,11 +19,10 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::layers; -TextureClientX11::TextureClientX11(ISurfaceAllocator* aAllocator, - SurfaceFormat aFormat, - TextureFlags aFlags) - : TextureClient(aAllocator, aFlags), +TextureClientX11::TextureClientX11(ISurfaceAllocator* aAllocator, SurfaceFormat aFormat, TextureFlags aFlags) + : TextureClient(aFlags), mFormat(aFormat), + mAllocator(aAllocator), mLocked(false) { MOZ_COUNT_CTOR(TextureClientX11); diff --git a/gfx/layers/basic/TextureClientX11.h b/gfx/layers/basic/TextureClientX11.h index 3ae4f808a1a0..b0e53ddcd9ac 100644 --- a/gfx/layers/basic/TextureClientX11.h +++ b/gfx/layers/basic/TextureClientX11.h @@ -55,6 +55,7 @@ class TextureClientX11 : public TextureClient gfx::SurfaceFormat mFormat; gfx::IntSize mSize; RefPtr mSurface; + RefPtr mAllocator; RefPtr mDrawTarget; bool mLocked; }; diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index a4435c2b7a96..ee4a7456736b 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -155,8 +155,7 @@ CanvasClientSharedSurface::CanvasClientSharedSurface(CompositableForwarder* aLay // Accelerated backends static TemporaryRef -TexClientFromShSurf(ISurfaceAllocator* aAllocator, SharedSurface* surf, - TextureFlags flags) +TexClientFromShSurf(SharedSurface* surf, TextureFlags flags) { switch (surf->mType) { case SharedSurfaceType::Basic: @@ -168,7 +167,7 @@ TexClientFromShSurf(ISurfaceAllocator* aAllocator, SharedSurface* surf, #endif default: - return new SharedSurfaceTextureClient(aAllocator, flags, surf); + return new SharedSurfaceTextureClient(flags, surf); } } @@ -365,7 +364,7 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) auto flags = GetTextureFlags() | TextureFlags::IMMUTABLE; // Get a TexClient from our surf. - RefPtr newTex = TexClientFromShSurf(GetForwarder(), surf, flags); + RefPtr newTex = TexClientFromShSurf(surf, flags); if (!newTex) { auto manager = aLayer->ClientManager(); auto shadowForwarder = manager->AsShadowForwarder(); diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index ec6b438d79e5..de76542717a6 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -192,17 +192,15 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = static_cast(image); - texture = new EGLImageTextureClient(GetForwarder(), - mTextureFlags, - typedImage, - size); + texture = new EGLImageTextureClient(mTextureFlags, + typedImage, + size); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = static_cast(image); const SurfaceTextureImage::Data* data = typedImage->GetData(); - texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags, - data->mSurfTex, size, - data->mInverted); + texture = new SurfaceTextureClient(mTextureFlags, data->mSurfTex, + size, data->mInverted); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 4c38bccad8e9..b0702cc12e49 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -235,7 +235,7 @@ TextureClient::SetAddedToCompositableClient() bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) { - MOZ_ASSERT(aForwarder && aForwarder == mAllocator); + MOZ_ASSERT(aForwarder); if (mActor && mActor->GetForwarder() == aForwarder) { return true; } @@ -250,6 +250,7 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) MOZ_ASSERT(mActor); mActor->mForwarder = aForwarder; mActor->mTextureClient = this; + mAllocator = aForwarder; mShared = true; return mActor->IPCOpen(); } @@ -330,7 +331,7 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator, gfxWindowsPlatform::GetPlatform()->GetD2DDevice() && aSize.width <= maxTextureSize && aSize.height <= maxTextureSize) { - texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags); + texture = new TextureClientD3D11(aFormat, aTextureFlags); } if (parentBackend == LayersBackend::LAYERS_D3D9 && aMoz2DBackend == gfx::BackendType::CAIRO && @@ -338,14 +339,14 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator, aSize.width <= maxTextureSize && aSize.height <= maxTextureSize) { if (gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) { - texture = new CairoTextureClientD3D9(aAllocator, aFormat, aTextureFlags); + texture = new CairoTextureClientD3D9(aFormat, aTextureFlags); } } if (!texture && aFormat == SurfaceFormat::B8G8R8X8 && aAllocator->IsSameProcess() && aMoz2DBackend == gfx::BackendType::CAIRO) { - texture = new DIBTextureClient(aAllocator, aFormat, aTextureFlags); + texture = new DIBTextureClient(aFormat, aTextureFlags); } #endif @@ -478,9 +479,8 @@ TextureClient::CreateWithBufferSize(ISurfaceAllocator* aAllocator, return texture; } -TextureClient::TextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags) - : mAllocator(aAllocator) - , mFlags(aFlags) +TextureClient::TextureClient(TextureFlags aFlags) + : mFlags(aFlags) , mShared(false) , mValid(true) , mAddedToCompositableClient(false) @@ -710,7 +710,8 @@ BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend, TextureFlags aFlags) - : TextureClient(aAllocator, aFlags) + : TextureClient(aFlags) + , mAllocator(aAllocator) , mFormat(aFormat) , mBackend(aMoz2DBackend) , mOpenMode(OpenMode::OPEN_NONE) @@ -733,6 +734,12 @@ BufferTextureClient::CreateSimilar(TextureFlags aFlags, return newTex; } +ISurfaceAllocator* +BufferTextureClient::GetAllocator() const +{ + return mAllocator; +} + bool BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) { @@ -900,10 +907,9 @@ BufferTextureClient::GetAsSurface() //////////////////////////////////////////////////////////////////////// // SharedSurfaceTextureClient -SharedSurfaceTextureClient::SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, - TextureFlags aFlags, +SharedSurfaceTextureClient::SharedSurfaceTextureClient(TextureFlags aFlags, gl::SharedSurface* surf) - : TextureClient(aAllocator, aFlags) + : TextureClient(aFlags) , mIsLocked(false) , mSurf(surf) , mGL(mSurf->mGL) diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 27e619560cb2..bb520c8c217f 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -173,8 +173,7 @@ class TextureClient : public AtomicRefCountedWithFinalize { public: - explicit TextureClient(ISurfaceAllocator* aAllocator, - TextureFlags aFlags = TextureFlags::DEFAULT); + explicit TextureClient(TextureFlags aFlags = TextureFlags::DEFAULT); virtual ~TextureClient(); // Creates and allocates a TextureClient usable with Moz2D. @@ -603,12 +602,15 @@ public: virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return true; } + ISurfaceAllocator* GetAllocator() const; + virtual TemporaryRef CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT, TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const MOZ_OVERRIDE; protected: RefPtr mDrawTarget; + RefPtr mAllocator; gfx::SurfaceFormat mFormat; gfx::IntSize mSize; gfx::BackendType mBackend; @@ -687,8 +689,7 @@ protected: class SharedSurfaceTextureClient : public TextureClient { public: - SharedSurfaceTextureClient(ISurfaceAllocator* aAllocator, TextureFlags aFlags, - gl::SharedSurface* surf); + SharedSurfaceTextureClient(TextureFlags aFlags, gl::SharedSurface* surf); protected: ~SharedSurfaceTextureClient(); diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index cf54d23ee360..db751944b4e9 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -161,10 +161,8 @@ CreateTextureHostD3D11(const SurfaceDescriptor& aDesc, return result; } -TextureClientD3D11::TextureClientD3D11(ISurfaceAllocator* aAllocator, - gfx::SurfaceFormat aFormat, - TextureFlags aFlags) - : TextureClient(aAllocator, aFlags) +TextureClientD3D11::TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags) + : TextureClient(aFlags) , mFormat(aFormat) , mIsLocked(false) , mNeedsClear(false) @@ -207,8 +205,7 @@ TemporaryRef TextureClientD3D11::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { - RefPtr tex = new TextureClientD3D11(mAllocator, mFormat, - mFlags | aFlags); + RefPtr tex = new TextureClientD3D11(mFormat, mFlags | aFlags); if (!tex->AllocateForSurface(mSize, aAllocFlags)) { return nullptr; diff --git a/gfx/layers/d3d11/TextureD3D11.h b/gfx/layers/d3d11/TextureD3D11.h index cbf89093afea..ee6d22927c6f 100644 --- a/gfx/layers/d3d11/TextureD3D11.h +++ b/gfx/layers/d3d11/TextureD3D11.h @@ -28,9 +28,7 @@ class CompositorD3D11; class TextureClientD3D11 : public TextureClient { public: - TextureClientD3D11(ISurfaceAllocator* aAllocator, - gfx::SurfaceFormat aFormat, - TextureFlags aFlags); + TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags); virtual ~TextureClientD3D11(); diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp index 30d8f2e4aef9..e2fe0db27df5 100644 --- a/gfx/layers/d3d9/TextureD3D9.cpp +++ b/gfx/layers/d3d9/TextureD3D9.cpp @@ -550,10 +550,8 @@ DataTextureSourceD3D9::GetTileRect() return ThebesIntRect(GetTileRect(mCurrentTile)); } -CairoTextureClientD3D9::CairoTextureClientD3D9(ISurfaceAllocator* aAllocator, - gfx::SurfaceFormat aFormat, - TextureFlags aFlags) - : TextureClient(aAllocator, aFlags) +CairoTextureClientD3D9::CairoTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags) + : TextureClient(aFlags) , mFormat(aFormat) , mIsLocked(false) , mNeedsClear(false) @@ -571,8 +569,7 @@ CairoTextureClientD3D9::~CairoTextureClientD3D9() TemporaryRef CairoTextureClientD3D9::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { - RefPtr tex = new CairoTextureClientD3D9(mAllocator, mFormat, - mFlags | aFlags); + RefPtr tex = new CairoTextureClientD3D9(mFormat, mFlags | aFlags); if (!tex->AllocateForSurface(mSize, aAllocFlags)) { return nullptr; @@ -725,10 +722,8 @@ CairoTextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocation return true; } -SharedTextureClientD3D9::SharedTextureClientD3D9(ISurfaceAllocator* aAllocator, - gfx::SurfaceFormat aFormat, - TextureFlags aFlags) - : TextureClient(aAllocator, aFlags) +SharedTextureClientD3D9::SharedTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags) + : TextureClient(aFlags) , mFormat(aFormat) , mHandle(0) , mIsLocked(false) diff --git a/gfx/layers/d3d9/TextureD3D9.h b/gfx/layers/d3d9/TextureD3D9.h index 19152145edd4..76b80b092b34 100644 --- a/gfx/layers/d3d9/TextureD3D9.h +++ b/gfx/layers/d3d9/TextureD3D9.h @@ -187,8 +187,7 @@ protected: class CairoTextureClientD3D9 : public TextureClient { public: - CairoTextureClientD3D9(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, - TextureFlags aFlags); + CairoTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags); virtual ~CairoTextureClientD3D9(); @@ -242,9 +241,7 @@ private: class SharedTextureClientD3D9 : public TextureClient { public: - SharedTextureClientD3D9(ISurfaceAllocator* aAllocator, - gfx::SurfaceFormat aFormat, - TextureFlags aFlags); + SharedTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags); virtual ~SharedTextureClientD3D9(); diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp index 1dd5b1e61690..cdf9601f1bd1 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp @@ -9,9 +9,8 @@ namespace mozilla { namespace layers { -MacIOSurfaceTextureClientOGL::MacIOSurfaceTextureClientOGL(ISurfaceAllocator* aAllcator, - TextureFlags aFlags) - : TextureClient(aAllcator, aFlags) +MacIOSurfaceTextureClientOGL::MacIOSurfaceTextureClientOGL(TextureFlags aFlags) + : TextureClient(aFlags) , mIsLocked(false) {} diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h index 6661f8dfeb61..e423ffc95995 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h @@ -16,8 +16,7 @@ namespace layers { class MacIOSurfaceTextureClientOGL : public TextureClient { public: - explicit MacIOSurfaceTextureClientOGL(ISurfaceAllocator* aAllcator, - TextureFlags aFlags); + explicit MacIOSurfaceTextureClientOGL(TextureFlags aFlags); virtual ~MacIOSurfaceTextureClientOGL(); diff --git a/gfx/layers/opengl/TextureClientOGL.cpp b/gfx/layers/opengl/TextureClientOGL.cpp index 8aa64ed73457..c37a3ffa5ebe 100644 --- a/gfx/layers/opengl/TextureClientOGL.cpp +++ b/gfx/layers/opengl/TextureClientOGL.cpp @@ -20,11 +20,10 @@ class CompositableForwarder; //////////////////////////////////////////////////////////////////////// // EGLImageTextureClient -EGLImageTextureClient::EGLImageTextureClient(ISurfaceAllocator* aAllocator, - TextureFlags aFlags, +EGLImageTextureClient::EGLImageTextureClient(TextureFlags aFlags, EGLImageImage* aImage, gfx::IntSize aSize) - : TextureClient(aAllocator, aFlags) + : TextureClient(aFlags) , mImage(aImage) , mSize(aSize) , mIsLocked(false) @@ -73,12 +72,11 @@ EGLImageTextureClient::Unlock() #ifdef MOZ_WIDGET_ANDROID -SurfaceTextureClient::SurfaceTextureClient(ISurfaceAllocator* aAllocator, - TextureFlags aFlags, +SurfaceTextureClient::SurfaceTextureClient(TextureFlags aFlags, AndroidSurfaceTexture* aSurfTex, gfx::IntSize aSize, bool aInverted) - : TextureClient(aAllocator, aFlags) + : TextureClient(aFlags) , mSurfTex(aSurfTex) , mSize(aSize) , mIsLocked(false) diff --git a/gfx/layers/opengl/TextureClientOGL.h b/gfx/layers/opengl/TextureClientOGL.h index 3130a0008e47..d54f520ae1ad 100644 --- a/gfx/layers/opengl/TextureClientOGL.h +++ b/gfx/layers/opengl/TextureClientOGL.h @@ -25,8 +25,7 @@ class CompositableForwarder; class EGLImageTextureClient : public TextureClient { public: - EGLImageTextureClient(ISurfaceAllocator* aAllocator, - TextureFlags aFlags, + EGLImageTextureClient(TextureFlags aFlags, EGLImageImage* aImage, gfx::IntSize aSize); @@ -73,8 +72,7 @@ protected: class SurfaceTextureClient : public TextureClient { public: - SurfaceTextureClient(ISurfaceAllocator* aAllocator, - TextureFlags aFlags, + SurfaceTextureClient(TextureFlags aFlags, gl::AndroidSurfaceTexture* aSurfTex, gfx::IntSize aSize, bool aInverted); From 3b25572bdef719a7b56a04b012528f4da3c10ae0 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 22 Dec 2014 17:39:36 +0100 Subject: [PATCH 49/64] Bug 1114336 - Fix typo in UpdateFromCompositorFrameMetrics. r=kats --- gfx/layers/client/TiledContentClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 2795f2d7a5d9..0b4cf6ed6042 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -216,7 +216,7 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics( fabsf(contentMetrics.mDisplayPort.x - compositorMetrics.mDisplayPort.x) <= 2 && fabsf(contentMetrics.mDisplayPort.y - compositorMetrics.mDisplayPort.y) <= 2 && fabsf(contentMetrics.mDisplayPort.width - compositorMetrics.mDisplayPort.width) <= 2 && - fabsf(contentMetrics.mDisplayPort.height - compositorMetrics.mDisplayPort.height)) { + fabsf(contentMetrics.mDisplayPort.height - compositorMetrics.mDisplayPort.height) <= 2) { return false; } From 4ab4a2e4147f6a1b64a2fbf928ee392b12371f71 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Mon, 15 Dec 2014 13:00:13 -0500 Subject: [PATCH 50/64] bug 1111217 - Http2Session::CloseTransaction can delete this while on stack from OnMsgCancelTransaction r=hurley --- netwerk/protocol/http/nsHttpConnectionMgr.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 7a46a22448ef..750dfafea8ba 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -2377,13 +2377,15 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param) LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param)); nsresult closeCode = static_cast(reason); - nsHttpTransaction *trans = (nsHttpTransaction *) param; + nsRefPtr trans = + dont_AddRef(static_cast(param)); + // // if the transaction owns a connection and the transaction is not done, // then ask the connection to close the transaction. otherwise, close the // transaction directly (removing it from the pending queue first). // - nsAHttpConnection *conn = trans->Connection(); + nsRefPtr conn(trans->Connection()); if (conn && !trans->IsDone()) { conn->CloseTransaction(trans, closeCode); } else { @@ -2394,7 +2396,7 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param) int32_t index = ent->mPendingQ.IndexOf(trans); if (index >= 0) { LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]" - " found in pending queue\n", trans)); + " found in pending queue\n", trans.get())); ent->mPendingQ.RemoveElementAt(index); nsHttpTransaction *temp = trans; NS_RELEASE(temp); // b/c NS_RELEASE nulls its argument! @@ -2429,12 +2431,11 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param) if (liveTransaction && liveTransaction->IsNullTransaction()) { LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p] " "also canceling Null Transaction %p on conn %p\n", - trans, liveTransaction, activeConn)); + trans.get(), liveTransaction, activeConn)); activeConn->CloseTransaction(liveTransaction, closeCode); } } } - NS_RELEASE(trans); } void From afbba9218fd93a6e560edfd99e9a46509ce011ec Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Tue, 16 Dec 2014 11:21:11 -0500 Subject: [PATCH 51/64] Bug 1066383, rework custom html menu item handling to support contextmenu attribute in separate process, r=janv,mconley,peterv --- b2g/installer/package-manifest.in | 2 + browser/base/content/browser.js | 4 +- browser/base/content/content.js | 12 +- browser/base/content/nsContextMenu.js | 15 +- browser/base/content/tabbrowser.xml | 1 + browser/base/content/test/general/browser.ini | 2 + .../browser_contextmenu_childprocess.js | 87 ++++++ .../test/general/test_contextmenu.html | 2 +- browser/installer/package-manifest.in | 2 + dom/html/HTMLMenuElement.cpp | 17 +- dom/html/htmlMenuBuilder.js | 132 +++++++++ dom/html/htmlMenuBuilder.manifest | 3 + dom/html/moz.build | 5 + dom/html/nsIMenuBuilder.idl | 26 +- dom/webidl/HTMLMenuElement.webidl | 6 +- dom/xul/moz.build | 2 - dom/xul/nsIXULContextMenuBuilder.idl | 38 --- dom/xul/nsXULContextMenuBuilder.cpp | 230 --------------- dom/xul/nsXULContextMenuBuilder.h | 51 ---- mobile/android/installer/package-manifest.in | 2 + toolkit/modules/PageMenu.jsm | 266 ++++++++++++++---- 21 files changed, 515 insertions(+), 390 deletions(-) create mode 100644 browser/base/content/test/general/browser_contextmenu_childprocess.js create mode 100644 dom/html/htmlMenuBuilder.js create mode 100644 dom/html/htmlMenuBuilder.manifest delete mode 100644 dom/xul/nsIXULContextMenuBuilder.idl delete mode 100644 dom/xul/nsXULContextMenuBuilder.cpp delete mode 100644 dom/xul/nsXULContextMenuBuilder.h diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 59ace3c21438..024bbc6d7b06 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -401,6 +401,8 @@ @BINPATH@/components/nsSidebar.js @BINPATH@/components/nsAsyncShutdown.manifest @BINPATH@/components/nsAsyncShutdown.js +@BINPATH@/components/htmlMenuBuilder.js +@BINPATH@/components/htmlMenuBuilder.manifest ; WiFi, NetworkManager, NetworkStats #ifdef MOZ_WIDGET_GONK diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index d6e4b1de03a3..c886033e57ed 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -259,10 +259,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter", "nsICrashReporter"); #endif -XPCOMUtils.defineLazyGetter(this, "PageMenu", function() { +XPCOMUtils.defineLazyGetter(this, "PageMenuParent", function() { let tmp = {}; Cu.import("resource://gre/modules/PageMenu.jsm", tmp); - return new tmp.PageMenu(); + return new tmp.PageMenuParent(); }); /** diff --git a/browser/base/content/content.js b/browser/base/content/content.js index b2356a6fe4e7..9fc0fd64847e 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -43,6 +43,11 @@ XPCOMUtils.defineLazyGetter(this, "SimpleServiceDiscovery", function() { }); return ssdp; }); +XPCOMUtils.defineLazyGetter(this, "PageMenuChild", function() { + let tmp = {}; + Cu.import("resource://gre/modules/PageMenu.jsm", tmp); + return new tmp.PageMenuChild(); +}); // TabChildGlobal var global = this; @@ -102,6 +107,10 @@ addMessageListener("SecondScreen:tab-mirror", function(message) { } }); +addMessageListener("ContextMenu:DoCustomCommand", function(message) { + PageMenuChild.executeMenu(message.data); +}); + addEventListener("DOMFormHasPassword", function(event) { InsecurePasswordUtils.checkForInsecurePasswords(event.target); LoginManagerContent.onFormPassword(event); @@ -148,7 +157,8 @@ let handleContentContextMenu = function (event) { InlineSpellCheckerContent.initContextMenu(event, editFlags, this); } - sendSyncMessage("contextmenu", { editFlags, spellInfo, addonInfo }, { event, popupNode: event.target }); + let customMenuItems = PageMenuChild.build(event.target); + sendSyncMessage("contextmenu", { editFlags, spellInfo, customMenuItems, addonInfo }, { event, popupNode: event.target }); } else { // Break out to the parent window and pass the add-on info along diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 4dc54af0cdcc..196882fd942f 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -24,10 +24,15 @@ nsContextMenu.prototype = { return; this.hasPageMenu = false; - // FIXME (bug 1047751) - The page menu is disabled in e10s. - if (!aIsShift && !this.isRemote) { - this.hasPageMenu = PageMenu.maybeBuildAndAttachMenu(this.target, - aXulMenu); + if (!aIsShift) { + if (this.isRemote) { + this.hasPageMenu = + PageMenuParent.addToPopup(gContextMenuContentData.customMenuItems, + this.browser, aXulMenu); + } + else { + this.hasPageMenu = PageMenuParent.buildAndAddToPopup(this.target, aXulMenu); + } } this.isFrameImage = document.getElementById("isFrameImage"); @@ -1766,7 +1771,7 @@ nsContextMenu.prototype = { } // Check if this is a page menu item: - if (e.target.hasAttribute(PageMenu.GENERATEDITEMID_ATTR)) { + if (e.target.hasAttribute(PageMenuParent.GENERATEDITEMID_ATTR)) { this._telemetryClickID = "custom-page-item"; } else { this._telemetryClickID = (e.target.id || "unknown").replace(/^context-/i, ""); diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index b081551681c6..87d36f9722f0 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3175,6 +3175,7 @@ browser: browser, editFlags: aMessage.data.editFlags, spellInfo: spellInfo, + customMenuItems: aMessage.data.customMenuItems, addonInfo: aMessage.data.addonInfo }; let popup = browser.ownerDocument.getElementById("contentAreaContextMenu"); let event = gContextMenuContentData.event; diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 7322e5b95d66..a1232ad10570 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -72,6 +72,7 @@ support-files = redirect_bug623155.sjs searchSuggestionEngine.sjs searchSuggestionEngine.xml + subtst_contextmenu.html test-mixedcontent-securityerrors.html test_bug435035.html test_bug462673.html @@ -486,4 +487,5 @@ skip-if = e10s # bug 1100687 - test directly manipulates content (content.docume [browser_mcb_redirect.js] skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account [browser_windowactivation.js] +[browser_contextmenu_childprocess.js] [browser_bug963945.js] diff --git a/browser/base/content/test/general/browser_contextmenu_childprocess.js b/browser/base/content/test/general/browser_contextmenu_childprocess.js new file mode 100644 index 000000000000..c967137919ff --- /dev/null +++ b/browser/base/content/test/general/browser_contextmenu_childprocess.js @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const gBaseURL = "https://example.com/browser/browser/base/content/test/general/"; + +add_task(function *() { + let tab = gBrowser.addTab(); + let browser = gBrowser.getBrowserForTab(tab); + + gBrowser.selectedTab = tab; + yield promiseTabLoadEvent(tab, gBaseURL + "subtst_contextmenu.html"); + + let popupShownPromise = promiseWaitForEvent(window, "popupshown", true); + + // Get the point of the element with the page menu (test-pagemenu) and + // synthesize a right mouse click there. + let eventDetails = { type : "contextmenu", button : 2 }; + let rect = browser.contentWindow.document.getElementById("test-pagemenu").getBoundingClientRect(); + EventUtils.synthesizeMouse(browser, rect.x + rect.width / 2, rect.y + rect.height / 2, eventDetails, window); + + let event = yield popupShownPromise; + + let contextMenu = document.getElementById("contentAreaContextMenu"); + checkMenu(contextMenu); + contextMenu.hidePopup(); + gBrowser.removeCurrentTab(); +}); + +function checkItems(menuitem, arr) +{ + for (let i = 0; i < arr.length; i += 2) { + let str = arr[i]; + let details = arr[i + 1]; + if (str == "---") { + is(menuitem.localName, "menuseparator", "menuseparator"); + } + else if ("children" in details) { + is(menuitem.localName, "menu", "submenu"); + is(menuitem.getAttribute("label"), str, str + " label"); + checkItems(menuitem.firstChild.firstChild, details.children); + } + else { + is(menuitem.localName, "menuitem", str + " menuitem"); + + is(menuitem.getAttribute("label"), str, str + " label"); + is(menuitem.getAttribute("type"), details.type, str + " type"); + is(menuitem.getAttribute("image"), details.icon ? gBaseURL + details.icon : "", str + " icon"); + + if (details.checked) + is(menuitem.getAttribute("checked"), "true", str + " checked"); + else + ok(!menuitem.hasAttribute("checked"), str + " checked"); + + if (details.disabled) + is(menuitem.getAttribute("disabled"), "true", str + " disabled"); + else + ok(!menuitem.hasAttribute("disabled"), str + " disabled"); + } + + menuitem = menuitem.nextSibling; + } +} + +function checkMenu(contextMenu) +{ + let items = [ "Plain item", {type: "", icon: "", checked: false, disabled: false}, + "Disabled item", {type: "", icon: "", checked: false, disabled: true}, + "Item w/ textContent", {type: "", icon: "", checked: false, disabled: false}, + "---", null, + "Checkbox", {type: "checkbox", icon: "", checked: true, disabled: false}, + "---", null, + "Radio1", {type: "checkbox", icon: "", checked: true, disabled: false}, + "Radio2", {type: "checkbox", icon: "", checked: false, disabled: false}, + "Radio3", {type: "checkbox", icon: "", checked: false, disabled: false}, + "---", null, + "Item w/ icon", {type: "", icon: "favicon.ico", checked: false, disabled: false}, + "Item w/ bad icon", {type: "", icon: "", checked: false, disabled: false}, + "---", null, + "Submenu", { children: + ["Radio1", {type: "checkbox", icon: "", checked: false, disabled: false}, + "Radio2", {type: "checkbox", icon: "", checked: true, disabled: false}, + "Radio3", {type: "checkbox", icon: "", checked: false, disabled: false}, + "---", null, + "Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}] } + ]; + checkItems(contextMenu.childNodes[2], items); +} diff --git a/browser/base/content/test/general/test_contextmenu.html b/browser/base/content/test/general/test_contextmenu.html index edb7c705d502..c87ae2b5c40e 100644 --- a/browser/base/content/test/general/test_contextmenu.html +++ b/browser/base/content/test/general/test_contextmenu.html @@ -495,7 +495,7 @@ function runTest(testNum) { "context-viewinfo", true ].concat(inspectItems)); - invokeItemAction("0"); + invokeItemAction("1"); closeContextMenu(); // run mozRequestFullScreen on the element we're testing diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 0feaf0fe704f..a2f944bb616d 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -542,6 +542,8 @@ @RESPATH@/components/Identity.manifest @RESPATH@/components/recording-cmdline.js @RESPATH@/components/recording-cmdline.manifest +@RESPATH@/components/htmlMenuBuilder.js +@RESPATH@/components/htmlMenuBuilder.manifest @RESPATH@/components/PermissionSettings.js @RESPATH@/components/PermissionSettings.manifest diff --git a/dom/html/HTMLMenuElement.cpp b/dom/html/HTMLMenuElement.cpp index 8553534119f5..a15e7d0ea79f 100644 --- a/dom/html/HTMLMenuElement.cpp +++ b/dom/html/HTMLMenuElement.cpp @@ -9,11 +9,13 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/dom/HTMLMenuElementBinding.h" #include "mozilla/dom/HTMLMenuItemElement.h" +#include "nsIMenuBuilder.h" #include "nsAttrValueInlines.h" #include "nsContentUtils.h" -#include "nsXULContextMenuBuilder.h" #include "nsIURI.h" +#define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1" + NS_IMPL_NS_NEW_HTML_ELEMENT(Menu) namespace mozilla { @@ -97,12 +99,8 @@ HTMLMenuElement::CreateBuilder(nsIMenuBuilder** _retval) { NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR); - *_retval = nullptr; - - if (mType == MENU_TYPE_CONTEXT) { - NS_ADDREF(*_retval = new nsXULContextMenuBuilder()); - } - + nsCOMPtr builder = CreateBuilder(); + builder.swap(*_retval); return NS_OK; } @@ -113,8 +111,9 @@ HTMLMenuElement::CreateBuilder() return nullptr; } - nsCOMPtr ret = new nsXULContextMenuBuilder(); - return ret.forget(); + nsCOMPtr builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID); + NS_WARN_IF(!builder); + return builder.forget(); } NS_IMETHODIMP diff --git a/dom/html/htmlMenuBuilder.js b/dom/html/htmlMenuBuilder.js new file mode 100644 index 000000000000..863fc4d74b13 --- /dev/null +++ b/dom/html/htmlMenuBuilder.js @@ -0,0 +1,132 @@ +/* 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/. */ + +// This component is used to build the menus for the HTML contextmenu attribute. + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +const Cc = Components.classes; +const Ci = Components.interfaces; + +// A global value that is used to identify each menu item. It is +// incremented with each one that is found. +var gGeneratedId = 1; + +function HTMLMenuBuilder() { + this.currentNode = null; + this.root = null; + this.items = {}; + this.nestedStack = []; +}; + +// Building is done in two steps: +// The first generates a hierarchical JS object that contains the menu structure. +// This object is returned by toJSONString. +// +// The second step can take this structure and generate a XUL menu hierarchy or +// other UI from this object. The default UI is done in PageMenu.jsm. +// +// When a multi-process browser is used, the first step is performed by the child +// process and the second step is performed by the parent process. + +HTMLMenuBuilder.prototype = +{ + classID: Components.ID("{51c65f5d-0de5-4edc-9058-60e50cef77f8}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIMenuBuilder]), + + currentNode: null, + root: null, + items: {}, + nestedStack: [], + + toJSONString: function() { + return JSON.stringify(this.root); + }, + + openContainer: function(aLabel) { + if (!this.currentNode) { + this.root = { + type: "menu", + children: [] + }; + this.currentNode = this.root; + } + else { + let parent = this.currentNode; + this.currentNode = { + type: "menu", + label: aLabel, + children: [] + }; + parent.children.push(this.currentNode); + this.nestedStack.push(parent); + } + }, + + addItemFor: function(aElement, aCanLoadIcon) { + if (!("children" in this.currentNode)) { + return; + } + + let item = { + type: "menuitem", + label: aElement.label + }; + + let elementType = aElement.type; + if (elementType == "checkbox" || elementType == "radio") { + item.checkbox = true; + + if (aElement.checked) { + item.checked = true; + } + } + + let icon = aElement.icon; + if (icon.length > 0 && aCanLoadIcon) { + item.icon = icon; + } + + if (aElement.disabled) { + item.disabled = true; + } + + item.id = gGeneratedId++; + this.currentNode.children.push(item); + + this.items[item.id] = aElement; + }, + + addSeparator: function() { + if (!("children" in this.currentNode)) { + return; + } + + this.currentNode.children.push({ type: "separator"}); + }, + + undoAddSeparator: function() { + if (!("children" in this.currentNode)) { + return; + } + + let children = this.currentNode.children; + if (children.length && children[children.length - 1].type == "separator") { + children.pop(); + } + }, + + closeContainer: function() { + this.currentNode = this.nestedStack.length ? this.nestedStack.pop() : this.root; + }, + + click: function(id) { + let item = this.items[id]; + if (item) { + item.click(); + } + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HTMLMenuBuilder]); diff --git a/dom/html/htmlMenuBuilder.manifest b/dom/html/htmlMenuBuilder.manifest new file mode 100644 index 000000000000..b245f8fe2de5 --- /dev/null +++ b/dom/html/htmlMenuBuilder.manifest @@ -0,0 +1,3 @@ +component {51c65f5d-0de5-4edc-9058-60e50cef77f8} htmlMenuBuilder.js +contract @mozilla.org/content/html-menu-builder;1 {51c65f5d-0de5-4edc-9058-60e50cef77f8} + diff --git a/dom/html/moz.build b/dom/html/moz.build index cd725e70d2a4..97f6d1799026 100644 --- a/dom/html/moz.build +++ b/dom/html/moz.build @@ -215,6 +215,11 @@ SOURCES += [ 'PluginDocument.cpp', ] +EXTRA_COMPONENTS += [ + 'htmlMenuBuilder.js', + 'htmlMenuBuilder.manifest' +] + FAIL_ON_WARNINGS = True MSVC_ENABLE_PGO = True diff --git a/dom/html/nsIMenuBuilder.idl b/dom/html/nsIMenuBuilder.idl index a925fbcb709e..02664480fa46 100644 --- a/dom/html/nsIMenuBuilder.idl +++ b/dom/html/nsIMenuBuilder.idl @@ -11,7 +11,7 @@ interface nsIDOMHTMLMenuItemElement; * An interface used to construct native toolbar or context menus from */ -[scriptable, uuid(12724737-f7db-43b4-94ab-708a7b86e115)] +[scriptable, uuid(93F4A48F-D043-4F45-97FD-9771EA1AF976)] interface nsIMenuBuilder : nsISupports { @@ -49,4 +49,28 @@ interface nsIMenuBuilder : nsISupports */ void closeContainer(); + /** + * Returns a JSON string representing the menu hierarchy. For a context menu, + * it will be of the form: + * { + * type: "menu", + * children: [ + * { + * type: "menuitem", + * label: "label", + * icon: "image.png" + * }, + * { + * type: "separator", + * }, + * ]; + */ + AString toJSONString(); + + /** + * Invoke the action of the menuitem with assigned id aGeneratedItemId. + * + * @param aGeneratedItemId the menuitem id + */ + void click(in DOMString aGeneratedItemId); }; diff --git a/dom/webidl/HTMLMenuElement.webidl b/dom/webidl/HTMLMenuElement.webidl index 5ee2e66e3790..ff81a7c80d23 100644 --- a/dom/webidl/HTMLMenuElement.webidl +++ b/dom/webidl/HTMLMenuElement.webidl @@ -40,11 +40,11 @@ partial interface HTMLMenuElement { /** * Creates a native menu builder. The builder type is dependent on menu type. - * Currently, it returns nsXULContextMenuBuilder for context menus. - * Toolbar menus are not yet supported (the method returns null). + * Currently, it returns the @mozilla.org/content/html-menu-builder;1 + * component. Toolbar menus are not yet supported (the method returns null). */ [ChromeOnly] - MenuBuilder createBuilder(); + MenuBuilder? createBuilder(); /* * Builds a menu by iterating over menu children. diff --git a/dom/xul/moz.build b/dom/xul/moz.build index 62315cd7cfc5..a316ca9397ec 100644 --- a/dom/xul/moz.build +++ b/dom/xul/moz.build @@ -12,7 +12,6 @@ if CONFIG['MOZ_XUL']: DIRS += ['templates'] XPIDL_SOURCES += [ - 'nsIXULContextMenuBuilder.idl', 'nsIXULOverlayProvider.idl', ] @@ -23,7 +22,6 @@ if CONFIG['MOZ_XUL']: UNIFIED_SOURCES += [ 'nsXULCommandDispatcher.cpp', 'nsXULContentSink.cpp', - 'nsXULContextMenuBuilder.cpp', 'nsXULElement.cpp', 'nsXULPopupListener.cpp', 'nsXULPrototypeCache.cpp', diff --git a/dom/xul/nsIXULContextMenuBuilder.idl b/dom/xul/nsIXULContextMenuBuilder.idl deleted file mode 100644 index 1f5070393f6f..000000000000 --- a/dom/xul/nsIXULContextMenuBuilder.idl +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "nsISupports.idl" - -interface nsIDOMDocumentFragment; - -/** - * An interface for initialization of XUL context menu builder - * and for triggering of menuitem actions with assigned identifiers. - */ - -[scriptable, uuid(eb6b42c0-2f1c-4760-b5ca-bdc9b3ec77d4)] -interface nsIXULContextMenuBuilder : nsISupports -{ - - /** - * Initialize builder before building. - * - * @param aDocumentFragment the fragment that will be used to append top - * level elements - * - * @param aGeneratedItemIdAttrName the name of the attribute that will be - * used to mark elements as generated and for menuitem identification - */ - void init(in nsIDOMDocumentFragment aDocumentFragment, - in AString aGeneratedItemIdAttrName); - - /** - * Invoke the action of the menuitem with assigned id aGeneratedItemId. - * - * @param aGeneratedItemId the menuitem id - */ - void click(in DOMString aGeneratedItemId); - -}; diff --git a/dom/xul/nsXULContextMenuBuilder.cpp b/dom/xul/nsXULContextMenuBuilder.cpp deleted file mode 100644 index e6d9d5602c9e..000000000000 --- a/dom/xul/nsXULContextMenuBuilder.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "nsContentCreatorFunctions.h" -#include "nsIContent.h" -#include "nsIDOMDocumentFragment.h" -#include "nsIDOMHTMLElement.h" -#include "nsIDOMHTMLMenuItemElement.h" -#include "nsXULContextMenuBuilder.h" -#include "nsIDocument.h" -#include "mozilla/dom/Element.h" - -using namespace mozilla; -using namespace mozilla::dom; - -nsXULContextMenuBuilder::nsXULContextMenuBuilder() - : mCurrentGeneratedItemId(0) -{ -} - -nsXULContextMenuBuilder::~nsXULContextMenuBuilder() -{ -} - -NS_IMPL_CYCLE_COLLECTION(nsXULContextMenuBuilder, mFragment, mDocument, - mCurrentNode, mElements) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULContextMenuBuilder) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULContextMenuBuilder) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULContextMenuBuilder) - NS_INTERFACE_MAP_ENTRY(nsIMenuBuilder) - NS_INTERFACE_MAP_ENTRY(nsIXULContextMenuBuilder) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMenuBuilder) -NS_INTERFACE_MAP_END - - -NS_IMETHODIMP -nsXULContextMenuBuilder::OpenContainer(const nsAString& aLabel) -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - if (!mCurrentNode) { - mCurrentNode = mFragment; - } else { - nsCOMPtr menu; - nsresult rv = CreateElement(nsGkAtoms::menu, nullptr, getter_AddRefs(menu)); - NS_ENSURE_SUCCESS(rv, rv); - - menu->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aLabel, false); - - nsCOMPtr menuPopup; - rv = CreateElement(nsGkAtoms::menupopup, nullptr, - getter_AddRefs(menuPopup)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = menu->AppendChildTo(menuPopup, false); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mCurrentNode->AppendChildTo(menu, false); - NS_ENSURE_SUCCESS(rv, rv); - - mCurrentNode = menuPopup; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::AddItemFor(nsIDOMHTMLMenuItemElement* aElement, - bool aCanLoadIcon) -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - nsCOMPtr menuitem; - nsCOMPtr element = do_QueryInterface(aElement); - nsresult rv = CreateElement(nsGkAtoms::menuitem, element, - getter_AddRefs(menuitem)); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString type; - aElement->GetType(type); - if (type.EqualsLiteral("checkbox") || type.EqualsLiteral("radio")) { - // The menu is only temporary, so we don't need to handle - // the radio type precisely. - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::type, - NS_LITERAL_STRING("checkbox"), false); - bool checked; - aElement->GetChecked(&checked); - if (checked) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, - NS_LITERAL_STRING("true"), false); - } - } - - nsAutoString label; - aElement->GetLabel(label); - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::label, label, false); - - nsAutoString icon; - aElement->GetIcon(icon); - if (!icon.IsEmpty()) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, - NS_LITERAL_STRING("menuitem-iconic"), false); - if (aCanLoadIcon) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::image, icon, false); - } - } - - bool disabled; - aElement->GetDisabled(&disabled); - if (disabled) { - menuitem->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, - NS_LITERAL_STRING("true"), false); - } - - return mCurrentNode->AppendChildTo(menuitem, false); -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::AddSeparator() -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - nsCOMPtr menuseparator; - nsresult rv = CreateElement(nsGkAtoms::menuseparator, nullptr, - getter_AddRefs(menuseparator)); - NS_ENSURE_SUCCESS(rv, rv); - - return mCurrentNode->AppendChildTo(menuseparator, false); -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::UndoAddSeparator() -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - uint32_t count = mCurrentNode->GetChildCount(); - if (!count || - mCurrentNode->GetChildAt(count - 1)->Tag() != nsGkAtoms::menuseparator) { - return NS_OK; - } - - mCurrentNode->RemoveChildAt(count - 1, false); - return NS_OK; -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::CloseContainer() -{ - if (!mFragment) { - return NS_ERROR_NOT_INITIALIZED; - } - - if (mCurrentNode == mFragment) { - mCurrentNode = nullptr; - } else { - nsIContent* parent = mCurrentNode->GetParent(); - mCurrentNode = parent->GetParent(); - } - - return NS_OK; -} - - -NS_IMETHODIMP -nsXULContextMenuBuilder::Init(nsIDOMDocumentFragment* aDocumentFragment, - const nsAString& aGeneratedItemIdAttrName) -{ - NS_ENSURE_ARG_POINTER(aDocumentFragment); - - mFragment = do_QueryInterface(aDocumentFragment); - mDocument = mFragment->GetOwnerDocument(); - mGeneratedItemIdAttr = do_GetAtom(aGeneratedItemIdAttrName); - - return NS_OK; -} - -NS_IMETHODIMP -nsXULContextMenuBuilder::Click(const nsAString& aGeneratedItemId) -{ - nsresult rv; - int32_t idx = nsString(aGeneratedItemId).ToInteger(&rv); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr element = mElements.SafeObjectAt(idx); - if (element) { - element->DOMClick(); - } - } - - return NS_OK; -} - -nsresult -nsXULContextMenuBuilder::CreateElement(nsIAtom* aTag, - nsIDOMHTMLElement* aHTMLElement, - Element** aResult) -{ - *aResult = nullptr; - - nsRefPtr nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo( - aTag, nullptr, kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE); - - nsresult rv = NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER); - if (NS_FAILED(rv)) { - return rv; - } - - nsAutoString generateditemid; - - if (aHTMLElement) { - mElements.AppendObject(aHTMLElement); - generateditemid.AppendInt(mCurrentGeneratedItemId++); - } - - (*aResult)->SetAttr(kNameSpaceID_None, mGeneratedItemIdAttr, generateditemid, - false); - - return NS_OK; -} diff --git a/dom/xul/nsXULContextMenuBuilder.h b/dom/xul/nsXULContextMenuBuilder.h deleted file mode 100644 index 83e19cb99dab..000000000000 --- a/dom/xul/nsXULContextMenuBuilder.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "nsCOMPtr.h" -#include "nsCOMArray.h" -#include "nsIMenuBuilder.h" -#include "nsIXULContextMenuBuilder.h" -#include "nsCycleCollectionParticipant.h" - -class nsIAtom; -class nsIContent; -class nsIDocument; -class nsIDOMHTMLElement; - -namespace mozilla { -namespace dom { -class Element; -} // namespace dom -} // namespace mozilla - -class nsXULContextMenuBuilder : public nsIMenuBuilder, - public nsIXULContextMenuBuilder -{ -public: - nsXULContextMenuBuilder(); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULContextMenuBuilder, - nsIMenuBuilder) - NS_DECL_NSIMENUBUILDER - - NS_DECL_NSIXULCONTEXTMENUBUILDER - -protected: - virtual ~nsXULContextMenuBuilder(); - - nsresult CreateElement(nsIAtom* aTag, - nsIDOMHTMLElement* aHTMLElement, - mozilla::dom::Element** aResult); - - nsCOMPtr mFragment; - nsCOMPtr mDocument; - nsCOMPtr mGeneratedItemIdAttr; - - nsCOMPtr mCurrentNode; - int32_t mCurrentGeneratedItemId; - - nsCOMArray mElements; -}; diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index bccdc4c56b66..60f807f6f8da 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -408,6 +408,8 @@ @BINPATH@/components/Webapps.manifest @BINPATH@/components/AppsService.js @BINPATH@/components/AppsService.manifest +@BINPATH@/components/htmlMenuBuilder.js +@BINPATH@/components/htmlMenuBuilder.manifest @BINPATH@/components/Activities.manifest @BINPATH@/components/ActivitiesGlue.js diff --git a/toolkit/modules/PageMenu.jsm b/toolkit/modules/PageMenu.jsm index 7d5823f8557b..d36120b6b0fe 100644 --- a/toolkit/modules/PageMenu.jsm +++ b/toolkit/modules/PageMenu.jsm @@ -2,7 +2,7 @@ * 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/. */ -this.EXPORTED_SYMBOLS = ["PageMenu"]; +this.EXPORTED_SYMBOLS = ["PageMenuParent", "PageMenuChild"]; this.PageMenu = function PageMenu() { } @@ -11,46 +11,71 @@ PageMenu.prototype = { PAGEMENU_ATTR: "pagemenu", GENERATEDITEMID_ATTR: "generateditemid", - popup: null, - builder: null, + _popup: null, - maybeBuildAndAttachMenu: function(aTarget, aPopup) { - var pageMenu = null; - var target = aTarget; + // Only one of builder or browser will end up getting set. + _builder: null, + _browser: null, + + // Given a target node, get the context menu for it or its ancestor. + getContextMenu: function(aTarget) { + let pageMenu = null; + let target = aTarget; while (target) { - var contextMenu = target.contextMenu; + let contextMenu = target.contextMenu; if (contextMenu) { - pageMenu = contextMenu; - break; + return contextMenu; } target = target.parentNode; } - if (!pageMenu) { - return false; - } + return null; + }, - var insertionPoint = this.getInsertionPoint(aPopup); - if (!insertionPoint) { - return false; + // Given a target node, generate a JSON object for any context menu + // associated with it, or null if there is no context menu. + maybeBuild: function(aTarget) { + let pageMenu = this.getContextMenu(aTarget); + if (!pageMenu) { + return null; } pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu); pageMenu.sendShowEvent(); // the show event is not cancelable, so no need to check a result here - var fragment = aPopup.ownerDocument.createDocumentFragment(); + this._builder = pageMenu.createBuilder(); + if (!this._builder) { + return null; + } - var builder = pageMenu.createBuilder(); - if (!builder) { + pageMenu.build(this._builder); + + // This serializes then parses again, however this could be avoided in + // the single-process case with further improvement. + let menuString = this._builder.toJSONString(); + if (!menuString) { + return null; + } + + return JSON.parse(menuString); + }, + + // Given a JSON menu object and popup, add the context menu to the popup. + buildAndAttachMenuWithObject: function(aMenu, aBrowser, aPopup) { + if (!aMenu) { return false; } - builder.QueryInterface(Components.interfaces.nsIXULContextMenuBuilder); - builder.init(fragment, this.GENERATEDITEMID_ATTR); - pageMenu.build(builder); + let insertionPoint = this.getInsertionPoint(aPopup); + if (!insertionPoint) { + return false; + } - var pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR); + let fragment = aPopup.ownerDocument.createDocumentFragment(); + this.buildXULMenu(aMenu, fragment); + + let pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR); if (pos == "start") { insertionPoint.insertBefore(fragment, insertionPoint.firstChild); @@ -60,33 +85,101 @@ PageMenu.prototype = { insertionPoint.appendChild(fragment); } - this.builder = builder; - this.popup = aPopup; + this._browser = aBrowser; + this._popup = aPopup; - this.popup.addEventListener("command", this); - this.popup.addEventListener("popuphidden", this); + this._popup.addEventListener("command", this); + this._popup.addEventListener("popuphidden", this); return true; }, - handleEvent: function(event) { - var type = event.type; - var target = event.target; - if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) { - this.builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR)); - } else if (type == "popuphidden" && this.popup == target) { - this.removeGeneratedContent(this.popup); + // Construct the XUL menu structure for a given JSON object. + buildXULMenu: function(aNode, aElementForAppending) { + let document = aElementForAppending.ownerDocument; - this.popup.removeEventListener("popuphidden", this); - this.popup.removeEventListener("command", this); + let children = aNode.children; + for (let child of children) { + let menuitem; + switch (child.type) { + case "menuitem": + if (!child.id) { + continue; // Ignore children without ids + } - this.popup = null; - this.builder = null; + menuitem = document.createElement("menuitem"); + if (child.checkbox) { + menuitem.setAttribute("type", "checkbox"); + if (child.checked) { + menuitem.setAttribute("checked", "true"); + } + } + + if (child.label) { + menuitem.setAttribute("label", child.label); + } + if (child.icon) { + menuitem.setAttribute("image", child.icon); + menuitem.className = "menuitem-iconic"; + } + if (child.disabled) { + menuitem.setAttribute("disabled", true); + } + + break; + + case "separator": + menuitem = document.createElement("menuseparator"); + break; + + case "menu": + menuitem = document.createElement("menu"); + if (child.label) { + menuitem.setAttribute("label", child.label); + } + + let menupopup = document.createElement("menupopup"); + menuitem.appendChild(menupopup); + + this.buildXULMenu(child, menupopup); + break; + } + + menuitem.setAttribute(this.GENERATEDITEMID_ATTR, child.id ? child.id : 0); + aElementForAppending.appendChild(menuitem); } }, + // Called when the generated menuitem is executed. + handleEvent: function(event) { + let type = event.type; + let target = event.target; + if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) { + // If a builder is assigned, call click on it directly. Otherwise, this is + // likely a menu with data from another process, so send a message to the + // browser to execute the menuitem. + if (this._builder) { + this._builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR)); + } + else if (this._browser) { + this._browser.messageManager.sendAsyncMessage("ContextMenu:DoCustomCommand", + target.getAttribute(this.GENERATEDITEMID_ATTR)); + } + } else if (type == "popuphidden" && this._popup == target) { + this.removeGeneratedContent(this._popup); + + this._popup.removeEventListener("popuphidden", this); + this._popup.removeEventListener("command", this); + + this._popup = null; + this._builder = null; + this._browser = null; + } + }, + + // Get the first child of the given element with the given tag name. getImmediateChild: function(element, tag) { - var child = element.firstChild; + let child = element.firstChild; while (child) { if (child.localName == tag) { return child; @@ -96,16 +189,19 @@ PageMenu.prototype = { return null; }, + // Return the location where the generated items should be inserted into the + // given popup. They should be inserted as the next sibling of the returned + // element. getInsertionPoint: function(aPopup) { if (aPopup.hasAttribute(this.PAGEMENU_ATTR)) return aPopup; - var element = aPopup.firstChild; + let element = aPopup.firstChild; while (element) { if (element.localName == "menu") { - var popup = this.getImmediateChild(element, "menupopup"); + let popup = this.getImmediateChild(element, "menupopup"); if (popup) { - var result = this.getInsertionPoint(popup); + let result = this.getInsertionPoint(popup); if (result) { return result; } @@ -117,19 +213,20 @@ PageMenu.prototype = { return null; }, + // Remove the generated content from the given popup. removeGeneratedContent: function(aPopup) { - var ungenerated = []; + let ungenerated = []; ungenerated.push(aPopup); - var count; + let count; while (0 != (count = ungenerated.length)) { - var last = count - 1; - var element = ungenerated[last]; + let last = count - 1; + let element = ungenerated[last]; ungenerated.splice(last, 1); - var i = element.childNodes.length; + let i = element.childNodes.length; while (i-- > 0) { - var child = element.childNodes[i]; + let child = element.childNodes[i]; if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) { ungenerated.push(child); continue; @@ -139,3 +236,78 @@ PageMenu.prototype = { } } } + +// This object is expected to be used from a parent process. +this.PageMenuParent = function PageMenuParent() { +} + +PageMenuParent.prototype = { + __proto__ : PageMenu.prototype, + + /* + * Given a target node and popup, add the context menu to the popup. This is + * intended to be called when a single process is used. This is equivalent to + * calling PageMenuChild.build and PageMenuParent.addToPopup in sequence. + * + * Returns true if custom menu items were present. + */ + buildAndAddToPopup: function(aTarget, aPopup) { + let menuObject = this.maybeBuild(aTarget); + if (!menuObject) { + return false; + } + + return this.buildAndAttachMenuWithObject(menuObject, null, aPopup); + }, + + /* + * Given a JSON menu object and popup, add the context menu to the popup. This + * is intended to be called when the child page is in a different process. + * aBrowser should be the browser containing the page the context menu is + * displayed for, which may be null. + * + * Returns true if custom menu items were present. + */ + addToPopup: function(aMenu, aBrowser, aPopup) { + return this.buildAndAttachMenuWithObject(aMenu, aBrowser, aPopup); + } +} + +// This object is expected to be used from a child process. +this.PageMenuChild = function PageMenuChild() { +} + +PageMenuChild.prototype = { + __proto__ : PageMenu.prototype, + + /* + * Given a target node, return a JSON object for the custom menu commands. The + * object will consist of a hierarchical structure of menus, menuitems or + * separators. Supported properties of each are: + * Menu: children, label, type="menu" + * Menuitems: checkbox, checked, disabled, icon, label, type="menuitem" + * Separators: type="separator" + * + * In addition, the id of each item will be used to identify the item + * when it is executed. The type will either be 'menu', 'menuitem' or + * 'separator'. The toplevel node will be a menu with a children property. The + * children property of a menu is an array of zero or more other items. + * + * If there is no menu associated with aTarget, null will be returned. + */ + build: function(aTarget) { + return this.maybeBuild(aTarget); + }, + + /* + * Given the id of a menu, execute the command associated with that menu. It + * is assumed that only one command will be executed so the builder is + * cleared afterwards. + */ + executeMenu: function(aId) { + if (this._builder) { + this._builder.click(aId); + this._builder = null; + } + } +} From 8e8246a71f54e6b85473c8e82c67d79f06c9d92a Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 06:44:11 -0800 Subject: [PATCH 52/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 4 ++-- b2g/config/flame-kk/sources.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index d569c43825fc..2438e12f026e 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -113,7 +113,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 06d22c370d94..aa883245b56f 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -113,7 +113,7 @@ - + @@ -130,7 +130,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 825377c58027..69c48ff50f37 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -113,7 +113,7 @@ - + From 73552440fa55127bf04c0f188807f14301900ae1 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 06:54:15 -0800 Subject: [PATCH 53/64] Bumping manifests a=b2g-bump --- b2g/config/flame-kk/sources.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 69c48ff50f37..27345ce8d00b 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -137,9 +137,11 @@ - + + + From 52a1d0fc64f16d010800042af1cbafa91854a9f1 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 06:59:15 -0800 Subject: [PATCH 54/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 2438e12f026e..3afce13987bc 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -12,7 +12,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index aa883245b56f..133c2dd9fa7c 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -12,7 +12,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 27345ce8d00b..b01ba4efdbef 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -12,7 +12,7 @@ - + From 3f604fee9044662da24e35212d50c4693df89258 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 08:57:18 -0800 Subject: [PATCH 55/64] Bumping gaia.json for 4 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/b80972445abc Author: Florin Strugariu Desc: Merge pull request #26949 from JohanLorenzo/bug-1114560 Bug 1114560 - Add a test to delete the whole phone number on the dialer ======== https://hg.mozilla.org/integration/gaia-central/rev/d8c2a1d4e1f4 Author: Johan Lorenzo Desc: Bug 1114560 - Add a test to delete the whole phone number on the dialer ======== https://hg.mozilla.org/integration/gaia-central/rev/f736743c14c3 Author: Florin Strugariu Desc: Merge pull request #26948 from JohanLorenzo/bug-1114559 Bug 1114559 - Add a test to check the presence of contacts' default image ======== https://hg.mozilla.org/integration/gaia-central/rev/e5595ce485e2 Author: Johan Lorenzo Desc: Bug 1114559 - Add a test to check the presence of contacts' default image --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 96b6c17a3333..5de66ae82cb4 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "644729ef0d87bfd9994325f7ee8875e1df30c139", + "revision": "b80972445abcf82705cd8bc57e12e3cfe2061e93", "repo_path": "integration/gaia-central" } From bc7e55333f65d19030080867961e8e99999cd850 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 09:01:56 -0800 Subject: [PATCH 56/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 3afce13987bc..f939d8e44fe8 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index bdfd3808d737..71d8b2b9ce02 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 31102ae37cf8..c9300f786120 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 133c2dd9fa7c..380014e06798 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index bdfd3808d737..71d8b2b9ce02 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index b01ba4efdbef..23f6d62a7328 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index d997d3559dc9..f67f973548d3 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index a4dfd542999f..d8a9d05e93ae 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 855755f93a26..52beba6ba3d1 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index e99af6ffcab9..c9cc3355442e 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 875f04294971..82d9455a3dbf 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From 38ca750aa71295a3350623ff4b911b3377166578 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 09:27:16 -0800 Subject: [PATCH 57/64] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/6a113da9e00f Author: Kevin Grandon Desc: Merge pull request #26925 from KevinGrandon/bug_1113904_add_editorconfig Bug 1113904 - Introduce gaia .editorconfig ======== https://hg.mozilla.org/integration/gaia-central/rev/9c0dabfbd68e Author: Kevin Grandon Desc: Bug 1113904 - Introduce gaia .editorconfig r=justindarc --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 5de66ae82cb4..3986586365a8 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "b80972445abcf82705cd8bc57e12e3cfe2061e93", + "revision": "6a113da9e00fa2afaad2d77923f306063f84fc05", "repo_path": "integration/gaia-central" } From 27852c98c55005bb8b2e9a47c94cfcfe3ed681ba Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 09:36:55 -0800 Subject: [PATCH 58/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index f939d8e44fe8..99503f549b53 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 71d8b2b9ce02..983c33420e87 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index c9300f786120..818400b1832e 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 380014e06798..a239cf40bf05 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 71d8b2b9ce02..983c33420e87 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 23f6d62a7328..2bc525efaf4c 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index f67f973548d3..4ea725dd6cec 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index d8a9d05e93ae..0dec11562728 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 52beba6ba3d1..a7f240d75aa7 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index c9cc3355442e..7c3bb697b134 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 82d9455a3dbf..6728f0bc7a62 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From ea44d7904f9b934afc26f06bb9d925c689d2764b Mon Sep 17 00:00:00 2001 From: Kyle Machulis Date: Mon, 22 Dec 2014 09:38:01 -0800 Subject: [PATCH 59/64] Bug 1112936 - Enable settings API tests on e10s; r=gwagner r=bent r=gerard-majax --HG-- extra : rebase_source : c5532dc6968c317e72399040a3024b6a22df0df8 --- dom/settings/tests/file_loadserver.js | 17 +++ dom/settings/tests/mochitest.ini | 4 +- dom/settings/tests/test_settings_basics.html | 138 +++++++++--------- dom/settings/tests/test_settings_blobs.html | 27 ++-- .../tests/test_settings_data_uris.html | 27 ++-- .../tests/test_settings_onsettingchange.html | 46 +++--- .../tests/test_settings_permissions.html | 22 ++- 7 files changed, 141 insertions(+), 140 deletions(-) create mode 100644 dom/settings/tests/file_loadserver.js diff --git a/dom/settings/tests/file_loadserver.js b/dom/settings/tests/file_loadserver.js new file mode 100644 index 000000000000..64c2104a92ce --- /dev/null +++ b/dom/settings/tests/file_loadserver.js @@ -0,0 +1,17 @@ +let Ci = Components.interfaces; +let Cc = Components.classes; +let Cu = Components.utils; + +// Stolen from SpecialPowers, since at this point we don't know we're in a test. +let isMainProcess = function() { + try { + return Cc["@mozilla.org/xre/app-info;1"]. + getService(Ci.nsIXULRuntime). + processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; + } catch (e) { } + return true; +}; + +if (isMainProcess()) { + Components.utils.import("resource://gre/modules/SettingsRequestManager.jsm"); +} diff --git a/dom/settings/tests/mochitest.ini b/dom/settings/tests/mochitest.ini index 90f21987ece6..a5740d2062c5 100644 --- a/dom/settings/tests/mochitest.ini +++ b/dom/settings/tests/mochitest.ini @@ -1,5 +1,7 @@ [DEFAULT] -skip-if = (toolkit == 'gonk' && debug) || e10s #debug-only failure, bug 932878 +skip-if = (toolkit == 'gonk' && debug) #debug-only failure, bug 932878 +support-files = + file_loadserver.js [test_settings_basics.html] [test_settings_permissions.html] diff --git a/dom/settings/tests/test_settings_basics.html b/dom/settings/tests/test_settings_basics.html index 22a35e369a8f..d9fce696447f 100644 --- a/dom/settings/tests/test_settings_basics.html +++ b/dom/settings/tests/test_settings_basics.html @@ -21,10 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={678695} "use strict"; -if (SpecialPowers.isMainProcess()) { - SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm"); -} - +var url = SimpleTest.getTestFileURL("file_loadserver.js"); +var script = SpecialPowers.loadChromeScript(url); SpecialPowers.addPermission("settings-api-read", true, document); SpecialPowers.addPermission("settings-api-write", true, document); SpecialPowers.addPermission("settings-read", true, document); @@ -99,12 +97,10 @@ function check(o1, o2) { var req, req2, req3, req4, req5, req6; var index = 0; -var mozSettings = navigator.mozSettings; - var steps = [ function () { ok(true, "Deleting database"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -113,14 +109,14 @@ var steps = [ }, function () { ok(true, "Setting wifi"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifi); req.onsuccess = function () { ok(true, "set done"); } req.onerror = onFailure; - var lock2 = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); req2 = lock2.get("net3g.apn"); req2.onsuccess = function () { is(Object.keys(req2.result).length, 1, "length 1"); @@ -132,7 +128,7 @@ var steps = [ }, function () { ok(true, "Change wifi1"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifi2); req.onsuccess = function () { ok(true, "Set Done"); @@ -150,7 +146,7 @@ var steps = [ }, function () { ok(true, "Set Combination"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req3 = lock.set(combination); req3.onsuccess = function () { ok(true, "set done"); @@ -164,7 +160,7 @@ var steps = [ req3.onerror = onFailure; }, function() { - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req4 = lock.get("net3g.apn2"); req4.onsuccess = function() { ok(true, "Done"); @@ -175,7 +171,7 @@ var steps = [ }, function() { ok(true, "Get unknown key"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("abc.def"); req.onsuccess = function() { is(req.result["abc.def"], undefined, "no result"); @@ -186,7 +182,7 @@ var steps = [ function() { ok(true, "adding onsettingchange"); navigator.mozSettings.onsettingchange = onsettingschangeWithNext; - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req2 = lock.get("screen.brightness"); req2.onsuccess = function() { ok(true, "end adding onsettingchange"); @@ -196,7 +192,7 @@ var steps = [ }, function() { ok(true, "Test onsettingchange"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set done, observer has to call next"); @@ -205,7 +201,7 @@ var steps = [ }, function() { ok(true, "delete onsettingschange"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); navigator.mozSettings.onsettingchange = null; req = lock.set(screenBright); req.onsuccess = function () { @@ -216,7 +212,7 @@ var steps = [ }, function () { ok(true, "Waiting for all set callbacks"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); req.onsuccess = function() { ok(true, "Done"); @@ -230,7 +226,7 @@ var steps = [ navigator.mozSettings.addObserver("screen.brightness", observer1); navigator.mozSettings.addObserver("screen.brightness", observer2); navigator.mozSettings.addObserver("screen.brightness", observerWithNext); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req2 = lock.get("screen.brightness"); req2.onsuccess = function() { ok(true, "set observeSetting done!"); @@ -240,7 +236,7 @@ var steps = [ }, function() { ok(true, "test observers"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set done"); @@ -249,7 +245,7 @@ var steps = [ }, function() { ok(true, "removing Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set done"); @@ -260,7 +256,7 @@ var steps = [ }, function() { ok(true, "test Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set done"); @@ -269,7 +265,7 @@ var steps = [ }, function() { ok(true, "removing Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); navigator.mozSettings.removeObserver("screen.brightness", observerWithNext); req = lock.set(screenBright); req.onsuccess = function () { @@ -282,7 +278,7 @@ var steps = [ }, function() { ok(true, "removing Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); req.onsuccess = function () { ok(true, "get done"); @@ -292,7 +288,7 @@ var steps = [ }, function () { ok(true, "Nested test"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); req.onsuccess = function () { req3 = lock.set({"screen.brightness": req.result["screen.brightness"] + 1}) @@ -313,7 +309,7 @@ var steps = [ } req2.onerror = onFailure; - var lock2 = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); req5 = lock2.get("screen.brightness"); req5.onsuccess = function () { is(req5.result["screen.brightness"], 1.7, "same Value"); @@ -323,7 +319,7 @@ var steps = [ }, function () { ok(true, "Deleting database"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -331,7 +327,7 @@ var steps = [ }; }, function () { - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req2 = lock.set(wifi); req2.onsuccess = function () { ok(true, "set done"); @@ -339,7 +335,7 @@ var steps = [ req2.onerror = onFailure; ok(true, "Get all settings"); - var lock2 = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); req3 = lock2.get("*"); req3.onsuccess = function () { is(Object.keys(req3.result).length, 1, "length 1"); @@ -360,7 +356,7 @@ var steps = [ }, function () { ok(true, "Change wifi1"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifi2); req.onsuccess = function () { ok(true, "Set Done"); @@ -379,8 +375,8 @@ var steps = [ }, function () { ok(true, "Test locking"); - var lock = mozSettings.createLock(); - var lock2 = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); req = lock.set(wifiEnabled); req.onsuccess = function () { ok(true, "Test Locking Done"); @@ -396,7 +392,7 @@ var steps = [ }, function () { ok(true, "Test locking result"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("wifi.enabled"); req.onsuccess = function() { check(req.result, wifiDisabled); @@ -409,7 +405,7 @@ var steps = [ ok(true, "Test locking heavy"); for (var i=0; i<30; i++) { // only new locks! - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); var obj = {}; obj["wifi.enabled" + i] = true; req = lock.set( obj ); @@ -419,7 +415,7 @@ var steps = [ req.onerror = onFailure; }; { - var lock2 = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); req2 = lock2.get("*"); req2.onsuccess = function () { is(Object.keys(req2.result).length, 32, "length 12"); @@ -428,7 +424,7 @@ var steps = [ }; req2.onerror = onFailure; } - var lock2 = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); var obj = {}; obj["wifi.enabled" + 30] = true; req3 = lock2.set( obj ); @@ -437,7 +433,7 @@ var steps = [ }; req3.onerror = onFailure; - var lock3 = mozSettings.createLock(); + var lock3 = navigator.mozSettings.createLock(); // with one lock for (var i = 0; i < 30; i++) { req4 = lock3.get("wifi.enabled" + i); @@ -451,7 +447,7 @@ var steps = [ } ok(true, "start next2!"); - var lock4 = mozSettings.createLock(); + var lock4 = navigator.mozSettings.createLock(); for (var i=0; i<30; i++) { var obj = {}; obj["wifi.enabled" + i] = false; @@ -461,7 +457,7 @@ var steps = [ }; req4.onerror = onFailure; } - var lock5 = mozSettings.createLock(); + var lock5 = navigator.mozSettings.createLock(); for (var i=0; i<30; i++) { req5 = lock5.get("wifi.enabled" + i); var testObj = {}; @@ -473,7 +469,7 @@ var steps = [ req5.onerror = onFailure; } - var lock6 = mozSettings.createLock(); + var lock6 = navigator.mozSettings.createLock(); req6 = lock6.clear(); req6.onsuccess = function () { ok(true, "Deleted the database"); @@ -483,8 +479,8 @@ var steps = [ }, function () { ok(true, "reverse Test locking"); - var lock2 = mozSettings.createLock(); - var lock = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifiEnabled); req.onsuccess = function () { @@ -501,7 +497,7 @@ var steps = [ }, function () { ok(true, "Test locking result"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("wifi.enabled"); req.onsuccess = function() { @@ -510,14 +506,14 @@ var steps = [ } req.onerror = onFailure; - var lock2 = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); req2 = lock2.clear(); req2.onsuccess = function () { ok(true, "Deleted the database"); }; req2.onerror = onFailure; - var lock3 = mozSettings.createLock(); + var lock3 = navigator.mozSettings.createLock(); req3 = lock3.set(wifi); req3.onsuccess = function () { ok(true, "set done"); @@ -528,7 +524,7 @@ var steps = [ }, function () { ok(true, "Get all settings"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("*"); req.onsuccess = function () { is(Object.keys(req.result).length, 1, "length 1"); @@ -540,7 +536,7 @@ var steps = [ }, function () { ok(true, "Get net3g.apn"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("net3g.apn"); req.onsuccess = function () { is(Object.keys(req.result).length, 1, "length 1"); @@ -552,7 +548,7 @@ var steps = [ }, function () { ok(true, "Change wifi2"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifi2); req.onsuccess = function () { ok(true, "Set Done"); @@ -562,7 +558,7 @@ var steps = [ }, function () { ok(true, "Get net3g.apn"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("net3g.apn"); req.onsuccess = function () { is(Object.keys(req.result).length, 1, "length 1"); @@ -574,7 +570,7 @@ var steps = [ }, function () { ok(true, "Add wifi.enabled"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifiEnabled); req.onsuccess = function () { ok(true, "Set Done"); @@ -584,7 +580,7 @@ var steps = [ }, function () { ok(true, "Get Wifi Enabled"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("wifi.enabled"); req.onsuccess = function () { is(Object.keys(req.result).length, 1, "length 1"); @@ -596,7 +592,7 @@ var steps = [ }, function () { ok(true, "Get all"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("*"); req.onsuccess = function () { is(Object.keys(req.result).length, 2, "length 2"); @@ -609,7 +605,7 @@ var steps = [ }, function () { ok(true, "Add wifiNetworks"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifiNetworks0); req.onsuccess = function () { ok(true, "Set Done"); @@ -625,7 +621,7 @@ var steps = [ }, function () { ok(true, "Get Wifi Networks"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("wifi.networks[0]"); req.onsuccess = function () { is(Object.keys(req.result).length, 1, "length 1"); @@ -637,12 +633,12 @@ var steps = [ }, function() { ok(true, "Clear DB, multiple locks"); - var lock4 = mozSettings.createLock(); - var lock3 = mozSettings.createLock(); - var lock2 = mozSettings.createLock(); - var lock = mozSettings.createLock(); - var lock6 = mozSettings.createLock(); - var lock7 = mozSettings.createLock(); + var lock4 = navigator.mozSettings.createLock(); + var lock3 = navigator.mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); + var lock6 = navigator.mozSettings.createLock(); + var lock7 = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -652,7 +648,7 @@ var steps = [ }, function () { ok(true, "Add wifiNetworks"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifiNetworks0); req.onsuccess = function () { ok(true, "Set Done"); @@ -662,7 +658,7 @@ var steps = [ }, function () { ok(true, "Test set after lock closed"); - var lockx = mozSettings.createLock(); + var lockx = navigator.mozSettings.createLock(); var cb = function() { var reqx = null; try { @@ -678,7 +674,7 @@ var steps = [ }, function() { ok(true, "Clear DB"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -688,7 +684,7 @@ var steps = [ }, function() { ok(true, "Set with multiple arguments"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(combination); req.onsuccess = function () { ok(true, "Set Done"); @@ -698,7 +694,7 @@ var steps = [ }, function() { ok(true, "request argument from multiple set"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); req.onsuccess = function () { check(req.result["screen.brightness"], 0.7, "get done"); @@ -708,7 +704,7 @@ var steps = [ }, function() { ok(true, "Test closed attribute on a valid lock"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); is(lock.closed, false, "closed attribute is false on creation"); req = lock.get("screen.brightness"); req.onsuccess = function () { @@ -719,7 +715,7 @@ var steps = [ }, function () { ok(true, "Test closed attribute on invalid lock"); - var lockx = mozSettings.createLock(); + var lockx = navigator.mozSettings.createLock(); var cb = function() { var reqx = null; try { @@ -735,7 +731,7 @@ var steps = [ }, function() { ok(true, "Clear DB"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -745,7 +741,7 @@ var steps = [ }, function() { ok(true, "Set object value"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set({"setting-obj": {foo: {bar: 23}}}); req.onsuccess = function() { req2 = lock.get("setting-obj"); @@ -761,7 +757,7 @@ var steps = [ }, function() { ok(true, "Clear DB"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -771,7 +767,7 @@ var steps = [ }, function () { ok(true, "Call success callback when transaction commits"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); lock.onsettingstransactionsuccess = function () { next(); }; @@ -789,7 +785,7 @@ var steps = [ }, function() { ok(true, "Clear DB"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); diff --git a/dom/settings/tests/test_settings_blobs.html b/dom/settings/tests/test_settings_blobs.html index 35986fa6fcbe..69ac21fb6d88 100644 --- a/dom/settings/tests/test_settings_blobs.html +++ b/dom/settings/tests/test_settings_blobs.html @@ -21,10 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821630 "use strict"; -if (SpecialPowers.isMainProcess()) { - SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm"); -} - +var url = SimpleTest.getTestFileURL("file_loadserver.js"); +var script = SpecialPowers.loadChromeScript(url); SpecialPowers.addPermission("settings-read", true, document); SpecialPowers.addPermission("settings-write", true, document); SpecialPowers.addPermission("settings-api-read", true, document); @@ -45,7 +43,6 @@ function onFailure() { } } -let mozSettings = window.navigator.mozSettings; let req; let storedBlob = new Blob(['12345'], {"type": "text/plain"}); @@ -61,7 +58,7 @@ function checkBlob(blob) { let steps = [ function() { - let lock = mozSettings.createLock(); + let lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = next; req.onerror = onFailure("Deleting database"); @@ -69,19 +66,19 @@ let steps = [ function() { function obs(e) { checkBlob(e.settingValue); - mozSettings.removeObserver("test1", obs); + navigator.mozSettings.removeObserver("test1", obs); next(); } - mozSettings.addObserver("test1", obs); + navigator.mozSettings.addObserver("test1", obs); next(); }, function() { // next is called by the observer above - let req = mozSettings.createLock().set({"test1": storedBlob}); + let req = navigator.mozSettings.createLock().set({"test1": storedBlob}); req.onerror = onFailure("Saving blob"); }, function() { - let req = mozSettings.createLock().get("test1"); + let req = navigator.mozSettings.createLock().get("test1"); req.onsuccess = function(event) { checkBlob(event.target.result["test1"]); next(); @@ -89,12 +86,12 @@ let steps = [ req.onerror = onFailure("Getting blob"); }, function() { - let req = mozSettings.createLock().set({"test2": [1, 2, storedBlob, 4]}); + let req = navigator.mozSettings.createLock().set({"test2": [1, 2, storedBlob, 4]}); req.onsuccess = next; req.onerror = onFailure("Saving array"); }, function() { - let req = mozSettings.createLock().get("test2"); + let req = navigator.mozSettings.createLock().get("test2"); req.onsuccess = function(event) { let val = event.target.result["test2"]; ok(Array.isArray(val), "Result is an array"); @@ -105,12 +102,12 @@ let steps = [ req.onerror = onFailure("Getting array"); }, function() { - let req = mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [storedBlob]}}}); + let req = navigator.mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [storedBlob]}}}); req.onsuccess = next(); req.onerror = onFailure("Saving object"); }, function() { - let req = mozSettings.createLock().get("test3"); + let req = navigator.mozSettings.createLock().get("test3"); req.onsuccess = function(event) { let val = event.target.result["test3"]; ok(typeof(val) == "object", "Result is an object"); @@ -125,7 +122,7 @@ let steps = [ req.onerror = onFailure("Getting object"); }, function() { - let req = mozSettings.createLock().clear(); + let req = navigator.mozSettings.createLock().clear(); req.onsuccess = function() { next(); }; diff --git a/dom/settings/tests/test_settings_data_uris.html b/dom/settings/tests/test_settings_data_uris.html index 9b4ef51a5df1..9650dff6d4d9 100644 --- a/dom/settings/tests/test_settings_data_uris.html +++ b/dom/settings/tests/test_settings_data_uris.html @@ -21,10 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=806374 "use strict"; -if (SpecialPowers.isMainProcess()) { - SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm"); -} - +var url = SimpleTest.getTestFileURL("file_loadserver.js"); +var script = SpecialPowers.loadChromeScript(url); SpecialPowers.addPermission("settings-read", true, document); SpecialPowers.addPermission("settings-write", true, document); SpecialPowers.addPermission("settings-api-read", true, document); @@ -45,7 +43,6 @@ function onFailure() { } } -let mozSettings = window.navigator.mozSettings; let req; // A simple data URI that will be converted to a blob. @@ -62,7 +59,7 @@ function checkBlob(blob) { let steps = [ function() { - let lock = mozSettings.createLock(); + let lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = next; req.onerror = onFailure("Deleting database"); @@ -70,19 +67,19 @@ let steps = [ function() { function obs(e) { checkBlob(e.settingValue); - mozSettings.removeObserver("test1", obs); + navigator.mozSettings.removeObserver("test1", obs); next(); } - mozSettings.addObserver("test1", obs); + navigator.mozSettings.addObserver("test1", obs); next(); }, function() { // next is called by the observer above - let req = mozSettings.createLock().set({"test1": dataURI}); + let req = navigator.mozSettings.createLock().set({"test1": dataURI}); req.onerror = onFailure("Saving blob"); }, function() { - let req = mozSettings.createLock().get("test1"); + let req = navigator.mozSettings.createLock().get("test1"); req.onsuccess = function(event) { checkBlob(event.target.result["test1"]); next(); @@ -90,12 +87,12 @@ let steps = [ req.onerror = onFailure("Getting blob"); }, function() { - let req = mozSettings.createLock().set({"test2": [1, 2, dataURI, 4]}); + let req = navigator.mozSettings.createLock().set({"test2": [1, 2, dataURI, 4]}); req.onsuccess = next; req.onerror = onFailure("Saving array"); }, function() { - let req = mozSettings.createLock().get("test2"); + let req = navigator.mozSettings.createLock().get("test2"); req.onsuccess = function(event) { let val = event.target.result["test2"]; ok(Array.isArray(val), "Result is an array"); @@ -106,12 +103,12 @@ let steps = [ req.onerror = onFailure("Getting array"); }, function() { - let req = mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [dataURI]}}}); + let req = navigator.mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [dataURI]}}}); req.onsuccess = next(); req.onerror = onFailure("Saving object"); }, function() { - let req = mozSettings.createLock().get("test3"); + let req = navigator.mozSettings.createLock().get("test3"); req.onsuccess = function(event) { let val = event.target.result["test3"]; ok(typeof(val) == "object", "Result is an object"); @@ -126,7 +123,7 @@ let steps = [ req.onerror = onFailure("Getting object"); }, function() { - let req = mozSettings.createLock().clear(); + let req = navigator.mozSettings.createLock().clear(); req.onsuccess = function() { next(); }; diff --git a/dom/settings/tests/test_settings_onsettingchange.html b/dom/settings/tests/test_settings_onsettingchange.html index 311e4f7142bb..da00103d7c8d 100644 --- a/dom/settings/tests/test_settings_onsettingchange.html +++ b/dom/settings/tests/test_settings_onsettingchange.html @@ -21,10 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=678695 "use strict"; -if (SpecialPowers.isMainProcess()) { - SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm"); -} - +var url = SimpleTest.getTestFileURL("file_loadserver.js"); +var script = SpecialPowers.loadChromeScript(url); SpecialPowers.addPermission("settings-write", true, document); SpecialPowers.addPermission("settings-read", true, document); SpecialPowers.addPermission("settings-api-read", true, document); @@ -83,12 +81,10 @@ function onComplexSettingschangeWithNext(event) { var req, req2; var index = 0; -var mozSettings = window.navigator.mozSettings; - var steps = [ function () { ok(true, "Deleting database"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -97,7 +93,7 @@ var steps = [ req.onerror = onFailure; }, function () { - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req2 = lock.set(screenBright); req2.onsuccess = function () { ok(true, "set done"); @@ -108,7 +104,7 @@ var steps = [ }, function() { ok(true, "testing"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req2 = lock.set(screenBright); req2.onsuccess = function() { ok(true, "end adding onsettingchange"); @@ -117,7 +113,7 @@ var steps = [ }, function() { ok(true, "test observers"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); req.onsuccess = function () { ok(true, "get done"); @@ -131,7 +127,7 @@ var steps = [ navigator.mozSettings.addObserver("screen.brightness", observer1); navigator.mozSettings.addObserver("screen.brightness", observer2); navigator.mozSettings.addObserver("screen.brightness", observerOnlyCalledOnce); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req2 = lock.get("screen.brightness"); req2.onsuccess = function() { ok(true, "set observeSetting done!"); @@ -141,7 +137,7 @@ var steps = [ }, function() { ok(true, "test observers"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set1 done"); @@ -150,7 +146,7 @@ var steps = [ }, function() { ok(true, "test observers"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); navigator.mozSettings.removeObserver("screen.brightness", observerOnlyCalledOnce); req.onsuccess = function () { @@ -160,7 +156,7 @@ var steps = [ }, function() { ok(true, "removing Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set2 done"); @@ -173,7 +169,7 @@ var steps = [ function() { ok(true, "delete onsettingschange"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); navigator.mozSettings.onsettingchange = null; req = lock.set(screenBright); req.onsuccess = function () { @@ -184,7 +180,7 @@ var steps = [ }, function () { ok(true, "Waiting for all set callbacks"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); req.onsuccess = function() { ok(true, "Done"); @@ -198,7 +194,7 @@ var steps = [ navigator.mozSettings.addObserver("screen.brightness", observer1); navigator.mozSettings.addObserver("screen.brightness", observer2); navigator.mozSettings.addObserver("screen.brightness", observerWithNext); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req2 = lock.get("screen.brightness"); req2.onsuccess = function() { ok(true, "set observeSetting done!"); @@ -208,7 +204,7 @@ var steps = [ }, function() { ok(true, "test observers"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set1 done"); @@ -217,7 +213,7 @@ var steps = [ }, function() { ok(true, "removing Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set2 done"); @@ -228,7 +224,7 @@ var steps = [ }, function() { ok(true, "test Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(screenBright); req.onsuccess = function () { ok(true, "set3 done"); @@ -237,7 +233,7 @@ var steps = [ }, function() { ok(true, "removing Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); navigator.mozSettings.removeObserver("screen.brightness", observerWithNext); req = lock.set(screenBright); req.onsuccess = function () { @@ -250,7 +246,7 @@ var steps = [ }, function() { ok(true, "removing Event Listener"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("screen.brightness"); req.onsuccess = function () { ok(true, "get5 done"); @@ -260,7 +256,7 @@ var steps = [ }, function() { ok(true, "Clear DB"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -270,7 +266,7 @@ var steps = [ }, function () { ok(true, "Deleting database"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); @@ -279,7 +275,7 @@ var steps = [ req.onerror = onFailure; }, function () { - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); navigator.mozSettings.onsettingchange = onComplexSettingschangeWithNext; req2 = navigator.mozSettings.createLock().set({'test.key': cset}); req2.onsuccess = function () { diff --git a/dom/settings/tests/test_settings_permissions.html b/dom/settings/tests/test_settings_permissions.html index 69114f886bb6..26b5d295fcf3 100644 --- a/dom/settings/tests/test_settings_permissions.html +++ b/dom/settings/tests/test_settings_permissions.html @@ -21,10 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={678695} "use strict"; -if (SpecialPowers.isMainProcess()) { - SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm"); -} - +var url = SimpleTest.getTestFileURL("file_loadserver.js"); +var script = SpecialPowers.loadChromeScript(url); SpecialPowers.removePermission("settings-read", document); SpecialPowers.removePermission("settings-write", document); SpecialPowers.addPermission("settings-api-read", true, document); @@ -80,21 +78,19 @@ function check(o1, o2) { var req, req2, req3, req4, req5, req6; var index = 0; -var mozSettings = navigator.mozSettings; - var steps = [ // Can't delete database here since that requires permissions we don't want // to give the page. function () { ok(true, "Setting wallpaper"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wallpaper); req.onsuccess = function () { ok(true, "set done"); } req.onerror = onFailure; - var lock2 = mozSettings.createLock(); + var lock2 = navigator.mozSettings.createLock(); req2 = lock2.get("wallpaper.image"); req2.onsuccess = function () { is(Object.keys(req2.result).length, 1, "length 1"); @@ -106,7 +102,7 @@ var steps = [ }, function () { ok(true, "Get Wifi"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.get("wifi.enabled"); req.onerror = function () { ok(true, "get failed (expected)"); @@ -116,7 +112,7 @@ var steps = [ }, function () { ok(true, "Set Wifi"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(wifi); req.onerror = function () { ok(true, "set failed (expected)"); @@ -126,7 +122,7 @@ var steps = [ }, function () { ok(true, "Set combination (1 valid 1 not valid)"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(combination); req.onerror = function () { ok(true, "set failed (expected)"); @@ -136,7 +132,7 @@ var steps = [ }, function () { ok(true, "All requests on a failed lock should fail"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); lock.onsettingstransactionfailure = function (evt) { ok(evt.error == "Lock failed a permissions check, all requests now failing.", "transaction failure on permissions error message correct."); ok(true, "transaction failed (expected) "); @@ -157,7 +153,7 @@ var steps = [ }, function () { ok(true, "Set combination (1 valid 1 not valid)"); - var lock = mozSettings.createLock(); + var lock = navigator.mozSettings.createLock(); req = lock.set(combination); req.onerror = function () { ok(true, "set failed (expected)"); From af2b51147933ec64cac5cc1a3b2bc68241e7a548 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 22 Dec 2014 13:07:28 -0500 Subject: [PATCH 60/64] Bug 1066383 - Touch CLOBBER due to the IDL removal not being properly caught by the build system. CLOSED TREE --- CLOBBER | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CLOBBER b/CLOBBER index 37b2285a1c32..d15932f19fab 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,9 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1105308 - Cleanup BluetoothUtils.{cpp,h} - -This patch set moves some files around and requires a rebuild -of the build system's dependency information. - -Merge day clobber +Bug 1066383 - Clobber needed due to build system not reliably picking up an IDL removal. From 37ee010f53fa34369d1f98d04cc54799d6c64b1a Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 10:27:17 -0800 Subject: [PATCH 61/64] Bumping gaia.json for 1 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/21dadcc13619 Author: Johan Lorenzo Desc: Revert "Bug 1114560 - Add a test to delete the whole phone number on the dialer" This reverts commit 69bd4c80954e3ba48f8ce71f24939108f1e69829. --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 3986586365a8..9a69282f5f2f 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "6a113da9e00fa2afaad2d77923f306063f84fc05", + "revision": "21dadcc1361926d0a34141a8dde21c5cb41e4428", "repo_path": "integration/gaia-central" } From b1a0a0363af97adfb3ddeb55cc8e8bcb2e54d9f0 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 10:36:56 -0800 Subject: [PATCH 62/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 99503f549b53..63ce83da8a50 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 983c33420e87..c45222a73531 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 818400b1832e..203ff6c22c26 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index a239cf40bf05..5351f7be321e 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 983c33420e87..c45222a73531 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 2bc525efaf4c..98e088839b70 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 4ea725dd6cec..a3c2b64b1337 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index 0dec11562728..6a948a6f7367 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index a7f240d75aa7..1ad6f6e3052e 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 7c3bb697b134..0cdf83629e07 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 6728f0bc7a62..184dd779d296 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + From 4d1767818e404c5918157ced1da3d07596fdf488 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 11:02:16 -0800 Subject: [PATCH 63/64] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/b60aedd37a5c Author: Guillaume C. Marty Desc: Merge pull request #26883 from gmarty/Bug-1093958-Lockscreen-only-displays-battery-icon-not-other-icons Bug 1093958 - Lockscreen only displays battery icon, not other icons ======== https://hg.mozilla.org/integration/gaia-central/rev/079728f35f27 Author: Guillaume Marty Desc: Bug 1093958 - Lockscreen only displays battery icon, not other icons --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 9a69282f5f2f..579ec00f4971 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "21dadcc1361926d0a34141a8dde21c5cb41e4428", + "revision": "b60aedd37a5ccdb71893d31761988bcc17a82676", "repo_path": "integration/gaia-central" } From 880c471b349483f927fbf25f08fec3c656bbf8cd Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Mon, 22 Dec 2014 11:06:58 -0800 Subject: [PATCH 64/64] Bumping manifests a=b2g-bump --- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/flame/sources.xml | 2 +- b2g/config/hamachi/sources.xml | 2 +- b2g/config/helix/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/wasabi/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 63ce83da8a50..e30db4ea6c80 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index c45222a73531..3e01ee2c593d 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 203ff6c22c26..05f78ea89633 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 5351f7be321e..84d94e8a5902 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index c45222a73531..3e01ee2c593d 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 98e088839b70..16389265c201 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index a3c2b64b1337..33f051fbb55d 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index 6a948a6f7367..f5626e39599b 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index 1ad6f6e3052e..3509fad831b5 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 0cdf83629e07..0d6d16d4654b 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index 184dd779d296..6fd6417cb997 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - +