From 5600b41cb1fbdfa927ade8a773f9217ae2586cf1 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 22 Dec 2014 12:38:41 +0100 Subject: [PATCH 01/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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 81f7e51dc6f23d23bdb391f5642d176a5bef38c2 Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Mon, 22 Dec 2014 03:49:00 -0500 Subject: [PATCH 11/21] 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 12/21] 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 13/21] 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 14/21] 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 15/21] 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 16/21] 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 17/21] 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 18/21] 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 19/21] 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 20/21] 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 af2b51147933ec64cac5cc1a3b2bc68241e7a548 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 22 Dec 2014 13:07:28 -0500 Subject: [PATCH 21/21] 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.