Merge m-i to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2014-12-24 15:38:41 -08:00
commit dc8c1c5904
121 changed files with 2391 additions and 687 deletions

View File

@ -8,7 +8,7 @@ OS_CXXFLAGS := $(filter-out -W%,$(OS_CXXFLAGS)) -fsyntax-only -Xclang -verify
include $(topsrcdir)/config/rules.mk
target:: $(OBJS)
export:: $(OBJS)
# We don't actually build anything.
.PHONY: $(OBJS)

View File

@ -642,8 +642,13 @@ NS_GetStreamForMediaStreamURI(nsIURI* aURI, mozilla::DOMMediaStream** aStream)
{
NS_ASSERTION(IsMediaStreamURI(aURI), "Only call this with mediastream URIs");
nsISupports* dataObject = GetDataObject(aURI);
if (!dataObject) {
return NS_ERROR_DOM_BAD_URI;
}
*aStream = nullptr;
return CallQueryInterface(GetDataObject(aURI), aStream);
return CallQueryInterface(dataObject, aStream);
}
NS_IMETHODIMP

View File

@ -1343,7 +1343,6 @@ BrowserElementChild.prototype = {
stateDesc = '???';
}
// XXX Until bug 764496 is fixed, this will always return false.
var isEV = !!(state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL);
sendAsyncMsg('securitychange', { state: stateDesc, extendedValidation: isEV });

View File

@ -10,6 +10,7 @@
#include "AppleVDADecoder.h"
#include "AppleVDALinker.h"
#include "mp4_demuxer/DecoderData.h"
#include "mp4_demuxer/H264.h"
#include "MP4Decoder.h"
#include "MediaData.h"
#include "MacIOSurfaceImage.h"
@ -43,9 +44,28 @@ AppleVDADecoder::AppleVDADecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
{
MOZ_COUNT_CTOR(AppleVDADecoder);
// TODO: Verify aConfig.mime_type.
// Retrieve video dimensions from H264 SPS NAL.
mPictureWidth = mConfig.image_width;
mPictureHeight = mConfig.image_height;
mMaxRefFrames = 4;
mp4_demuxer::SPSData spsdata;
if (mp4_demuxer::H264::DecodeSPSFromExtraData(mConfig.extra_data, spsdata) &&
spsdata.pic_width && spsdata.pic_height) {
mPictureWidth = spsdata.pic_width;
mPictureHeight = spsdata.pic_height;
// max_num_ref_frames determines the size of the sliding window
// we need to queue that many frames in order to guarantee proper
// pts frames ordering. Use a minimum of 4 to ensure proper playback of
// non compliant videos.
mMaxRefFrames =
(spsdata.max_num_ref_frames + 1) > mMaxRefFrames ?
spsdata.max_num_ref_frames + 1 : mMaxRefFrames;
}
LOG("Creating AppleVDADecoder for %dx%d h.264 video",
mConfig.image_width,
mConfig.image_height
mPictureWidth,
mPictureHeight
);
}
@ -270,17 +290,9 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
// in composition order.
mReorderQueue.Push(data);
// Assume a frame with a PTS <= current DTS is ready.
while (mReorderQueue.Length() > 0) {
while (mReorderQueue.Length() > mMaxRefFrames) {
nsRefPtr<VideoData> readyData = mReorderQueue.Pop();
if (readyData->mTime <= aFrameRef->decode_timestamp) {
LOG("returning queued frame with pts %lld", readyData->mTime);
mCallback->Output(readyData);
} else {
LOG("requeued frame with pts %lld > %lld",
readyData->mTime, aFrameRef->decode_timestamp);
mReorderQueue.Push(readyData);
break;
}
}
LOG("%llu decoded frames queued",
static_cast<unsigned long long>(mReorderQueue.Length()));
@ -411,11 +423,11 @@ AppleVDADecoder::CreateDecoderSpecification()
AutoCFRelease<CFNumberRef> avc_width =
CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&mConfig.image_width);
&mPictureWidth);
AutoCFRelease<CFNumberRef> avc_height =
CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,
&mConfig.image_height);
&mPictureHeight);
AutoCFRelease<CFNumberRef> avc_format =
CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type,

View File

@ -90,6 +90,9 @@ public:
MediaDataDecoderCallback* mCallback;
nsRefPtr<layers::ImageContainer> mImageContainer;
ReorderQueue mReorderQueue;
uint32_t mPictureWidth;
uint32_t mPictureHeight;
uint32_t mMaxRefFrames;
private:
VDADecoder mDecoder;

View File

@ -11,6 +11,7 @@
#include "AppleVTDecoder.h"
#include "AppleVTLinker.h"
#include "mp4_demuxer/DecoderData.h"
#include "mp4_demuxer/H264.h"
#include "MediaData.h"
#include "MacIOSurfaceImage.h"
#include "mozilla/ArrayUtils.h"
@ -275,8 +276,8 @@ AppleVTDecoder::InitializeSession()
rv = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
kCMVideoCodecType_H264,
mConfig.image_width,
mConfig.image_height,
mPictureWidth,
mPictureHeight,
extensions,
&mFormat);
if (rv != noErr) {

View File

@ -265,7 +265,7 @@ private:
void AssertInvariants() const;
#endif
SharedMemory* mSegment;
SharedMemory* MOZ_NON_OWNING_REF mSegment;
void* mData;
size_t mSize;
id_t mId;

View File

@ -13,8 +13,6 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
GENERATED_INCLUDES += ['/ipc/ipdl/_ipdlheaders']
# We #include some things in the dom/plugins/ directory that rely on
# toolkit libraries.
CXXFLAGS += CONFIG['TK_CFLAGS']

View File

@ -13,6 +13,7 @@
#include "builtin/SIMD.h"
#include "mozilla/IntegerTypeTraits.h"
#include "jsapi.h"
#include "jsfriendapi.h"
@ -147,12 +148,17 @@ static bool SignMask(JSContext *cx, unsigned argc, Value *vp)
return false;
}
Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
int32_t mx = data[0] < 0.0 ? 1 : 0;
int32_t my = data[1] < 0.0 ? 1 : 0;
int32_t mz = data[2] < 0.0 ? 1 : 0;
int32_t mw = data[3] < 0.0 ? 1 : 0;
int32_t result = mx | my << 1 | mz << 2 | mw << 3;
// Load the data as integer so that we treat the sign bit consistently,
// since -0.0 is not less than zero, but it still has the sign bit set.
typedef typename mozilla::SignedStdintTypeForSize<sizeof(Elem)>::Type Int;
static_assert(SimdType::lanes * sizeof(Int) <= jit::Simd128DataSize,
"signMask access should respect the bounds of the type");
const Elem *elems = reinterpret_cast<const Elem *>(typedObj.typedMem());
int32_t result = 0;
for (unsigned i = 0; i < SimdType::lanes; ++i) {
Int x = mozilla::BitwiseCast<Int>(elems[i]);
result |= (x < 0) << i;
}
args.rval().setInt32(result);
return true;
}
@ -296,7 +302,6 @@ bool
SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
const unsigned LANES = 4;
Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>());
if (args.length() == 1) {
@ -310,12 +315,6 @@ SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
return true;
}
if (args.length() < LANES) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
args.callee().getClass()->name, "3", "s");
return false;
}
Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0));
if (!result)
return false;
@ -324,7 +323,7 @@ SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
case SimdTypeDescr::TYPE_INT32: {
int32_t *mem = reinterpret_cast<int32_t*>(result->typedMem());
for (unsigned i = 0; i < 4; i++) {
if (!ToInt32(cx, args[i], &mem[i]))
if (!ToInt32(cx, args.get(i), &mem[i]))
return false;
}
break;
@ -332,7 +331,7 @@ SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
case SimdTypeDescr::TYPE_FLOAT32: {
float *mem = reinterpret_cast<float*>(result->typedMem());
for (unsigned i = 0; i < 4; i++) {
if (!RoundFloat32(cx, args[i], &mem[i]))
if (!RoundFloat32(cx, args.get(i), &mem[i]))
return false;
}
break;

View File

@ -1,3 +1,8 @@
if (typeof SIMD === 'undefined' || !isSimdAvailable()) {
print("won't run tests as simd extensions aren't activated yet");
quit(0);
}
(function(global) {
"use asm";
var frd = global.Math.fround;

View File

@ -188,7 +188,7 @@ assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f() { var x=i4(0,-
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var Infinity = glob.Infinity; function f() { var x=f4(0,0,0,0); x=f4(f32(1), f32(-13.37), f32(42), f32(-Infinity)); return x.signMask | 0 } return f'), this)(), 0b1010);
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var Infinity = glob.Infinity; function f() { var x=f4(0,0,0,0); x=f4(f32(-1), f32(0), f32(-0.000001), f32(Infinity)); return x.signMask | 0 } return f'), this)(), 0b0101);
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var NaN = glob.NaN; function f() { var x=f4(0,0,0,0); x=f4(f32(-1), f32(NaN), f32(3.), f32(4.)); return x.signMask | 0 } return f'), this)(), 0b0001);
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + 'var NaN = glob.NaN; function f() { var x=f4(0,0,0,0); x=f4(f32(-1), f32(NaN), f32(-0), f32(0)); return x.signMask | 0 } return f'), this)(), 0b0101);
// 1.3.3. Variable assignments
assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4();} return f");

View File

@ -1791,6 +1791,11 @@ CodeGenerator::visitNop(LNop *lir)
{
}
void
CodeGenerator::visitMop(LMop *lir)
{
}
void
CodeGenerator::visitOsiPoint(LOsiPoint *lir)
{

View File

@ -63,6 +63,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitLabel(LLabel *lir);
void visitNop(LNop *lir);
void visitMop(LMop *lir);
void visitOsiPoint(LOsiPoint *lir);
void visitGoto(LGoto *lir);
void visitTableSwitch(LTableSwitch *ins);

View File

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

View File

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

View File

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

View File

@ -43,6 +43,12 @@ class LNop : public LInstructionHelper<0, 0, 0>
LIR_HEADER(Nop)
};
class LMop : public LInstructionHelper<0, 0, 0>
{
public:
LIR_HEADER(Mop)
};
// An LOsiPoint captures a snapshot after a call and ensures enough space to
// patch in a call to the invalidation mechanism.
//

View File

@ -10,6 +10,7 @@
#define LIR_COMMON_OPCODE_LIST(_) \
_(Label) \
_(Nop) \
_(Mop) \
_(OsiPoint) \
_(MoveGroup) \
_(Integer) \

View File

@ -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);
@ -4117,10 +4117,20 @@ LIRGenerator::visitInstruction(MInstruction *ins)
ins->setInWorklistUnchecked();
#endif
// If we added a Nop for this instruction, we'll also add a Mop, so that
// that live-ranges for fixed register defs, which with LSRA extend through
// the Nop so that they can extend through the OsiPoint don't, with their
// one-extra extension, extend into a position where they use the input
// move group for the following instruction.
bool needsMop = !current->instructions().empty() && current->rbegin()->isNop();
// If no safepoint was created, there's no need for an OSI point.
if (LOsiPoint *osiPoint = popOsiPoint())
add(osiPoint);
if (needsMop)
add(new(alloc()) LMop);
return !gen->errored();
}

View File

@ -376,7 +376,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<ArrayObject>();
MNewArrayDynamicLength *ins =
@ -389,7 +389,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;
@ -1036,10 +1036,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) {
@ -1214,8 +1214,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;
@ -1366,14 +1366,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;
@ -2031,9 +2031,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();
@ -2059,9 +2059,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();
@ -2227,9 +2227,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());

View File

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

View File

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

View File

@ -155,6 +155,9 @@ RangeAnalysis::addBetaNodes()
MCompare *compare = test->getOperand(0)->toCompare();
if (compare->compareType() == MCompare::Compare_Unknown)
continue;
// TODO: support unsigned comparisons
if (compare->compareType() == MCompare::Compare_UInt32)
continue;
@ -174,12 +177,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 +1313,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 +1331,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 +1356,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 +2737,7 @@ CloneForDeadBranches(TempAllocator &alloc, MInstruction *candidate)
candidate->block()->insertBefore(candidate, clone);
if (!candidate->isConstant()) {
if (!candidate->isConstantValue()) {
MOZ_ASSERT(clone->canRecoverOnBailout());
clone->setRecoveredOnBailout();
}

View File

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

View File

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

View File

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

View File

@ -127,6 +127,7 @@ BEGIN_TEST(testJitRangeAnalysis_MathSignBeta)
MConstant *cm0 = MConstant::New(func.alloc, DoubleValue(-0.0));
entry->add(cm0);
MCompare *cmp = MCompare::New(func.alloc, p, c0, JSOP_LT);
cmp->setCompareType(MCompare::Compare_Double);
entry->add(cmp);
entry->end(MTest::New(func.alloc, cmp, thenBlock, elseBlock));
@ -144,6 +145,7 @@ BEGIN_TEST(testJitRangeAnalysis_MathSignBeta)
// {
// if (p >= 0)
MCompare *elseCmp = MCompare::New(func.alloc, p, c0, JSOP_GE);
elseCmp->setCompareType(MCompare::Compare_Double);
elseBlock->add(elseCmp);
elseBlock->end(MTest::New(func.alloc, elseCmp, elseThenBlock, elseElseBlock));

View File

@ -1,66 +0,0 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1061229;
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
var {StructType, int32} = TypedObject;
var summary = 'constructors used as coercions';
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
function assertCaught(f) {
var caught = false;
var args = Array.slice(arguments, 1);
try {
f.apply(null, args);
} catch (e) {
caught = true;
print(e)
}
assertEq(caught, true);
}
function test() {
var x = int32x4(1, 2, 3, 4);
var y = int32x4(x);
assertEq(x, y);
assertEq(y.x, x.x);
assertEq(y.x, 1);
assertEq(y.y, x.y);
assertEq(y.y, 2);
assertEq(y.z, x.z);
assertEq(y.z, 3);
assertEq(y.w, x.w);
assertEq(y.w, 4);
assertCaught(int32x4, 3);
assertCaught(int32x4, float32x4(1, 2, 3, 4));
assertCaught(int32x4, 'pony x 4');
var x = float32x4(NaN, 13.37, -Infinity, 4);
var y = float32x4(x);
assertEq(x, y);
assertEq(y.x, x.x);
assertEq(y.x, Math.fround(NaN));
assertEq(y.y, x.y);
assertEq(y.y, Math.fround(13.37));
assertEq(y.z, x.z);
assertEq(y.z, Math.fround(-Infinity));
assertEq(y.w, x.w);
assertEq(y.w, Math.fround(4));
assertCaught(float32x4, 3);
assertCaught(float32x4, int32x4(1, 2, 3, 4));
assertCaught(float32x4, 'pony x 4');
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

View File

@ -0,0 +1,66 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
function test() {
// Constructors.
assertEqX4(int32x4(1, 2, 3, 4), [1,2,3,4]);
assertEqX4(int32x4(1, 2, 3), [1,2,3,0]);
assertEqX4(int32x4(1, 2), [1,2,0,0]);
// The 1-argument form is reserved for coercions.
assertEqX4(int32x4(), [0,0,0,0]);
assertEqX4(int32x4(1, 2, 3, 4, 5), [1,2,3,4]);
assertEqX4(int32x4(1, 2, 3, 4, 5, 6), [1,2,3,4]);
assertEqX4(float32x4(1, 2, 3, 4), [1,2,3,4]);
assertEqX4(float32x4(1, 2, 3), [1,2,3,NaN]);
assertEqX4(float32x4(1, 2), [1,2,NaN,NaN]);
// The 1-argument form is reserved for coercions.
assertEqX4(float32x4(), [NaN,NaN,NaN,NaN]);
assertEqX4(float32x4(1, 2, 3, 4, 5), [1,2,3,4]);
assertEqX4(float32x4(1, 2, 3, 4, 5, 6), [1,2,3,4]);
// Constructors used as coercion.
var x = int32x4(1, 2, 3, 4);
var y = int32x4(x);
assertEq(x, y);
assertEq(y.x, x.x);
assertEq(y.x, 1);
assertEq(y.y, x.y);
assertEq(y.y, 2);
assertEq(y.z, x.z);
assertEq(y.z, 3);
assertEq(y.w, x.w);
assertEq(y.w, 4);
assertThrowsInstanceOf(() => int32x4(3), TypeError);
assertThrowsInstanceOf(() => int32x4(float32x4(1,2,3,4)), TypeError);
assertThrowsInstanceOf(() => int32x4('pony x 4'), TypeError);
var x = float32x4(NaN, 13.37, -Infinity, 4);
var y = float32x4(x);
assertEq(x, y);
assertEq(y.x, x.x);
assertEq(y.x, Math.fround(NaN));
assertEq(y.y, x.y);
assertEq(y.y, Math.fround(13.37));
assertEq(y.z, x.z);
assertEq(y.z, Math.fround(-Infinity));
assertEq(y.w, x.w);
assertEq(y.w, Math.fround(4));
assertThrowsInstanceOf(() => float32x4(3), TypeError);
assertThrowsInstanceOf(() => float32x4(int32x4(1,2,3,4)), TypeError);
assertThrowsInstanceOf(() => float32x4('pony x 4'), TypeError);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

View File

@ -0,0 +1,33 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
function test_float32x4() {
var v, w;
for ([v, w] of [[float32x4(-1, 20, 30, 4), 0b0001],
[float32x4(9.999, 2.1234, 30.4443, -4), 0b1000],
[float32x4(0, -Infinity, +Infinity, -0), 0b1010]])
{
assertEq(v.signMask, w);
}
if (typeof reportCompare === "function")
reportCompare(true, true);
}
function test_int32x4() {
var v, w;
for ([v, w] of [[int32x4(-1, 20, 30, 4), 0b0001],
[int32x4(10, 2, 30.2, -4), 0b1000],
[int32x4(0, 0x80000000, 0x7fffffff, -0), 0b0010]])
{
assertEq(v.signMask, w);
}
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test_float32x4();
test_int32x4();

View File

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "RubyUtils.h"
#include "nsIFrame.h"
using namespace mozilla;
NS_DECLARE_FRAME_PROPERTY(ReservedISize, nullptr);
union NSCoordValue
{
nscoord mCoord;
void* mPointer;
static_assert(sizeof(nscoord) <= sizeof(void*),
"Cannot store nscoord in pointer");
};
/* static */ void
RubyUtils::SetReservedISize(nsIFrame* aFrame, nscoord aISize)
{
MOZ_ASSERT(IsExpandableRubyBox(aFrame));
NSCoordValue value = { aISize };
aFrame->Properties().Set(ReservedISize(), value.mPointer);
}
/* static */ void
RubyUtils::ClearReservedISize(nsIFrame* aFrame)
{
MOZ_ASSERT(IsExpandableRubyBox(aFrame));
aFrame->Properties().Remove(ReservedISize());
}
/* static */ nscoord
RubyUtils::GetReservedISize(nsIFrame* aFrame)
{
MOZ_ASSERT(IsExpandableRubyBox(aFrame));
NSCoordValue value;
value.mPointer = aFrame->Properties().Get(ReservedISize());
return value.mCoord;
}

View File

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_RubyUtils_h_
#define mozilla_RubyUtils_h_
#include "nsGkAtoms.h"
#include "nsIFrame.h"
namespace mozilla {
/**
* Reserved ISize
*
* With some exceptions, each ruby internal box has two isizes, which
* are the reflowed isize and the final isize. The reflowed isize is
* what a box itself needs. It is determined when the box gets reflowed.
*
* The final isize is what a box should be as the final result. For a
* ruby base/text box, the final isize is the size of its ruby column.
* For a ruby base/text container, the final isize is the size of its
* ruby segment. The final isize is never smaller than the reflowed
* isize. It is initially determined when a ruby column/segment gets
* fully reflowed, and may be advanced when a box is expanded, e.g.
* for justification.
*
* The difference between the reflowed isize and the final isize is
* reserved in the line layout after reflowing a box, hence it is called
* "Reserved ISize" here. It is used to expand the ruby boxes from their
* reflowed isize to the final isize during alignment of the line.
*
* There are three exceptions for the final isize:
* 1. A ruby text container has a larger final isize only if it is for
* a span or collapsed annotations.
* 2. A ruby base container has a larger final isize only if at least
* one of its ruby text containers does.
* 3. If a ruby text container has a larger final isize, its children
* must not have.
*/
class RubyUtils
{
public:
static inline bool IsExpandableRubyBox(nsIFrame* aFrame)
{
nsIAtom* type = aFrame->GetType();
return type == nsGkAtoms::rubyBaseFrame ||
type == nsGkAtoms::rubyTextFrame ||
type == nsGkAtoms::rubyBaseContainerFrame ||
type == nsGkAtoms::rubyTextContainerFrame;
}
static void SetReservedISize(nsIFrame* aFrame, nscoord aISize);
static void ClearReservedISize(nsIFrame* aFrame);
static nscoord GetReservedISize(nsIFrame* aFrame);
};
}
#endif /* !defined(mozilla_RubyUtils_h_) */

View File

@ -94,6 +94,7 @@ UNIFIED_SOURCES += [
'nsTextRunTransformations.cpp',
'nsVideoFrame.cpp',
'nsViewportFrame.cpp',
'RubyUtils.cpp',
'ScrollbarActivity.cpp',
'StickyScrollContainer.cpp',
'TextOverflow.cpp',

View File

@ -762,8 +762,12 @@ public:
GetLogicalNormalPosition(mozilla::WritingMode aWritingMode,
nscoord aContainerWidth) const
{
// Subtract the width of this frame from the container width to get
// the correct position in rtl frames where the origin is on the
// right instead of the left
return mozilla::LogicalPoint(aWritingMode,
GetNormalPosition(), aContainerWidth);
GetNormalPosition(),
aContainerWidth - mRect.width);
}
virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)

View File

@ -24,6 +24,7 @@
#include "nsTextFrame.h"
#include "nsStyleStructInlines.h"
#include "nsBidiPresUtils.h"
#include "RubyUtils.h"
#include <algorithm>
#ifdef DEBUG
@ -77,7 +78,8 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
mInFirstLetter(false),
mHasBullet(false),
mDirtyNextLine(false),
mLineAtStart(false)
mLineAtStart(false),
mHasRuby(false)
{
MOZ_ASSERT(aOuterReflowState, "aOuterReflowState must not be null");
NS_ASSERTION(aFloatManager || aOuterReflowState->frame->GetType() ==
@ -96,6 +98,9 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
mTotalPlacedFrames = 0;
mBStartEdge = 0;
mTrimmableISize = 0;
#ifdef DEBUG
mFinalLineBSize = nscoord_MIN;
#endif
mInflationMinFontSize =
nsLayoutUtils::InflationMinFontSizeFor(aOuterReflowState->frame);
@ -193,11 +198,6 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
psd->mIEnd = aICoord + aISize;
mContainerWidth = aContainerWidth;
PerFrameData* pfd = NewPerFrameData(mBlockReflowState->frame);
pfd->mAscent = 0;
pfd->mSpan = psd;
psd->mFrame = pfd;
// If we're in a constrained height frame, then we don't allow a
// max line box width to take effect.
if (!(LineContainerFrame()->GetStateBits() &
@ -241,6 +241,11 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
psd->mICoord += indent;
}
PerFrameData* pfd = NewPerFrameData(mBlockReflowState->frame);
pfd->mAscent = 0;
pfd->mSpan = psd;
psd->mFrame = pfd;
}
void
@ -466,12 +471,12 @@ nsLineLayout::AttachFrameToBaseLineLayout(PerFrameData* aFrame)
PerFrameData* baseFrame = mBaseLineLayout->LastFrame();
MOZ_ASSERT(aFrame && baseFrame);
MOZ_ASSERT(!aFrame->GetFlag(PFD_ISLINKEDTOBASE),
MOZ_ASSERT(!aFrame->mIsLinkedToBase,
"The frame must not have been linked with the base");
aFrame->mNextAnnotation = baseFrame->mNextAnnotation;
baseFrame->mNextAnnotation = aFrame;
aFrame->SetFlag(PFD_ISLINKEDTOBASE, true);
aFrame->mIsLinkedToBase = true;
}
int32_t
@ -559,7 +564,7 @@ nsLineLayout::UnlinkFrame(PerFrameData* pfd)
{
while (nullptr != pfd) {
PerFrameData* next = pfd->mNext;
if (pfd->GetFlag(PFD_ISLINKEDTOBASE)) {
if (pfd->mIsLinkedToBase) {
// This frame is linked to a ruby base, and should not be freed
// now. Just unlink it from the span. It will be freed when its
// base frame gets unlinked.
@ -646,9 +651,20 @@ nsLineLayout::NewPerFrameData(nsIFrame* aFrame)
pfd->mNext = nullptr;
pfd->mPrev = nullptr;
pfd->mNextAnnotation = nullptr;
pfd->mFlags = 0; // all flags default to false
pfd->mFrame = aFrame;
// all flags default to false
pfd->mRelativePos = false;
pfd->mIsTextFrame = false;
pfd->mIsNonEmptyTextFrame = false;
pfd->mIsNonWhitespaceTextFrame = false;
pfd->mIsLetterFrame = false;
pfd->mRecomputeOverflow = false;
pfd->mIsBullet = false;
pfd->mSkipWhenTrimmingWhitespace = false;
pfd->mIsEmpty = false;
pfd->mIsLinkedToBase = false;
WritingMode frameWM = aFrame->GetWritingMode();
WritingMode lineWM = mRootSpan->mWritingMode;
pfd->mBounds = LogicalRect(lineWM);
@ -856,9 +872,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
reflowState.ComputedLogicalMargin().ConvertTo(lineWM, stateWM);
pfd->mBorderPadding =
reflowState.ComputedLogicalBorderPadding().ConvertTo(lineWM, stateWM);
pfd->SetFlag(PFD_RELATIVEPOS,
reflowState.mStyleDisplay->IsRelativelyPositionedStyle());
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
pfd->mRelativePos =
reflowState.mStyleDisplay->IsRelativelyPositionedStyle();
if (pfd->mRelativePos) {
pfd->mOffsets =
reflowState.ComputedLogicalOffsets().ConvertTo(frameWM, stateWM);
}
@ -912,6 +928,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
}
pfd->mJustificationInfo = mJustificationInfo;
mJustificationInfo = JustificationInfo();
// See if the frame is a placeholderFrame and if it is process
// the float. At the same time, check if the frame has any non-collapsed-away
@ -923,7 +940,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
} else {
if (nsGkAtoms::placeholderFrame == frameType) {
isEmpty = true;
pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, true);
pfd->mSkipWhenTrimmingWhitespace = true;
nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
if (outOfFlowFrame) {
// Add mTrimmableISize to the available width since if the line ends
@ -950,26 +967,25 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
}
else if (isText) {
// Note non-empty text-frames for inline frame compatibility hackery
pfd->SetFlag(PFD_ISTEXTFRAME, true);
pfd->mIsTextFrame = true;
nsTextFrame* textFrame = static_cast<nsTextFrame*>(pfd->mFrame);
isEmpty = !textFrame->HasNoncollapsedCharacters();
if (!isEmpty) {
pfd->SetFlag(PFD_ISNONEMPTYTEXTFRAME, true);
pfd->mIsNonEmptyTextFrame = true;
nsIContent* content = textFrame->GetContent();
const nsTextFragment* frag = content->GetText();
if (frag) {
pfd->SetFlag(PFD_ISNONWHITESPACETEXTFRAME,
!content->TextIsOnlyWhitespace());
pfd->mIsNonWhitespaceTextFrame = !content->TextIsOnlyWhitespace();
}
}
}
else if (nsGkAtoms::brFrame == frameType) {
pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, true);
pfd->mSkipWhenTrimmingWhitespace = true;
isEmpty = false;
} else {
if (nsGkAtoms::letterFrame==frameType) {
pfd->SetFlag(PFD_ISLETTERFRAME, true);
pfd->mIsLetterFrame = true;
}
if (pfd->mSpan) {
isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty();
@ -978,7 +994,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
}
}
}
pfd->SetFlag(PFD_ISEMPTY, isEmpty);
pfd->mIsEmpty = isEmpty;
mFloatManager->Untranslate(oldWM, tPt);
@ -1053,7 +1069,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
bool continuingTextRun = aFrame->CanContinueTextRun();
// Clear any residual mTrimmableISize if this isn't a text frame
if (!continuingTextRun && !pfd->GetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE)) {
if (!continuingTextRun && !pfd->mSkipWhenTrimmingWhitespace) {
mTrimmableISize = 0;
}
@ -1074,6 +1090,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
// nonempty leaf content has been placed
mLineAtStart = false;
}
if (nsGkAtoms::rubyFrame == frameType) {
mHasRuby = true;
}
}
// Place the frame, updating aBounds with the final size and
@ -1220,7 +1239,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) ||
pfd->mFrame->LastInFlow()->GetNextContinuation() ||
pfd->mFrame->FrameIsNonLastInIBSplit()) &&
!pfd->GetFlag(PFD_ISLETTERFRAME) &&
!pfd->mIsLetterFrame &&
pfd->mFrame->StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
pfd->mMargin.IEnd(lineWM) = 0;
@ -1395,7 +1414,7 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
WritingMode lineWM = mRootSpan->mWritingMode;
PerFrameData* pfd = NewPerFrameData(aFrame);
mRootSpan->AppendFrame(pfd);
pfd->SetFlag(PFD_ISBULLET, true);
pfd->mIsBullet = true;
if (aMetrics.BlockStartAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
pfd->mAscent = aFrame->GetLogicalBaseline(lineWM);
} else {
@ -1513,21 +1532,23 @@ nsLineLayout::VerticalAlignLine()
}
PlaceTopBottomFrames(psd, -mBStartEdge, lineBSize);
// Fill in returned line-box and max-element-width data
mLineBox->SetBounds(lineWM,
psd->mIStart, mBStartEdge,
psd->mICoord - psd->mIStart, lineBSize,
mContainerWidth);
mFinalLineBSize = lineBSize;
mLineBox->SetLogicalAscent(baselineBCoord - mBStartEdge);
if (mGotLineBox) {
// Fill in returned line-box and max-element-width data
mLineBox->SetBounds(lineWM,
psd->mIStart, mBStartEdge,
psd->mICoord - psd->mIStart, lineBSize,
mContainerWidth);
mLineBox->SetLogicalAscent(baselineBCoord - mBStartEdge);
#ifdef NOISY_BLOCKDIR_ALIGN
printf(
" [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d\n",
mLineBox->GetBounds().IStart(lineWM), mLineBox->GetBounds().BStart(lineWM),
mLineBox->GetBounds().ISize(lineWM), mLineBox->GetBounds().BSize(lineWM),
mFinalLineBSize, mLineBox->GetLogicalAscent());
printf(
" [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d\n",
mLineBox->GetBounds().IStart(lineWM), mLineBox->GetBounds().BStart(lineWM),
mLineBox->GetBounds().ISize(lineWM), mLineBox->GetBounds().BSize(lineWM),
mFinalLineBSize, mLineBox->GetLogicalAscent());
#endif
}
}
// Place frames with CSS property vertical-align: top or bottom.
@ -1714,8 +1735,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
// See bug 134580 and bug 155333.
zeroEffectiveSpanBox = true;
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
if (pfd->GetFlag(PFD_ISTEXTFRAME) &&
(pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME) || preMode ||
if (pfd->mIsTextFrame &&
(pfd->mIsNonWhitespaceTextFrame || preMode ||
pfd->mBounds.ISize(mRootSpan->mWritingMode) != 0)) {
zeroEffectiveSpanBox = false;
break;
@ -1759,7 +1780,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
// Special-case for a ::first-letter frame, set the line height to
// the frame block size if the user has left line-height == normal
if (spanFramePFD->GetFlag(PFD_ISLETTERFRAME) &&
if (spanFramePFD->mIsLetterFrame &&
!spanFrame->GetPrevInFlow() &&
spanFrame->StyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal) {
logicalBSize = spanFramePFD->mBounds.BSize(lineWM);
@ -2069,11 +2090,11 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
// "tall" lines around elements like <hr> since the rules of <hr>
// in quirks.css have pseudo text contents with LF in them.
#if 0
if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
if (!pfd->mIsTextFrame) {
#else
// Only consider non empty text frames when line-height=normal
bool canUpdate = !pfd->GetFlag(PFD_ISTEXTFRAME);
if (!canUpdate && pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) {
bool canUpdate = !pfd->mIsTextFrame;
if (!canUpdate && pfd->mIsNonWhitespaceTextFrame) {
canUpdate =
frame->StyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal;
}
@ -2138,7 +2159,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
// (1) and (2) above
bool applyMinLH = !psd->mZeroEffectiveSpanBox || mHasBullet;
bool isLastLine = (!mLineBox->IsLineWrapped() && !mLineEndsInBR);
bool isLastLine = !mGotLineBox ||
(!mLineBox->IsLineWrapped() && !mLineEndsInBR);
if (!applyMinLH && isLastLine) {
nsIContent* blockContent = mRootSpan->mFrame->mFrame->GetContent();
if (blockContent) {
@ -2388,14 +2410,13 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
return true;
}
}
else if (!pfd->GetFlag(PFD_ISTEXTFRAME) &&
!pfd->GetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE)) {
else if (!pfd->mIsTextFrame && !pfd->mSkipWhenTrimmingWhitespace) {
// If we hit a frame on the end that's not text and not a placeholder,
// then there is no trailing whitespace to trim. Stop the search.
*aDeltaISize = 0;
return true;
}
else if (pfd->GetFlag(PFD_ISTEXTFRAME)) {
else if (pfd->mIsTextFrame) {
// Call TrimTrailingWhiteSpace even on empty textframes because they
// might have a soft hyphen which should now appear, changing the frame's
// width
@ -2409,7 +2430,7 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
#endif
if (trimOutput.mChanged) {
pfd->SetFlag(PFD_RECOMPUTEOVERFLOW, true);
pfd->mRecomputeOverflow = true;
}
// Delta width not being zero means that
@ -2451,7 +2472,7 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
}
}
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME) || trimOutput.mChanged) {
if (pfd->mIsNonEmptyTextFrame || trimOutput.mChanged) {
// Pass up to caller so they can shrink their span
*aDeltaISize = trimOutput.mDeltaWidth;
return true;
@ -2475,12 +2496,22 @@ nsLineLayout::TrimTrailingWhiteSpace()
struct nsLineLayout::JustificationComputationState
{
PerFrameData* mFirstParticipant;
PerFrameData* mLastParticipant;
// Whether we are going across a boundary of ruby base, i.e.
// entering one, leaving one, or both.
bool mCrossingRubyBaseBoundary;
JustificationComputationState()
: mFirstParticipant(nullptr)
, mLastParticipant(nullptr)
, mCrossingRubyBaseBoundary(false) { }
};
/**
* This function returns the total number of
* expansion opportunities in the given span.
* Compute the justification info of the given span, and store the
* number of inner opportunities into the frame's justification info.
* It returns the number of non-inner opportunities it detects.
*/
int32_t
nsLineLayout::ComputeFrameJustification(PerSpanData* aPSD,
@ -2489,31 +2520,55 @@ nsLineLayout::ComputeFrameJustification(PerSpanData* aPSD,
NS_ASSERTION(aPSD, "null arg");
NS_ASSERTION(!aState.mLastParticipant || !aState.mLastParticipant->mSpan,
"Last participant shall always be a leaf frame");
int32_t result = 0;
bool firstChild = true;
int32_t& innerOpportunities =
aPSD->mFrame->mJustificationInfo.mInnerOpportunities;
MOZ_ASSERT(innerOpportunities == 0,
"Justification info should not have been set yet.");
int32_t outerOpportunities = 0;
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd; pfd = pfd->mNext) {
if (!pfd->ParticipatesInJustification()) {
continue;
}
bool isRubyBase = pfd->mFrame->GetType() == nsGkAtoms::rubyBaseFrame;
if (isRubyBase) {
aState.mCrossingRubyBaseBoundary = true;
}
int extraOpportunities = 0;
if (pfd->mSpan) {
PerSpanData* span = pfd->mSpan;
result += ComputeFrameJustification(span, aState);
extraOpportunities = ComputeFrameJustification(span, aState);
innerOpportunities += pfd->mJustificationInfo.mInnerOpportunities;
} else {
const auto& info = pfd->mJustificationInfo;
if (pfd->GetFlag(PFD_ISTEXTFRAME)) {
result += info.mInnerOpportunities;
if (pfd->mIsTextFrame) {
innerOpportunities += info.mInnerOpportunities;
}
PerFrameData* prev = aState.mLastParticipant;
if (prev) {
if (!prev) {
aState.mFirstParticipant = pfd;
} else {
auto& assign = pfd->mJustificationAssignment;
auto& prevAssign = prev->mJustificationAssignment;
const auto& prevInfo = prev->mJustificationInfo;
if (info.mIsStartJustifiable || prevInfo.mIsEndJustifiable) {
result++;
if (!info.mIsStartJustifiable) {
if (info.mIsStartJustifiable ||
prevInfo.mIsEndJustifiable ||
aState.mCrossingRubyBaseBoundary) {
extraOpportunities = 1;
if (aState.mCrossingRubyBaseBoundary) {
// For ruby alignment with value space-around, there is
// always an expansion opportunity at the boundary of a ruby
// base, and it always generates one gap at each side. If we
// don't do it here, the interaction between text align and
// and ruby align could be strange.
prevAssign.mGapsAtEnd = 1;
assign.mGapsAtStart = 1;
} else if (!info.mIsStartJustifiable) {
prevAssign.mGapsAtEnd = 2;
assign.mGapsAtStart = 0;
} else if (!prevInfo.mIsEndJustifiable) {
@ -2527,10 +2582,18 @@ nsLineLayout::ComputeFrameJustification(PerSpanData* aPSD,
}
aState.mLastParticipant = pfd;
aState.mCrossingRubyBaseBoundary = isRubyBase;
}
if (firstChild) {
outerOpportunities = extraOpportunities;
firstChild = false;
} else {
innerOpportunities += extraOpportunities;
}
}
return result;
return outerOpportunities;
}
void
@ -2539,18 +2602,38 @@ nsLineLayout::AdvanceAnnotationInlineBounds(PerFrameData* aPFD,
nscoord aDeltaICoord,
nscoord aDeltaISize)
{
MOZ_ASSERT(aPFD->mFrame->GetType() == nsGkAtoms::rubyTextFrame ||
aPFD->mFrame->GetType() == nsGkAtoms::rubyTextContainerFrame);
nsIFrame* frame = aPFD->mFrame;
nsIAtom* frameType = frame->GetType();
MOZ_ASSERT(frameType == nsGkAtoms::rubyTextFrame ||
frameType == nsGkAtoms::rubyTextContainerFrame);
MOZ_ASSERT(aPFD->mSpan, "rt and rtc should have span.");
PerSpanData* psd = aPFD->mSpan;
WritingMode lineWM = mRootSpan->mWritingMode;
WritingMode frameWM = aPFD->mSpan->mWritingMode;
LogicalRect bounds = aPFD->mFrame->GetLogicalRect(aContainerWidth);
bounds = bounds.ConvertTo(lineWM, frameWM, aContainerWidth);
LogicalRect bounds(lineWM, frame->GetRect(), aContainerWidth);
bounds.IStart(lineWM) += aDeltaICoord;
bounds.ISize(lineWM) += aDeltaISize;
aPFD->mBounds = bounds.ConvertTo(frameWM, lineWM, aContainerWidth);
aPFD->mFrame->SetRect(frameWM, aPFD->mBounds, aContainerWidth);
// Check whether this expansion should be counted into the reserved
// isize or not. When it is a ruby text container, and it has some
// children linked to the base, it must not have reserved isize,
// or its children won't align with their bases. Otherwise, this
// expansion should be reserved. There are two cases a ruby text
// container does not have children linked to the base:
// 1. it is a container for span; 2. its children are collapsed.
// See bug 1055674 for the second case.
if (frameType == nsGkAtoms::rubyTextFrame ||
// This ruby text container is a span.
(psd->mFirstFrame == psd->mLastFrame && psd->mFirstFrame &&
!psd->mFirstFrame->mIsLinkedToBase)) {
nscoord reservedISize = RubyUtils::GetReservedISize(frame);
RubyUtils::SetReservedISize(frame, reservedISize + aDeltaISize);
} else {
// It is a normal ruby text container. Its children will expand
// themselves properly. We only need to expand its own size here.
bounds.ISize(lineWM) += aDeltaISize;
}
aPFD->mBounds = bounds;
aPFD->mFrame->SetRect(lineWM, bounds, aContainerWidth);
}
/**
@ -2578,7 +2661,7 @@ nsLineLayout::ApplyLineJustificationToAnnotations(PerFrameData* aPFD,
// In these cases, their size should not be affected, but we still
// need to move them so that they won't overlap other frames.
PerFrameData* sibling = pfd->mNext;
while (sibling && !sibling->GetFlag(PFD_ISLINKEDTOBASE)) {
while (sibling && !sibling->mIsLinkedToBase) {
AdvanceAnnotationInlineBounds(sibling, containerWidth,
aDeltaICoord + aDeltaISize, 0);
sibling = sibling->mNext;
@ -2597,25 +2680,23 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD,
nscoord deltaICoord = 0;
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nullptr; pfd = pfd->mNext) {
// Don't reposition bullets (and other frames that occur out of X-order?)
if (!pfd->GetFlag(PFD_ISBULLET)) {
if (!pfd->mIsBullet) {
nscoord dw = 0;
WritingMode lineWM = mRootSpan->mWritingMode;
const auto& assign = pfd->mJustificationAssignment;
pfd->mBounds.IStart(lineWM) += deltaICoord;
if (true == pfd->GetFlag(PFD_ISTEXTFRAME)) {
if (true == pfd->mIsTextFrame) {
if (aState.IsJustifiable()) {
// Set corresponding justification gaps here, so that the
// text frame knows how it should add gaps at its sides.
const auto& info = pfd->mJustificationInfo;
const auto& assign = pfd->mJustificationAssignment;
auto textFrame = static_cast<nsTextFrame*>(pfd->mFrame);
textFrame->AssignJustificationGaps(assign);
dw = aState.Consume(JustificationUtils::CountGaps(info, assign));
}
if (dw) {
pfd->SetFlag(PFD_RECOMPUTEOVERFLOW, true);
pfd->mRecomputeOverflow = true;
}
}
else {
@ -2625,6 +2706,13 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD,
}
pfd->mBounds.ISize(lineWM) += dw;
if (!pfd->mIsTextFrame && assign.TotalGaps()) {
// It is possible that we assign gaps to non-text frame.
// Apply the gaps as margin around the frame.
deltaICoord += aState.Consume(assign.mGapsAtStart);
dw += aState.Consume(assign.mGapsAtEnd);
}
pfd->mBounds.IStart(lineWM) += deltaICoord;
ApplyLineJustificationToAnnotations(pfd, aPSD, deltaICoord, dw);
deltaICoord += dw;
@ -2634,6 +2722,79 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD,
return deltaICoord;
}
/**
* This method expands the given frame by the given reserved isize.
*/
void
nsLineLayout::ExpandRubyBox(PerFrameData* aFrame, nscoord aReservedISize,
nscoord aContainerWidth)
{
int32_t opportunities = aFrame->mJustificationInfo.mInnerOpportunities;
// Each expandable ruby box has an gap at each of its sides. For
// rb/rbc, see comment in ComputeFrameJustification; for rt/rtc,
// see comment in this method below.
int32_t gaps = opportunities * 2 + 2;
JustificationApplicationState state(gaps, aReservedISize);
ApplyFrameJustification(aFrame->mSpan, state);
WritingMode lineWM = mRootSpan->mWritingMode;
aFrame->mBounds.ISize(lineWM) += aReservedISize;
aFrame->mFrame->SetRect(lineWM, aFrame->mBounds, aContainerWidth);
}
/**
* This method expands the given frame by the reserved inline size.
* It also expands its annotations if they are expandable and have
* reserved isize larger than zero.
*/
void
nsLineLayout::ExpandRubyBoxWithAnnotations(PerFrameData* aFrame,
nscoord aContainerWidth)
{
nscoord reservedISize = RubyUtils::GetReservedISize(aFrame->mFrame);
if (reservedISize) {
ExpandRubyBox(aFrame, reservedISize, aContainerWidth);
}
for (PerFrameData* annotation = aFrame->mNextAnnotation;
annotation; annotation = annotation->mNextAnnotation) {
nscoord reservedISize = RubyUtils::GetReservedISize(annotation->mFrame);
if (!reservedISize) {
continue;
}
MOZ_ASSERT(annotation->mSpan);
JustificationComputationState computeState;
ComputeFrameJustification(annotation->mSpan, computeState);
if (!computeState.mFirstParticipant) {
continue;
}
// Add one gap at each side of this annotation.
computeState.mFirstParticipant->mJustificationAssignment.mGapsAtStart = 1;
computeState.mLastParticipant->mJustificationAssignment.mGapsAtEnd = 1;
ExpandRubyBox(annotation, reservedISize, aContainerWidth);
ExpandInlineRubyBoxes(annotation->mSpan);
}
}
/**
* This method looks for all expandable ruby box in the given span, and
* calls ExpandRubyBox to expand them in depth-first preorder.
*/
void
nsLineLayout::ExpandInlineRubyBoxes(PerSpanData* aSpan)
{
nscoord containerWidth = ContainerWidthForSpan(aSpan);
for (PerFrameData* pfd = aSpan->mFirstFrame; pfd; pfd = pfd->mNext) {
if (RubyUtils::IsExpandableRubyBox(pfd->mFrame)) {
ExpandRubyBoxWithAnnotations(pfd, containerWidth);
}
if (pfd->mSpan) {
ExpandInlineRubyBoxes(pfd->mSpan);
}
}
}
// Align inline frames within the line according to the CSS text-align
// property.
void
@ -2678,18 +2839,38 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
}
}
if ((remainingISize > 0 || textAlignTrue) &&
!(mBlockReflowState->frame->IsSVGText())) {
bool isSVG = mBlockReflowState->frame->IsSVGText();
bool doTextAlign = remainingISize > 0 || textAlignTrue;
int32_t additionalGaps = 0;
if (!isSVG && (mHasRuby || (doTextAlign &&
textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY))) {
JustificationComputationState computeState;
ComputeFrameJustification(psd, computeState);
if (mHasRuby && computeState.mFirstParticipant) {
PerFrameData* firstFrame = computeState.mFirstParticipant;
if (firstFrame->mFrame->StyleContext()->IsDirectlyInsideRuby()) {
MOZ_ASSERT(!firstFrame->mJustificationAssignment.mGapsAtStart);
firstFrame->mJustificationAssignment.mGapsAtStart = 1;
additionalGaps++;
}
PerFrameData* lastFrame = computeState.mLastParticipant;
if (lastFrame->mFrame->StyleContext()->IsDirectlyInsideRuby()) {
MOZ_ASSERT(!lastFrame->mJustificationAssignment.mGapsAtEnd);
lastFrame->mJustificationAssignment.mGapsAtEnd = 1;
additionalGaps++;
}
}
}
if (!isSVG && doTextAlign) {
switch (textAlign) {
case NS_STYLE_TEXT_ALIGN_JUSTIFY: {
JustificationComputationState computeState = {
nullptr // mLastParticipant
};
int32_t opportunities = ComputeFrameJustification(psd, computeState);
int32_t opportunities =
psd->mFrame->mJustificationInfo.mInnerOpportunities;
if (opportunities > 0) {
JustificationApplicationState applyState(
opportunities * 2, remainingISize);
int32_t gaps = opportunities * 2 + additionalGaps;
JustificationApplicationState applyState(gaps, remainingISize);
// Apply the justification, and make sure to update our linebox
// width to account for it.
@ -2735,6 +2916,10 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
}
}
if (mHasRuby) {
ExpandInlineRubyBoxes(mRootSpan);
}
if (mPresContext->BidiEnabled() &&
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
@ -2798,7 +2983,7 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflo
nsPoint origin = frame->GetPosition();
// Adjust the origin of the frame
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
if (pfd->mRelativePos) {
//XXX temporary until ApplyRelativePositioning can handle logical offsets
nsMargin physicalOffsets =
pfd->mOffsets.GetPhysicalMargin(pfd->mFrame->GetWritingMode());
@ -2829,12 +3014,12 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflo
RelativePositionFrames(pfd->mSpan, r);
} else {
r = pfd->mOverflowAreas;
if (pfd->GetFlag(PFD_ISTEXTFRAME)) {
if (pfd->mIsTextFrame) {
// We need to recompute overflow areas in two cases:
// (1) When PFD_RECOMPUTEOVERFLOW is set due to trimming
// (2) When there are text decorations, since we can't recompute the
// overflow area until Reflow and VerticalAlignLine have finished
if (pfd->GetFlag(PFD_RECOMPUTEOVERFLOW) ||
if (pfd->mRecomputeOverflow ||
frame->StyleContext()->HasTextDecorationLines()) {
nsTextFrame* f = static_cast<nsTextFrame*>(frame);
r = f->RecomputeOverflow(*mBlockReflowState);

View File

@ -116,6 +116,15 @@ public:
*/
void VerticalAlignLine();
// Get the final size of the line, in the block direction.
// Do not call this until after we've called VerticalAlignLine.
nscoord GetFinalLineBSize() const
{
NS_ASSERTION(mFinalLineBSize != nscoord_MIN,
"VerticalAlignLine should have been called before");
return mFinalLineBSize;
}
bool TrimTrailingWhiteSpace();
/**
@ -437,47 +446,27 @@ protected:
mozilla::LogicalMargin mOffsets; // in *frame* writing mode
// state for text justification
// Note that, although all frames would have correct inner
// opportunities computed after ComputeFrameJustification, start
// and end justifiable info are not reliable for non-text frames.
mozilla::JustificationInfo mJustificationInfo;
mozilla::JustificationAssignment mJustificationAssignment;
// PerFrameData flags
#define PFD_RELATIVEPOS 0x00000001
#define PFD_ISTEXTFRAME 0x00000002
#define PFD_ISNONEMPTYTEXTFRAME 0x00000004
#define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
#define PFD_ISLETTERFRAME 0x00000010
#define PFD_RECOMPUTEOVERFLOW 0x00000020
#define PFD_ISBULLET 0x00000040
#define PFD_SKIPWHENTRIMMINGWHITESPACE 0x00000080
#define PFD_ISEMPTY 0x00000100
#define PFD_ISLINKEDTOBASE 0x00000200
#define PFD_LASTFLAG PFD_ISLINKEDTOBASE
// PerFrameData flags
bool mRelativePos : 1;
bool mIsTextFrame : 1;
bool mIsNonEmptyTextFrame : 1;
bool mIsNonWhitespaceTextFrame : 1;
bool mIsLetterFrame : 1;
bool mRecomputeOverflow : 1;
bool mIsBullet : 1;
bool mSkipWhenTrimmingWhitespace : 1;
bool mIsEmpty : 1;
bool mIsLinkedToBase : 1;
// Other state we use
uint16_t mFlags;
uint8_t mBlockDirAlign;
static_assert(PFD_LASTFLAG <= UINT16_MAX,
"Flag value exceeds the length of flags variable.");
void SetFlag(uint32_t aFlag, bool aValue)
{
NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
if (aValue) { // set flag
mFlags |= aFlag;
}
else { // unset flag
mFlags &= ~aFlag;
}
}
bool GetFlag(uint32_t aFlag) const
{
NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
return !!(mFlags & aFlag);
}
PerFrameData* Last() {
PerFrameData* pfd = this;
while (pfd->mNext) {
@ -499,7 +488,7 @@ protected:
bool ParticipatesInJustification() const
{
// Skip bullets and empty frames
return !GetFlag(PFD_ISBULLET) && !GetFlag(PFD_ISEMPTY);
return !mIsBullet && !mIsEmpty;
}
};
PerFrameData* mFrameFreeList;
@ -601,6 +590,7 @@ protected:
bool mHasBullet : 1;
bool mDirtyNextLine : 1;
bool mLineAtStart : 1;
bool mHasRuby : 1;
int32_t mSpanDepth;
#ifdef DEBUG
@ -685,6 +675,14 @@ protected:
nscoord ApplyFrameJustification(
PerSpanData* aPSD, mozilla::JustificationApplicationState& aState);
void ExpandRubyBox(PerFrameData* aFrame, nscoord aReservedISize,
nscoord aContainerWidth);
void ExpandRubyBoxWithAnnotations(PerFrameData* aFrame,
nscoord aContainerWidth);
void ExpandInlineRubyBoxes(PerSpanData* aSpan);
void AttachFrameToBaseLineLayout(PerFrameData* aFrame);
#ifdef DEBUG

View File

@ -13,6 +13,7 @@
#include "nsStyleContext.h"
#include "nsStyleStructInlines.h"
#include "WritingModes.h"
#include "RubyUtils.h"
using namespace mozilla;
@ -376,15 +377,17 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
// Reflow spans
nscoord spanISize = ReflowSpans(aPresContext, aReflowState,
spanReflowStates);
if (isize < spanISize) {
nscoord delta = spanISize - isize;
if (allowLineBreak && ShouldBreakBefore(aReflowState, delta)) {
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
} else {
aReflowState.mLineLayout->AdvanceICoord(delta);
isize = spanISize;
}
nscoord deltaISize = spanISize - isize;
if (deltaISize <= 0) {
RubyUtils::ClearReservedISize(this);
} else if (allowLineBreak && ShouldBreakBefore(aReflowState, deltaISize)) {
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
} else {
RubyUtils::SetReservedISize(this, deltaISize);
aReflowState.mLineLayout->AdvanceICoord(deltaISize);
isize = spanISize;
}
}
// When there are spans, ReflowPairs and ReflowOnePair won't
// record any optional break position. We have to record one
// at the end of this segment.
@ -394,7 +397,6 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
gfxBreakPriority::eNormalBreak)) {
aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
}
}
DebugOnly<nscoord> lineSpanSize = aReflowState.mLineLayout->EndSpan(this);
// When there are no frames inside the ruby base container, EndSpan
@ -407,8 +409,24 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
// when it is reflowed, it will just use this size.
nsRubyTextContainerFrame* textContainer = i < rtcCount ?
mTextContainers[i] : mSpanContainers[i - rtcCount];
textContainer->SetISize(isize);
lineLayouts[i]->EndLineReflow();
nsLineLayout* lineLayout = lineLayouts[i].get();
RubyUtils::ClearReservedISize(textContainer);
nscoord rtcISize = lineLayout->GetCurrentICoord();
// Only span containers and containers with collapsed annotations
// need reserving isize. For normal ruby text containers, their
// children will be expanded properly. We only need to expand their
// own size.
if (i < rtcCount) {
rtcISize = isize;
} else if (isize > rtcISize) {
RubyUtils::SetReservedISize(textContainer, isize - rtcISize);
}
lineLayout->VerticalAlignLine();
LogicalSize lineSize(lineWM, isize, lineLayout->GetFinalLineBSize());
textContainer->SetLineSize(lineSize);
lineLayout->EndLineReflow();
}
aDesiredSize.ISize(lineWM) = isize;
@ -568,6 +586,7 @@ nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext,
nsReflowStatus reflowStatus;
nsHTMLReflowMetrics metrics(*aReflowStates[i]);
RubyUtils::ClearReservedISize(textFrame);
bool pushedFrame;
aReflowStates[i]->mLineLayout->ReflowFrame(textFrame, reflowStatus,
@ -590,6 +609,7 @@ nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext,
MOZ_ASSERT(aBaseFrame->GetType() == nsGkAtoms::rubyBaseFrame);
nsReflowStatus reflowStatus;
nsHTMLReflowMetrics metrics(aReflowState);
RubyUtils::ClearReservedISize(aBaseFrame);
bool pushedFrame;
aReflowState.mLineLayout->ReflowFrame(aBaseFrame, reflowStatus,
@ -601,12 +621,24 @@ nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext,
// Align all the line layout to the new coordinate.
nscoord icoord = istart + pairISize;
aReflowState.mLineLayout->AdvanceICoord(
icoord - aReflowState.mLineLayout->GetCurrentICoord());
nscoord deltaISize = icoord - aReflowState.mLineLayout->GetCurrentICoord();
if (deltaISize > 0) {
aReflowState.mLineLayout->AdvanceICoord(deltaISize);
if (aBaseFrame) {
RubyUtils::SetReservedISize(aBaseFrame, deltaISize);
}
}
for (uint32_t i = 0; i < rtcCount; i++) {
nsLineLayout* lineLayout = aReflowStates[i]->mLineLayout;
lineLayout->AdvanceICoord(icoord - lineLayout->GetCurrentICoord());
if (aBaseFrame && aTextFrames[i]) {
nsIFrame* textFrame = aTextFrames[i];
nscoord deltaISize = icoord - lineLayout->GetCurrentICoord();
if (deltaISize > 0) {
lineLayout->AdvanceICoord(deltaISize);
if (textFrame) {
RubyUtils::SetReservedISize(textFrame, deltaISize);
}
}
if (aBaseFrame && textFrame) {
lineLayout->AttachLastFrameToBaseLineLayout();
}
}

View File

@ -271,6 +271,23 @@ nsRubyFrame::Reflow(nsPresContext* aPresContext,
borderPadding, lineWM, frameWM);
}
#ifdef DEBUG
static void
SanityCheckRubyPosition(int8_t aRubyPosition)
{
uint8_t horizontalPosition = aRubyPosition &
(NS_STYLE_RUBY_POSITION_LEFT | NS_STYLE_RUBY_POSITION_RIGHT);
MOZ_ASSERT(horizontalPosition == NS_STYLE_RUBY_POSITION_LEFT ||
horizontalPosition == NS_STYLE_RUBY_POSITION_RIGHT);
uint8_t verticalPosition = aRubyPosition &
(NS_STYLE_RUBY_POSITION_OVER | NS_STYLE_RUBY_POSITION_UNDER |
NS_STYLE_RUBY_POSITION_INTER_CHARACTER);
MOZ_ASSERT(verticalPosition == NS_STYLE_RUBY_POSITION_OVER ||
verticalPosition == NS_STYLE_RUBY_POSITION_UNDER ||
verticalPosition == NS_STYLE_RUBY_POSITION_INTER_CHARACTER);
}
#endif
void
nsRubyFrame::ReflowSegment(nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
@ -356,6 +373,16 @@ nsRubyFrame::ReflowSegment(nsPresContext* aPresContext,
}
nsRect baseRect = aBaseContainer->GetRect();
// We need to position our rtc frames on one side or the other of the
// base container's rect, using a coordinate space that's relative to
// the ruby frame. Right now, the base container's rect's block-axis
// position is relative to the block container frame containing the
// lines, so we use 0 instead. (i.e. we assume that the base container
// is adjacent to the ruby frame's block-start edge.)
// XXX We may need to add border/padding here. See bug 1055667.
(lineWM.IsVertical() ? baseRect.x : baseRect.y) = 0;
// The rect for offsets of text containers.
nsRect offsetRect = baseRect;
for (uint32_t i = 0; i < rtcCount; i++) {
nsRubyTextContainerFrame* textContainer = textContainers[i];
nsReflowStatus textReflowStatus;
@ -376,14 +403,37 @@ nsRubyFrame::ReflowSegment(nsPresContext* aPresContext,
"Ruby text container must not break itself inside");
textContainer->SetSize(LogicalSize(lineWM, textMetrics.ISize(lineWM),
textMetrics.BSize(lineWM)));
nscoord x, y;
nscoord bsize = textMetrics.BSize(lineWM);
uint8_t rubyPosition = textContainer->StyleText()->mRubyPosition;
#ifdef DEBUG
SanityCheckRubyPosition(rubyPosition);
#endif
if (lineWM.IsVertical()) {
x = lineWM.IsVerticalLR() ? -bsize : baseRect.XMost();
y = baseRect.Y();
// writing-mode is vertical, so bsize is the annotation's *width*
if (rubyPosition & NS_STYLE_RUBY_POSITION_LEFT) {
x = offsetRect.X() - bsize;
offsetRect.SetLeftEdge(x);
} else {
x = offsetRect.XMost();
offsetRect.SetRightEdge(x + bsize);
}
y = offsetRect.Y();
} else {
x = baseRect.X();
y = -bsize;
// writing-mode is horizontal, so bsize is the annotation's *height*
x = offsetRect.X();
if (rubyPosition & NS_STYLE_RUBY_POSITION_OVER) {
y = offsetRect.Y() - bsize;
offsetRect.SetTopEdge(y);
} else if (rubyPosition & NS_STYLE_RUBY_POSITION_UNDER) {
y = offsetRect.YMost();
offsetRect.SetBottomEdge(y + bsize);
} else {
// XXX inter-character support in bug 1055672
MOZ_ASSERT_UNREACHABLE("Unsupported ruby-position");
y = offsetRect.Y();
}
}
FinishReflowChild(textContainer, aPresContext, textMetrics,
&textReflowState, x, y, 0);

View File

@ -71,7 +71,8 @@ nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
// All rt children have already been reflowed. All we need to do is
// to report complete and return the desired size.
// to report complete and return the desired size provided by the
// ruby base container.
// Although a ruby text container may have continuations, returning
// NS_FRAME_COMPLETE here is still safe, since its parent, ruby frame,
@ -79,12 +80,5 @@ nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
// will take care of our continuations.
aStatus = NS_FRAME_COMPLETE;
WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
WritingMode frameWM = aReflowState.GetWritingMode();
LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding();
// ISize is provided by the ruby base container
// during reflow of that container.
aDesiredSize.ISize(lineWM) = mISize;
nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
borderPadding, lineWM, frameWM);
aDesiredSize.SetSize(lineWM, mLineSize);
}

View File

@ -47,15 +47,16 @@ protected:
NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext);
explicit nsRubyTextContainerFrame(nsStyleContext* aContext)
: nsRubyTextContainerFrameSuper(aContext) {}
: nsRubyTextContainerFrameSuper(aContext)
, mLineSize(mozilla::WritingMode(aContext)) {}
friend class nsRubyBaseContainerFrame;
void SetISize(nscoord aISize) { mISize = aISize; }
void SetLineSize(const mozilla::LogicalSize& aSize) { mLineSize = aSize; }
// The intended dimensions of the ruby text container. These are modified
// whenever a ruby text box is reflowed and used when the ruby text container
// is reflowed.
nscoord mISize;
// The intended dimensions of the ruby text container. It is set by
// the corresponding ruby base container when the segment is reflowed,
// and used when the ruby text container is reflowed by its parent.
mozilla::LogicalSize mLineSize;
};
#endif /* nsRubyTextContainerFrame_h___ */

View File

@ -90,7 +90,10 @@ nsRubyTextFrame::Reflow(nsPresContext* aPresContext,
aReflowState, aStatus);
if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) {
aDesiredSize.ClearSize();
// Reset the ISize. The BSize is not changed so that it won't
// affect vertical positioning in unexpected way.
WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
aDesiredSize.ISize(lineWM) = 0;
aDesiredSize.SetOverflowAreasToDesiredBounds();
}
}

View File

@ -1861,10 +1861,10 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
uint32_t nextBreakIndex = 0;
nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
bool isSVG = mLineContainer->IsSVGText();
bool enabledJustification = mLineContainer &&
(mLineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
mLineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY) &&
!mLineContainer->IsSVGText();
mLineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY);
// for word-break style
switch (mLineContainer->StyleText()->mWordBreak) {
@ -1896,7 +1896,8 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
textFlags |= GetSpacingFlags(WordSpacing(f));
nsTextFrameUtils::CompressionMode compression =
CSSWhitespaceToCompressionMode[textStyle->mWhiteSpace];
if (enabledJustification && !textStyle->WhiteSpaceIsSignificant()) {
if ((enabledJustification || f->StyleContext()->IsDirectlyInsideRuby()) &&
!textStyle->WhiteSpaceIsSignificant() && !isSVG) {
textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING;
}
fontStyle = f->StyleFont();
@ -2760,6 +2761,12 @@ static int32_t FindChar(const nsTextFragment* frag,
static bool IsChineseOrJapanese(nsIFrame* aFrame)
{
if (aFrame->StyleContext()->IsDirectlyInsideRuby()) {
// Always treat ruby as CJ language so that those characters can
// be expanded properly even when surrounded by other language.
return true;
}
nsIAtom* language = aFrame->StyleFont()->mLanguage;
if (!language) {
return false;
@ -8502,7 +8509,8 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
// Compute space and letter counts for justification, if required
if (!textStyle->WhiteSpaceIsSignificant() &&
(lineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY) &&
lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
StyleContext()->IsDirectlyInsideRuby()) &&
!lineContainer->IsSVGText()) {
AddStateBits(TEXT_JUSTIFICATION_ENABLED);
provider.ComputeJustification(offset, charsFit);

View File

@ -2,7 +2,7 @@ default-preferences pref(layout.css.ruby.enabled,true)
== autohiding-1.html autohiding-1-ref.html
== autohiding-2.html autohiding-2-ref.html
== autohiding-3.html autohiding-3-ref.html
fails == autohiding-3.html autohiding-3-ref.html # bug 1107701
== box-generation-1.html box-generation-1-ref.html
== box-generation-2.html box-generation-2-ref.html
== box-generation-3.html box-generation-3-ref.html
@ -22,5 +22,8 @@ fuzzy-if(winWidget,28,1) == dynamic-removal-3.html dynamic-removal-3-ref.html #
== inlinize-blocks-5.html inlinize-blocks-5-ref.html
== ruby-whitespace-1.html ruby-whitespace-1-ref.html
== ruby-whitespace-2.html ruby-whitespace-2-ref.html
== ruby-position-horizontal.html ruby-position-horizontal-ref.html
pref(layout.css.vertical-text.enabled,true) fails == ruby-position-vertical-lr.html ruby-position-vertical-lr-ref.html # bug 1112474
pref(layout.css.vertical-text.enabled,true) fails == ruby-position-vertical-rl.html ruby-position-vertical-rl-ref.html # bug 1112474
!= ruby-reflow-1-opaqueruby.html ruby-reflow-1-noruby.html
== ruby-reflow-1-transparentruby.html ruby-reflow-1-noruby.html

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bug 1055665 - Test for ruby-position</title>
<link rel="stylesheet" href="common.css">
<style>
body {
font-family: monospace;
line-height: normal;
}
.annotation, .annotation > div {
position: absolute;
}
</style>
</head>
<body>
<div style="height: 8em; line-height: 8em;">
<div style="display: inline-block; line-height: normal;">
<div class="annotation">
<div style="top: -100%;">over##</div>
<div style="top: 100%;">under#</div>
<div style="top: -200%;">over2#</div>
<div style="top: 200%;">under2</div>
&nbsp; <!-- to give container a nonzero size for
percent values to resolve against -->
</div>
base##
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bug 1055665 - Test for ruby-position</title>
<link rel="stylesheet" href="common.css">
<style>
body {
font-family: monospace;
/* use a large line-height here to avoid additional leadings */
line-height: 8em;
}
rtc, rt {
font-size: 100% !important;
line-height: normal !important;
}
</style>
</head>
<body>
<ruby>
<rb>base##</rb>
<rtc style="ruby-position: over left"><rt>over##</rt></rtc>
<rtc style="ruby-position: under left"><rt>under#</rt></rtc>
<rtc style="ruby-position: over left"><rt>over2#</rt></rtc>
<rtc style="ruby-position: under left"><rt>under2</rt></rtc>
</ruby>
</body>
</html>

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bug 1055665 - Test for ruby-position</title>
<link rel="stylesheet" href="common.css">
<style>
body {
font-family: monospace;
line-height: normal;
writing-mode: vertical-lr;
}
.annotation, .annotation > div {
position: absolute;
}
</style>
</head>
<body>
<div style="width: 8em; line-height: 8em;">
<div style="display: inline-block; line-height: normal;">
<div class="annotation">
<div style="right: 100%;">left##</div>
<div style="right: -100%;">right#</div>
<div style="right: 200%;">left2#</div>
<div style="right: -200%;">right2</div>
&nbsp; <!-- to give container a nonzero size for
percent values to resolve against -->
</div>
base##
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bug 1055665 - Test for ruby-position</title>
<link rel="stylesheet" href="common.css">
<style>
body {
font-family: monospace;
/* use a large line-height here to avoid additional leadings */
line-height: 8em;
writing-mode: vertical-lr;
}
rtc, rt {
font-size: 100% !important;
line-height: normal !important;
}
</style>
</head>
<body>
<ruby>
<rb>base##</rb>
<rtc style="ruby-position: over left"><rt>left##</rt></rtc>
<rtc style="ruby-position: over right"><rt>right#</rt></rtc>
<rtc style="ruby-position: over left"><rt>left2#</rt></rtc>
<rtc style="ruby-position: over right"><rt>right2</rt></rtc>
</ruby>
</body>
</html>

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bug 1055665 - Test for ruby-position</title>
<link rel="stylesheet" href="common.css">
<style>
body {
font-family: monospace;
line-height: normal;
writing-mode: vertical-rl;
}
.annotation, .annotation > div {
position: absolute;
}
</style>
</head>
<body>
<div style="width: 8em; line-height: 8em;">
<div style="display: inline-block; line-height: normal;">
<div class="annotation">
<div style="right: 100%;">left##</div>
<div style="right: -100%;">right#</div>
<div style="right: 200%;">left2#</div>
<div style="right: -200%;">right2</div>
&nbsp; <!-- to give container a nonzero size for
percent values to resolve against -->
</div>
base##
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bug 1055665 - Test for ruby-position</title>
<link rel="stylesheet" href="common.css">
<style>
body {
font-family: monospace;
/* use a large line-height here to avoid additional leadings */
line-height: 8em;
writing-mode: vertical-rl;
}
rtc, rt {
font-size: 100% !important;
line-height: normal !important;
}
</style>
</head>
<body>
<ruby>
<rb>base##</rb>
<rtc style="ruby-position: over left"><rt>left##</rt></rtc>
<rtc style="ruby-position: over right"><rt>right#</rt></rtc>
<rtc style="ruby-position: over left"><rt>left2#</rt></rtc>
<rtc style="ruby-position: over right"><rt>right2</rt></rtc>
</ruby>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
p { border: 1px solid black; }
.layout-main-page-content { width: 75%; float: right; text-align:right; }
.layout-right-column { width: 25%; float: left; }
</style>
</head>
<body>
<div>
<div class="layout-main-page-content">
<img src="foo">
<p dir="rtl" id="p_10">0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789</p>
<p dir="rtl" id="p_20">0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789</p>
</div>
</div>
<div class="layout-right-column" dir="rtl">
hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge
<img id="image" style="height: 280px; overflow: hidden;" src="foo" width="100%">
</div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
p { border: 1px solid black; }
.layout-main-page-content { width: 75%; float: right;}
.layout-right-column { width: 25%; float: left; }
</style>
<script type="text/javascript">
function do_test() {
document.getElementById("image").removeAttribute("hidden");
document.documentElement.removeAttribute("class");
};
</script>
</head>
<body dir="rtl" onload="do_test()">
<div>
<div class="layout-main-page-content">
<img src="foo">
<p dir="rtl" id="p_10">0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789</p>
<p dir="rtl" id="p_20">0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789</p>
</div>
</div>
<div class="layout-right-column">
hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge
<img id="image" hidden="true" style="height: 280px; overflow: hidden;" src="foo" width="100%">
</div>
</body>
</html>

View File

@ -18,3 +18,4 @@ fails == 345369-2.html 345369-2-ref.html
== 429974-1.html 429974-1-ref.html
== 546048-1.html 546048-1-ref.html
== 775350-1.html 775350-1-ref.html
== 1114329.html 1114329-ref.html

View File

@ -310,6 +310,7 @@ CSS_KEY(inline-grid, inline_grid)
CSS_KEY(inline-table, inline_table)
CSS_KEY(inset, inset)
CSS_KEY(inside, inside)
// CSS_KEY(inter-character, inter_character) // TODO see bug 1055672
CSS_KEY(interpolatematrix, interpolatematrix)
CSS_KEY(isolate, isolate)
CSS_KEY(invert, invert)
@ -393,6 +394,7 @@ CSS_KEY(ordinal, ordinal)
CSS_KEY(ornaments, ornaments)
CSS_KEY(outset, outset)
CSS_KEY(outside, outside)
CSS_KEY(over, over)
CSS_KEY(overlay, overlay)
CSS_KEY(overline, overline)
CSS_KEY(padding-box, padding_box)
@ -553,6 +555,7 @@ CSS_KEY(tri-state, tri_state)
CSS_KEY(true, true)
CSS_KEY(ultra-condensed, ultra_condensed)
CSS_KEY(ultra-expanded, ultra_expanded)
CSS_KEY(under, under)
CSS_KEY(underline, underline)
CSS_KEY(unicase, unicase)
CSS_KEY(unset, unset)

View File

@ -795,6 +795,7 @@ protected:
bool ParseOverflow();
bool ParsePadding();
bool ParseQuotes();
bool ParseRubyPosition(nsCSSValue& aValue);
bool ParseSize();
bool ParseTextAlign(nsCSSValue& aValue,
const KTableValue aTable[]);
@ -10009,6 +10010,8 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
return ParseListStyleType(aValue);
case eCSSProperty_marks:
return ParseMarks(aValue);
case eCSSProperty_ruby_position:
return ParseRubyPosition(aValue);
case eCSSProperty_text_align:
return ParseTextAlign(aValue);
case eCSSProperty_text_align_last:
@ -13125,6 +13128,34 @@ CSSParserImpl::ParseQuotes()
return true;
}
static const int32_t gRubyPositionMask[] = {
// vertical values
NS_STYLE_RUBY_POSITION_OVER |
NS_STYLE_RUBY_POSITION_UNDER |
NS_STYLE_RUBY_POSITION_INTER_CHARACTER,
// horizontal values
NS_STYLE_RUBY_POSITION_RIGHT |
NS_STYLE_RUBY_POSITION_LEFT,
// end
MASK_END_VALUE
};
bool
CSSParserImpl::ParseRubyPosition(nsCSSValue& aValue)
{
if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) {
return true;
}
if (!ParseBitmaskValues(aValue, nsCSSProps::kRubyPositionKTable,
gRubyPositionMask)) {
return false;
}
auto value = aValue.GetIntValue();
// The specified value must include *both* a vertical keyword *and*
// a horizontal keyword. We reject it here if either is missing.
return (value & gRubyPositionMask[0]) && (value & gRubyPositionMask[1]);
}
bool
CSSParserImpl::ParseSize()
{

View File

@ -2976,6 +2976,17 @@ CSS_PROP_POSITION(
nullptr,
offsetof(nsStylePosition, mOffset),
eStyleAnimType_Sides_Right)
CSS_PROP_TEXT(
ruby-position,
ruby_position,
RubyPosition,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_VALUE_PARSER_FUNCTION,
"layout.css.ruby.enabled",
0,
kRubyPositionKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_DISPLAY(
scroll-behavior,
scroll_behavior,

View File

@ -1625,6 +1625,16 @@ const KTableValue nsCSSProps::kResizeKTable[] = {
eCSSKeyword_UNKNOWN,-1
};
const KTableValue nsCSSProps::kRubyPositionKTable[] = {
eCSSKeyword_over, NS_STYLE_RUBY_POSITION_OVER,
eCSSKeyword_under, NS_STYLE_RUBY_POSITION_UNDER,
// bug 1055672 for 'inter-character' support
// eCSSKeyword_inter_character, NS_STYLE_RUBY_POSITION_INTER_CHARACTER,
eCSSKeyword_right, NS_STYLE_RUBY_POSITION_RIGHT,
eCSSKeyword_left, NS_STYLE_RUBY_POSITION_LEFT,
eCSSKeyword_UNKNOWN, -1
};
const KTableValue nsCSSProps::kScrollBehaviorKTable[] = {
eCSSKeyword_auto, NS_STYLE_SCROLL_BEHAVIOR_AUTO,
eCSSKeyword_smooth, NS_STYLE_SCROLL_BEHAVIOR_SMOOTH,

View File

@ -628,6 +628,7 @@ public:
static const KTableValue kRadialGradientSizeKTable[];
static const KTableValue kRadialGradientLegacySizeKTable[];
static const KTableValue kResizeKTable[];
static const KTableValue kRubyPositionKTable[];
static const KTableValue kScrollBehaviorKTable[];
static const KTableValue kSpeakKTable[];
static const KTableValue kSpeakHeaderKTable[];

View File

@ -1290,6 +1290,13 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
aResult);
break;
case eCSSProperty_ruby_position:
nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
NS_STYLE_RUBY_POSITION_OVER,
NS_STYLE_RUBY_POSITION_LEFT,
aResult);
break;
default:
const nsAFlatCString& name = nsCSSProps::LookupPropertyValue(aProperty, intValue);
AppendASCIItoUTF16(name, aResult);

View File

@ -3076,6 +3076,20 @@ nsComputedDOMStyle::DoGetLineHeight()
return val;
}
CSSValue*
nsComputedDOMStyle::DoGetRubyPosition()
{
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
int32_t intValue = StyleText()->mRubyPosition;
nsAutoString valueStr;
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_ruby_position,
intValue,
NS_STYLE_RUBY_POSITION_OVER,
NS_STYLE_RUBY_POSITION_LEFT, valueStr);
val->SetString(valueStr);
return val;
}
CSSValue*
nsComputedDOMStyle::DoGetVerticalAlign()
{

View File

@ -374,6 +374,7 @@ private:
/* Text Properties */
mozilla::dom::CSSValue* DoGetLineHeight();
mozilla::dom::CSSValue* DoGetRubyPosition();
mozilla::dom::CSSValue* DoGetTextAlign();
mozilla::dom::CSSValue* DoGetTextAlignLast();
mozilla::dom::CSSValue* DoGetTextCombineUpright();

View File

@ -197,6 +197,7 @@ COMPUTED_STYLE_PROP(position, Position)
COMPUTED_STYLE_PROP(quotes, Quotes)
COMPUTED_STYLE_PROP(resize, Resize)
COMPUTED_STYLE_PROP(right, Right)
COMPUTED_STYLE_PROP(ruby_position, RubyPosition)
COMPUTED_STYLE_PROP(scroll_behavior, ScrollBehavior)
//// COMPUTED_STYLE_PROP(size, Size)
COMPUTED_STYLE_PROP(table_layout, TableLayout)

View File

@ -4368,6 +4368,13 @@ nsRuleNode::ComputeTextData(void* aStartStruct,
parentText->mHyphens,
NS_STYLE_HYPHENS_MANUAL, 0, 0, 0, 0);
// ruby-position: enum, inherit, initial
SetDiscrete(*aRuleData->ValueForRubyPosition(),
text->mRubyPosition, canStoreInRuleTree,
SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
parentText->mRubyPosition,
NS_STYLE_RUBY_POSITION_INITIAL, 0, 0, 0, 0);
// text-size-adjust: none, auto, inherit, initial
SetDiscrete(*aRuleData->ValueForTextSizeAdjust(), text->mTextSizeAdjust,
canStoreInRuleTree,

View File

@ -843,6 +843,15 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_HYPHENS_MANUAL 1
#define NS_STYLE_HYPHENS_AUTO 2
// ruby-position, see nsStyleText
#define NS_STYLE_RUBY_POSITION_OVER 0x01
#define NS_STYLE_RUBY_POSITION_UNDER 0x02
#define NS_STYLE_RUBY_POSITION_INTER_CHARACTER 0x04 // placeholder, not yet parsed
#define NS_STYLE_RUBY_POSITION_RIGHT 0x08
#define NS_STYLE_RUBY_POSITION_LEFT 0x10
#define NS_STYLE_RUBY_POSITION_INITIAL \
(NS_STYLE_RUBY_POSITION_OVER | NS_STYLE_RUBY_POSITION_RIGHT)
// See nsStyleText
#define NS_STYLE_TEXT_SIZE_ADJUST_NONE 0
#define NS_STYLE_TEXT_SIZE_ADJUST_AUTO 1

View File

@ -3344,6 +3344,7 @@ nsStyleText::nsStyleText(void)
mWordBreak = NS_STYLE_WORDBREAK_NORMAL;
mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
mHyphens = NS_STYLE_HYPHENS_MANUAL;
mRubyPosition = NS_STYLE_RUBY_POSITION_INITIAL;
mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE;
mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
@ -3367,6 +3368,7 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
mWordBreak(aSource.mWordBreak),
mWordWrap(aSource.mWordWrap),
mHyphens(aSource.mHyphens),
mRubyPosition(aSource.mRubyPosition),
mTextSizeAdjust(aSource.mTextSizeAdjust),
mTextCombineUpright(aSource.mTextCombineUpright),
mControlCharacterVisibility(aSource.mControlCharacterVisibility),
@ -3407,6 +3409,7 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
(mWordBreak != aOther.mWordBreak) ||
(mWordWrap != aOther.mWordWrap) ||
(mHyphens != aOther.mHyphens) ||
(mRubyPosition != aOther.mRubyPosition) ||
(mTextSizeAdjust != aOther.mTextSizeAdjust) ||
(mLetterSpacing != aOther.mLetterSpacing) ||
(mLineHeight != aOther.mLineHeight) ||

View File

@ -1596,6 +1596,7 @@ struct nsStyleText {
uint8_t mWordBreak; // [inherited] see nsStyleConsts.h
uint8_t mWordWrap; // [inherited] see nsStyleConsts.h
uint8_t mHyphens; // [inherited] see nsStyleConsts.h
uint8_t mRubyPosition; // [inherited] see nsStyleConsts.h
uint8_t mTextSizeAdjust; // [inherited] see nsStyleConsts.h
uint8_t mTextCombineUpright; // [inherited] see nsStyleConsts.h
uint8_t mControlCharacterVisibility; // [inherited] see nsStyleConsts.h

View File

@ -5047,6 +5047,21 @@ if (SpecialPowers.getBoolPref("layout.css.ruby.enabled")) {
"ruby-base-container",
"ruby-text",
"ruby-text-container");
gCSSProperties["ruby-position"] = {
domProp: "rubyPosition",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "over right", "right over" ],
other_values: [
"over left", "under right", "under left",
"left over", "right under", "left under"
],
invalid_values: [
"over", "under", "left", "right", "auto", "none", "not_a_position",
"over over", "over under", "left left", "left right",
"over left over", "right over left", "0", "100px", "50%"
]
};
}
if (SpecialPowers.getBoolPref("layout.css.grid.enabled")) {

View File

@ -0,0 +1,356 @@
/* 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 "mozilla/ArrayUtils.h"
#include "mp4_demuxer/AnnexB.h"
#include "mp4_demuxer/ByteReader.h"
#include "mp4_demuxer/ByteWriter.h"
#include "mp4_demuxer/H264.h"
#include <media/stagefright/foundation/ABitReader.h>
using namespace mozilla;
namespace mp4_demuxer
{
class BitReader
{
public:
explicit BitReader(const ByteBuffer& aBuffer)
: mBitReader(aBuffer.Elements(), aBuffer.Length())
{
}
uint32_t ReadBits(size_t aNum)
{
MOZ_ASSERT(mBitReader.numBitsLeft());
MOZ_ASSERT(aNum <= 32);
if (mBitReader.numBitsLeft() < aNum) {
return 0;
}
return mBitReader.getBits(aNum);
}
uint32_t ReadBit()
{
return ReadBits(1);
}
// Read unsigned integer Exp-Golomb-coded.
uint32_t ReadUE()
{
uint32_t i = 0;
while (ReadBit() == 0 && i < 32) {
i++;
}
if (i == 32) {
MOZ_ASSERT(false);
return 0;
}
uint32_t r = ReadBits(i);
r += (1 << i) - 1;
return r;
}
// Read signed integer Exp-Golomb-coded.
int32_t ReadSE()
{
int32_t r = ReadUE();
if (r & 1) {
return (r+1) / 2;
} else {
return -r / 2;
}
}
private:
stagefright::ABitReader mBitReader;
};
SPSData::SPSData()
{
PodZero(this);
chroma_format_idc = 1;
}
/* static */ already_AddRefed<ByteBuffer>
H264::DecodeNALUnit(const ByteBuffer* aNAL)
{
MOZ_ASSERT(aNAL);
if (aNAL->Length() < 4) {
return nullptr;
}
nsRefPtr<ByteBuffer> rbsp = new ByteBuffer;
ByteReader reader(*aNAL);
uint8_t nal_unit_type = reader.ReadU8() & 0x1f;
uint32_t nalUnitHeaderBytes = 1;
if (nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21) {
bool svc_extension_flag = false;
bool avc_3d_extension_flag = false;
if (nal_unit_type != 21) {
svc_extension_flag = reader.PeekU8() & 0x80;
} else {
avc_3d_extension_flag = reader.PeekU8() & 0x80;
}
if (svc_extension_flag) {
nalUnitHeaderBytes += 3;
} else if (avc_3d_extension_flag) {
nalUnitHeaderBytes += 2;
} else {
nalUnitHeaderBytes += 3;
}
}
if (!reader.Read(nalUnitHeaderBytes - 1)) {
return nullptr;
}
uint32_t zeros = 0;
while (reader.Remaining()) {
uint8_t byte = reader.ReadU8();
if (zeros < 2 || byte == 0x03) {
rbsp->AppendElement(byte);
}
if (byte == 0) {
zeros++;
} else {
zeros = 0;
}
}
return rbsp.forget();
}
/* static */ bool
H264::DecodeSPS(const ByteBuffer* aSPS, SPSData& aDest)
{
MOZ_ASSERT(aSPS);
BitReader br(*aSPS);
int32_t lastScale;
int32_t nextScale;
int32_t deltaScale;
aDest.profile_idc = br.ReadBits(8);
aDest.constraint_set0_flag = br.ReadBit();
aDest.constraint_set1_flag = br.ReadBit();
aDest.constraint_set2_flag = br.ReadBit();
aDest.constraint_set3_flag = br.ReadBit();
aDest.constraint_set4_flag = br.ReadBit();
aDest.constraint_set5_flag = br.ReadBit();
br.ReadBits(2); // reserved_zero_2bits
aDest.level_idc = br.ReadBits(8);
aDest.seq_parameter_set_id = br.ReadUE();
if (aDest.profile_idc == 100 || aDest.profile_idc == 110 ||
aDest.profile_idc == 122 || aDest.profile_idc == 244 ||
aDest.profile_idc == 44 || aDest.profile_idc == 83 ||
aDest.profile_idc == 86 || aDest.profile_idc == 118 ||
aDest.profile_idc == 128 || aDest.profile_idc == 138 ||
aDest.profile_idc == 139 || aDest.profile_idc == 134) {
if ((aDest.chroma_format_idc = br.ReadUE()) == 3) {
aDest.separate_colour_plane_flag = br.ReadBit();
}
br.ReadUE(); // bit_depth_luma_minus8
br.ReadUE(); // bit_depth_chroma_minus8
br.ReadBit(); // qpprime_y_zero_transform_bypass_flag
if (br.ReadBit()) { // seq_scaling_matrix_present_flag
for (int idx = 0; idx < ((aDest.chroma_format_idc != 3) ? 8 : 12); ++idx) {
if (br.ReadBit()) { // Scaling list present
lastScale = nextScale = 8;
int sl_n = (idx < 6) ? 16 : 64;
for (int sl_i = 0; sl_i < sl_n; sl_i++) {
if (nextScale) {
deltaScale = br.ReadSE();
nextScale = (lastScale + deltaScale + 256) % 256;
}
lastScale = (nextScale == 0) ? lastScale : nextScale;
}
}
}
}
}
aDest.log2_max_frame_num = br.ReadUE() + 4;
aDest.pic_order_cnt_type = br.ReadUE();
if (aDest.pic_order_cnt_type == 0) {
aDest.log2_max_pic_order_cnt_lsb = br.ReadUE() + 4;
} else if (aDest.pic_order_cnt_type == 1) {
aDest.delta_pic_order_always_zero_flag = br.ReadBit();
aDest.offset_for_non_ref_pic = br.ReadSE();
aDest.offset_for_top_to_bottom_field = br.ReadSE();
uint32_t num_ref_frames_in_pic_order_cnt_cycle = br.ReadUE();
for (uint32_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
br.ReadSE(); // offset_for_ref_frame[i]
}
}
aDest.max_num_ref_frames = br.ReadUE();
aDest.gaps_in_frame_num_allowed_flag = br.ReadBit();
aDest.pic_width_in_mbs = br.ReadUE() + 1;
aDest.pic_height_in_map_units = br.ReadUE() + 1;
aDest.frame_mbs_only_flag = br.ReadBit();
if (!aDest.frame_mbs_only_flag) {
aDest.pic_height_in_map_units *= 2;
aDest.mb_adaptive_frame_field_flag = br.ReadBit();
}
br.ReadBit(); // direct_8x8_inference_flag
aDest.frame_cropping_flag = br.ReadBit();
if (aDest.frame_cropping_flag) {
aDest.frame_crop_left_offset = br.ReadUE();
aDest.frame_crop_right_offset = br.ReadUE();
aDest.frame_crop_top_offset = br.ReadUE();
aDest.frame_crop_bottom_offset = br.ReadUE();
}
// Calculate common values.
// FFmpeg and VLC ignore the left and top cropping. Do the same here.
uint8_t ChromaArrayType =
aDest.separate_colour_plane_flag ? 0 : aDest.chroma_format_idc;
// Calculate width.
uint32_t CropUnitX = 1;
uint32_t SubWidthC = aDest.chroma_format_idc == 3 ? 1 : 2;
if (ChromaArrayType != 0) {
CropUnitX = SubWidthC;
}
uint32_t cropX = CropUnitX * aDest.frame_crop_right_offset;
aDest.pic_width = aDest.pic_width_in_mbs * 16 - cropX;
// Calculate Height
uint32_t CropUnitY = 2 - aDest.frame_mbs_only_flag;
uint32_t SubHeightC = aDest.chroma_format_idc <= 1 ? 2 : 1;
if (ChromaArrayType != 0)
CropUnitY *= SubHeightC;
uint32_t cropY = CropUnitY * aDest.frame_crop_bottom_offset;
aDest.pic_height = aDest.pic_height_in_map_units * 16 - cropY;
aDest.interlaced = !aDest.frame_mbs_only_flag;
return true;
}
/* static */ void
H264::vui_parameters(BitReader& aBr, SPSData& aDest)
{
aDest.aspect_ratio_info_present_flag = aBr.ReadBit();
if (aDest.aspect_ratio_info_present_flag)
{
aDest.aspect_ratio_idc = aBr.ReadBits(8);
if (aDest.aspect_ratio_idc == 255 /* EXTENDED_SAR */) {
aDest.sar_width = aBr.ReadBits(16);
aDest.sar_height = aBr.ReadBits(16);
}
}
else {
aDest.sar_width = aDest.sar_height = 0;
}
if (aBr.ReadBit()) { //overscan_info_present_flag
aDest.overscan_appropriate_flag = aBr.ReadBit();
}
if (aBr.ReadBit()) { //video_signal_type_present_flag
aDest.video_format = aBr.ReadBits(3);
aDest.video_full_range_flag = aBr.ReadBit();
aDest.colour_description_present_flag = aBr.ReadBit();
if (aDest.colour_description_present_flag) {
aDest.colour_primaries = aBr.ReadBits(8);
aDest.transfer_characteristics = aBr.ReadBits(8);
aDest.matrix_coefficients = aBr.ReadBits(8);
}
}
aDest.chroma_loc_info_present_flag = aBr.ReadBit();
if (aDest.chroma_loc_info_present_flag) {
aDest.chroma_sample_loc_type_top_field = aBr.ReadUE();
aDest.chroma_sample_loc_type_bottom_field = aBr.ReadUE();
}
if (aBr.ReadBit()) { //timing_info_present_flag
aDest.num_units_in_tick = aBr.ReadBits(32);
aDest.time_scale = aBr.ReadBits(32);
aDest.fixed_frame_rate_flag = aBr.ReadBit();
}
bool hrd_present = false;
if (aBr.ReadBit()) { // nal_hrd_parameters_present_flag
hrd_parameters(aBr);
hrd_present = true;
}
if (aBr.ReadBit()) { // vcl_hrd_parameters_present_flag
hrd_parameters(aBr);
hrd_present = true;
}
if (hrd_present) {
aBr.ReadBit(); // low_delay_hrd_flag
}
aDest.pic_struct_present_flag = aBr.ReadBit();
aDest.bitstream_restriction_flag = aBr.ReadBit();
if (aDest.bitstream_restriction_flag) {
aDest.motion_vectors_over_pic_boundaries_flag = aBr.ReadBit();
aDest.max_bytes_per_pic_denom = aBr.ReadUE();
aDest.max_bits_per_mb_denom = aBr.ReadUE();
aDest.log2_max_mv_length_horizontal = aBr.ReadUE();
aDest.log2_max_mv_length_vertical = aBr.ReadUE();
aDest.max_num_reorder_frames = aBr.ReadUE();
aDest.max_dec_frame_buffering = aBr.ReadUE();
}
}
/* static */ void
H264::hrd_parameters(BitReader& aBr)
{
uint32_t cpb_cnt_minus1 = aBr.ReadUE();
aBr.ReadBits(4); // bit_rate_scale
aBr.ReadBits(4); // cpb_size_scale
for (uint32_t SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++) {
aBr.ReadUE(); // bit_rate_value_minus1[ SchedSelIdx ]
aBr.ReadUE(); // cpb_size_value_minus1[ SchedSelIdx ]
aBr.ReadBit(); // cbr_flag[ SchedSelIdx ]
}
aBr.ReadBits(5); // initial_cpb_removal_delay_length_minus1
aBr.ReadBits(5); // cpb_removal_delay_length_minus1
aBr.ReadBits(5); // dpb_output_delay_length_minus1
aBr.ReadBits(5); // time_offset_length
}
/* static */ bool
H264::DecodeSPSFromExtraData(const ByteBuffer* aExtraData, SPSData& aDest)
{
if (!AnnexB::HasSPS(aExtraData)) {
return false;
}
ByteReader reader(*aExtraData);
if (!reader.Read(5)) {
return false;
}
if (!(reader.ReadU8() & 0x1f)) {
// No SPS.
reader.DiscardRemaining();
return false;
}
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != 7) {
// Not a SPS NAL type.
reader.DiscardRemaining();
return false;
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
nsRefPtr<ByteBuffer> rawNAL = new ByteBuffer;
rawNAL->AppendElements(ptr, length);
nsRefPtr<ByteBuffer> sps = DecodeNALUnit(rawNAL);
reader.DiscardRemaining();
return DecodeSPS(sps, aDest);
}
} // namespace mp4_demuxer

View File

@ -0,0 +1,361 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MP4_DEMUXER_H264_H_
#define MP4_DEMUXER_H264_H_
#include "mp4_demuxer/DecoderData.h"
namespace mp4_demuxer
{
class BitReader;
struct SPSData
{
/* Decoded Members */
/*
pic_width is the decoded width according to:
pic_width = ((pic_width_in_mbs_minus1 + 1) * 16)
- (frame_crop_left_offset + frame_crop_right_offset) * 2
*/
uint32_t pic_width;
/*
pic_height is the decoded height according to:
pic_height = (2 - frame_mbs_only_flag) * ((pic_height_in_map_units_minus1 + 1) * 16)
- (frame_crop_top_offset + frame_crop_bottom_offset) * 2
*/
uint32_t pic_height;
bool interlaced;
/*
H264 decoding parameters according to ITU-T H.264 (T-REC-H.264-201402-I/en)
http://www.itu.int/rec/T-REC-H.264-201402-I/en
*/
bool constraint_set0_flag;
bool constraint_set1_flag;
bool constraint_set2_flag;
bool constraint_set3_flag;
bool constraint_set4_flag;
bool constraint_set5_flag;
/*
profile_idc and level_idc indicate the profile and level to which the coded
video sequence conforms when the SVC sequence parameter set is the active
SVC sequence parameter set.
*/
uint8_t profile_idc;
uint8_t level_idc;
/*
seq_parameter_set_id identifies the sequence parameter set that is referred
to by the picture parameter set. The value of seq_parameter_set_id shall be
in the range of 0 to 31, inclusive.
*/
uint8_t seq_parameter_set_id;
/*
When the value of chroma_format_idc is equal to 1, the nominal vertical
and horizontal relative locations of luma and chroma samples in frames are
shown in Figure 6-1. Alternative chroma sample relative locations may be
indicated in video usability information (see Annex E).
*/
uint8_t chroma_format_idc;
/*
If separate_colour_plane_flag is equal to 0, each of the two chroma arrays
has the same height and width as the luma array. Otherwise
(separate_colour_plane_flag is equal to 1), the three colour planes are
separately processed as monochrome sampled pictures.
*/
bool separate_colour_plane_flag;
/*
log2_max_frame_num_minus4 specifies the value of the variable
MaxFrameNum that is used in frame_num related derivations as
follows:
MaxFrameNum = 2( log2_max_frame_num_minus4 + 4 ). The value of
log2_max_frame_num_minus4 shall be in the range of 0 to 12, inclusive.
*/
uint8_t log2_max_frame_num;
/*
pic_order_cnt_type specifies the method to decode picture order
count (as specified in subclause 8.2.1). The value of
pic_order_cnt_type shall be in the range of 0 to 2, inclusive.
*/
uint8_t pic_order_cnt_type;
/*
log2_max_pic_order_cnt_lsb_minus4 specifies the value of the
variable MaxPicOrderCntLsb that is used in the decoding
process for picture order count as specified in subclause
8.2.1 as follows:
MaxPicOrderCntLsb = 2( log2_max_pic_order_cnt_lsb_minus4 + 4 )
The value of log2_max_pic_order_cnt_lsb_minus4 shall be in
the range of 0 to 12, inclusive.
*/
uint8_t log2_max_pic_order_cnt_lsb;
/*
delta_pic_order_always_zero_flag equal to 1 specifies that
delta_pic_order_cnt[ 0 ] and delta_pic_order_cnt[ 1 ] are
not present in the slice headers of the sequence and shall
be inferred to be equal to 0.
*/
bool delta_pic_order_always_zero_flag;
/*
offset_for_non_ref_pic is used to calculate the picture
order count of a non-reference picture as specified in
8.2.1. The value of offset_for_non_ref_pic shall be in the
range of -231 to 231 - 1, inclusive.
*/
int8_t offset_for_non_ref_pic;
/*
offset_for_top_to_bottom_field is used to calculate the
picture order count of a bottom field as specified in
subclause 8.2.1. The value of offset_for_top_to_bottom_field
shall be in the range of -231 to 231 - 1, inclusive.
*/
int8_t offset_for_top_to_bottom_field;
/*
max_num_ref_frames specifies the maximum number of short-term and
long-term reference frames, complementary reference field pairs,
and non-paired reference fields that may be used by the decoding
process for inter prediction of any picture in the
sequence. max_num_ref_frames also determines the size of the sliding
window operation as specified in subclause 8.2.5.3. The value of
max_num_ref_frames shall be in the range of 0 to MaxDpbSize (as
specified in subclause A.3.1 or A.3.2), inclusive.
*/
uint32_t max_num_ref_frames;
/*
gaps_in_frame_num_value_allowed_flag specifies the allowed
values of frame_num as specified in subclause 7.4.3 and the
decoding process in case of an inferred gap between values of
frame_num as specified in subclause 8.2.5.2.
*/
bool gaps_in_frame_num_allowed_flag;
/*
pic_width_in_mbs_minus1 plus 1 specifies the width of each
decoded picture in units of macroblocks. 16 macroblocks in a row
*/
uint32_t pic_width_in_mbs;
/*
pic_height_in_map_units_minus1 plus 1 specifies the height in
slice group map units of a decoded frame or field. 16
macroblocks in each column.
*/
uint32_t pic_height_in_map_units;
/*
frame_mbs_only_flag equal to 0 specifies that coded pictures of
the coded video sequence may either be coded fields or coded
frames. frame_mbs_only_flag equal to 1 specifies that every
coded picture of the coded video sequence is a coded frame
containing only frame macroblocks.
*/
bool frame_mbs_only_flag;
/*
mb_adaptive_frame_field_flag equal to 0 specifies no
switching between frame and field macroblocks within a
picture. mb_adaptive_frame_field_flag equal to 1 specifies
the possible use of switching between frame and field
macroblocks within frames. When mb_adaptive_frame_field_flag
is not present, it shall be inferred to be equal to 0.
*/
bool mb_adaptive_frame_field_flag;
/*
frame_cropping_flag equal to 1 specifies that the frame cropping
offset parameters follow next in the sequence parameter
set. frame_cropping_flag equal to 0 specifies that the frame
cropping offset parameters are not present.
*/
bool frame_cropping_flag;
uint32_t frame_crop_left_offset;;
uint32_t frame_crop_right_offset;
uint32_t frame_crop_top_offset;
uint32_t frame_crop_bottom_offset;
// VUI Parameters
/*
vui_parameters_present_flag equal to 1 specifies that the
vui_parameters( ) syntax structure as specified in Annex E is
present. vui_parameters_present_flag equal to 0 specifies that
the vui_parameters( ) syntax structure as specified in Annex E
is not present.
*/
bool vui_parameters_present_flag;
/*
aspect_ratio_info_present_flag equal to 1 specifies that
aspect_ratio_idc is present. aspect_ratio_info_present_flag
equal to 0 specifies that aspect_ratio_idc is not present.
*/
bool aspect_ratio_info_present_flag;
/*
aspect_ratio_idc specifies the value of the sample aspect
ratio of the luma samples. Table E-1 shows the meaning of
the code. When aspect_ratio_idc indicates Extended_SAR, the
sample aspect ratio is represented by sar_width and
sar_height. When the aspect_ratio_idc syntax element is not
present, aspect_ratio_idc value shall be inferred to be
equal to 0.
*/
uint8_t aspect_ratio_idc;
uint32_t sar_width;
uint32_t sar_height;
bool overscan_info_present_flag;
bool overscan_appropriate_flag;
uint8_t video_format;
bool video_full_range_flag;
bool colour_description_present_flag;
uint8_t colour_primaries;
uint8_t transfer_characteristics;
uint8_t matrix_coefficients;
bool chroma_loc_info_present_flag;
uint32_t chroma_sample_loc_type_top_field;
uint32_t chroma_sample_loc_type_bottom_field;
uint32_t num_units_in_tick;
uint32_t time_scale;
bool fixed_frame_rate_flag;
// Bitstream restriction parameters
/*
pic_struct_present_flag equal to 1 specifies that picture timing SEI
messages (clause D.2.2) are present that include the pic_struct syntax
element. pic_struct_present_flag equal to 0 specifies that the pic_struct
syntax element is not present in picture timing SEI messages.
When pic_struct_present_flag is not present, its value shall be inferred to
be equal to 0.
*/
bool pic_struct_present_flag;
/*
bitstream_restriction_flag equal to 1, specifies that the following coded
video sequence bitstream restriction parameters are present.
bitstream_restriction_flag equal to 0, specifies that the following coded
video sequence bitstream restriction parameters are not present.
*/
bool bitstream_restriction_flag;
/*
motion_vectors_over_pic_boundaries_flag equal to 0 indicates that no
sample outside the picture boundaries and no sample at a fractional
sample position for which the sample value is derived using one or more
samples outside the picture boundaries is used for inter prediction of any
sample. motion_vectors_over_pic_boundaries_flag equal to 1 indicates that
one or more samples outside picture boundaries may be used in inter
prediction. When the motion_vectors_over_pic_boundaries_flag syntax element
is not present, motion_vectors_over_pic_boundaries_flag value shall be
inferred to be equal to 1.
*/
bool motion_vectors_over_pic_boundaries_flag;
/*
max_bytes_per_pic_denom indicates a number of bytes not exceeded by the
sum of the sizes of the VCL NAL units associated with any coded picture in
the coded video sequence.
*/
uint32_t max_bytes_per_pic_denom;
/*
max_bits_per_mb_denom indicates an upper bound for the number of coded bits
of macroblock_layer( ) data for any macroblock in any picture of the coded
video sequence. The value of max_bits_per_mb_denom shall be in the range
of 0 to 16, inclusive.
*/
uint32_t max_bits_per_mb_denom;
/*
log2_max_mv_length_horizontal and log2_max_mv_length_vertical indicate the
maximum absolute value of a decoded horizontal and vertical motion vector
component, respectively, in 14 luma sample units, for all pictures in the
coded video sequence. A value of n asserts that no value of a motion vector
component shall exceed the range from 2n to 2n 1, inclusive, in units
of 14 luma sample displacement. The value of log2_max_mv_length_horizontal
shall be in the range of 0 to 16, inclusive. The value of
log2_max_mv_length_vertical shall be in the range of 0 to 16, inclusive.
When log2_max_mv_length_horizontal is not present, the values of
log2_max_mv_length_horizontal and log2_max_mv_length_vertical shall be
inferred to be equal to 16.
*/
uint32_t log2_max_mv_length_horizontal;
uint32_t log2_max_mv_length_vertical;
/*
max_num_reorder_frames indicates an upper bound for the number of frames
buffers, in the decoded picture buffer (DPB), that are required for storing
frames, complementary field pairs, and non-paired fields before output.
It is a requirement of bitstream conformance that the maximum number of
frames, complementary field pairs, or non-paired fields that precede any
frame, complementary field pair, or non-paired field in the coded video
sequence in decoding order and follow it in output order shall be less than
or equal to max_num_reorder_frames. The value of max_num_reorder_frames
shall be in the range of 0 to max_dec_frame_buffering, inclusive.
When the max_num_reorder_frames syntax element is not present, the value
of max_num_reorder_frames value shall be inferred as follows:
If profile_idc is equal to 44, 86, 100, 110, 122, or 244 and
constraint_set3_flag is equal to 1, the value of max_num_reorder_frames
shall be inferred to be equal to 0.
Otherwise (profile_idc is not equal to 44, 86, 100, 110, 122, or 244 or
constraint_set3_flag is equal to 0), the value of max_num_reorder_frames
shall be inferred to be equal to MaxDpbFrames.
*/
uint32_t max_num_reorder_frames;
/*
max_dec_frame_buffering specifies the required size of the HRD decoded
picture buffer (DPB) in units of frame buffers. It is a requirement of
bitstream conformance that the coded video sequence shall not require a
decoded picture buffer with size of more than
Max( 1, max_dec_frame_buffering ) frame buffers to enable the output of
decoded pictures at the output times specified by dpb_output_delay of the
picture timing SEI messages. The value of max_dec_frame_buffering shall be
greater than or equal to max_num_ref_frames. An upper bound for the value
of max_dec_frame_buffering is specified by the level limits in
clauses A.3.1, A.3.2, G.10.2.1, and H.10.2.
*/
uint32_t max_dec_frame_buffering;
SPSData();
};
class H264
{
public:
static bool DecodeSPSFromExtraData(const ByteBuffer* aExtraData, SPSData& aDest);
/* Extract RAW BYTE SEQUENCE PAYLOAD from NAL content.
Returns nullptr if invalid content. */
static already_AddRefed<ByteBuffer> DecodeNALUnit(const ByteBuffer* aNAL);
/* Decode SPS NAL RBSP and fill SPSData structure */
static bool DecodeSPS(const ByteBuffer* aSPS, SPSData& aDest);
private:
static void vui_parameters(BitReader& aBr, SPSData& aDest);
// Read HRD parameters, all data is ignored.
static void hrd_parameters(BitReader& aBr);
};
} // namespace mp4_demuxer
#endif // MP4_DEMUXER_H264_H_

View File

@ -55,6 +55,7 @@ EXPORTS.mp4_demuxer += [
'binding/include/mp4_demuxer/ByteReader.h',
'binding/include/mp4_demuxer/ByteWriter.h',
'binding/include/mp4_demuxer/DecoderData.h',
'binding/include/mp4_demuxer/H264.h',
'binding/include/mp4_demuxer/Interval.h',
'binding/include/mp4_demuxer/MoofParser.h',
'binding/include/mp4_demuxer/mp4_demuxer.h',
@ -75,6 +76,7 @@ UNIFIED_SOURCES += [
'binding/Box.cpp',
'binding/BufferStream.cpp',
'binding/DecoderData.cpp',
'binding/H264.cpp',
'binding/Index.cpp',
'binding/MoofParser.cpp',
'binding/mp4_demuxer.cpp',

View File

@ -83,7 +83,7 @@ VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics(
int32_t VPMContentAnalysis::Release() {
content_metrics_.reset(NULL);
prev_frame_.reset(NULL);
prev_frame_.reset();
width_ = 0;
height_ = 0;
@ -112,7 +112,7 @@ int32_t VPMContentAnalysis::Initialize(int width, int height) {
}
content_metrics_.reset(NULL);
prev_frame_.reset(NULL);
prev_frame_.reset();
// Spatial Metrics don't work on a border of 8. Minimum processing
// block size is 16 pixels. So make sure the width and height support this.

View File

@ -66,7 +66,7 @@ class VPMContentAnalysis {
#endif
const uint8_t* orig_frame_;
scoped_ptr<uint8_t> prev_frame_;
scoped_ptr<uint8_t[]> prev_frame_;
int width_;
int height_;
int skip_num_;

View File

@ -1 +0,0 @@
../../../../tools/perf

View File

@ -512,11 +512,11 @@
* conversions.
* MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile
* time error to pass arithmetic expressions on variables to the function.
* MOZ_STRONG_REF: Applies to declarations of pointer types. This attribute
* MOZ_OWNING_REF: Applies to declarations of pointer types. This attribute
* tells the compiler that the raw pointer is a strong reference, and that
* property is somehow enforced by the code. This can make the compiler
* ignore these pointers when validating the usage of pointers otherwise.
* MOZ_WEAK_REF: Applies to declarations of pointer types. This attribute
* MOZ_NON_OWNING_REF: Applies to declarations of pointer types. This attribute
* tells the compiler that the raw pointer is a weak reference, and that
* property is somehow enforced by the code. This can make the compiler
* ignore these pointers when validating the usage of pointers otherwise.
@ -535,8 +535,8 @@
# endif
# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
# define MOZ_STRONG_REF __attribute__((annotate("moz_strong_ref")))
# define MOZ_WEAK_REF __attribute__((annotate("moz_weak_ref")))
# define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
# define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
/*
* It turns out that clang doesn't like void func() __attribute__ {} without a
* warning, so use pragmas to disable the warning. This code won't work on GCC
@ -556,8 +556,8 @@
# define MOZ_IMPLICIT /* nothing */
# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */
# define MOZ_HEAP_ALLOCATOR /* nothing */
# define MOZ_STRONG_REF /* nothing */
# define MOZ_WEAK_REF /* nothing */
# define MOZ_OWNING_REF /* nothing */
# define MOZ_NON_OWNING_REF /* nothing */
#endif /* MOZ_CLANG_PLUGIN */
/*

View File

@ -79,6 +79,11 @@ struct UnsignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, false>
{};
template<size_t Size>
struct SignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, true>
{};
template<typename IntegerType>
struct PositionOfSignBit
{

View File

@ -285,7 +285,7 @@ private:
mPtr = aVal;
}
T* mPtr;
T* MOZ_OWNING_REF mPtr;
static MOZ_ALWAYS_INLINE T* ref(T* aVal)
{
@ -336,7 +336,7 @@ public:
private:
TemporaryRef(T* aVal, const DontRef&) : mPtr(aVal) {}
mutable T* mPtr;
mutable T* MOZ_OWNING_REF mPtr;
TemporaryRef() MOZ_DELETE;
void operator=(const TemporaryRef&) MOZ_DELETE;

View File

@ -69,6 +69,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/NullPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TypeTraits.h"
@ -122,7 +123,7 @@ private:
void detach() { mPtr = nullptr; }
T* mPtr;
T* MOZ_NON_OWNING_REF mPtr;
};
} // namespace detail

View File

@ -25,7 +25,6 @@ pref("security.ssl3.ecdhe_rsa_aes_256_sha", true);
pref("security.ssl3.ecdhe_ecdsa_aes_256_sha", true);
pref("security.ssl3.dhe_rsa_aes_128_sha", true);
pref("security.ssl3.dhe_rsa_aes_256_sha", true);
pref("security.ssl3.dhe_dss_aes_128_sha", false);
pref("security.ssl3.ecdhe_rsa_rc4_128_sha", true);
pref("security.ssl3.ecdhe_ecdsa_rc4_128_sha", true);
pref("security.ssl3.rsa_aes_128_sha", true);

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import itertools
import json
import os
import re
@ -16,6 +17,7 @@ from ..frontend.data import (
ConfigFileSubstitution,
ExampleWebIDLInterface,
HeaderFileSubstitution,
IPDLFile,
GeneratedEventWebIDLFile,
GeneratedWebIDLFile,
PreprocessedTestWebIDLFile,
@ -172,6 +174,7 @@ class CommonBackend(BuildBackend):
self._test_manager = TestManager(self.environment)
self._webidls = WebIDLCollection()
self._configs = set()
self._ipdl_sources = set()
def consume_object(self, obj):
self._configs.add(obj.config)
@ -225,6 +228,9 @@ class CommonBackend(BuildBackend):
elif isinstance(obj, ExampleWebIDLInterface):
self._webidls.example_interfaces.add(obj.name)
elif isinstance(obj, IPDLFile):
self._ipdl_sources.add(mozpath.join(obj.srcdir, obj.basename))
else:
return
@ -236,6 +242,24 @@ class CommonBackend(BuildBackend):
self._handle_webidl_collection(self._webidls)
sorted_ipdl_sources = list(sorted(self._ipdl_sources))
def files_from(ipdl):
base = mozpath.basename(ipdl)
root, ext = mozpath.splitext(base)
# Both .ipdl and .ipdlh become .cpp files
files = ['%s.cpp' % root]
if ext == '.ipdl':
# .ipdl also becomes Child/Parent.cpp files
files.extend(['%sChild.cpp' % root,
'%sParent.cpp' % root])
return files
ipdl_cppsrcs = list(itertools.chain(*[files_from(p) for p in sorted_ipdl_sources]))
self._handle_ipdl_sources(sorted_ipdl_sources, ipdl_cppsrcs)
for config in self._configs:
self.backend_input_files.add(config.source)

View File

@ -45,7 +45,6 @@ from ..frontend.data import (
HostSimpleProgram,
HostSources,
InstallationTarget,
IPDLFile,
JARManifest,
JavaJarData,
JavaScriptModules,
@ -277,7 +276,6 @@ class RecursiveMakeBackend(CommonBackend):
CommonBackend._init(self)
self._backend_files = {}
self._ipdl_sources = set()
def detailed(summary):
s = '{:d} total backend files; ' \
@ -451,9 +449,6 @@ class RecursiveMakeBackend(CommonBackend):
elif isinstance(obj, JARManifest):
backend_file.write('JAR_MANIFEST := %s\n' % obj.path)
elif isinstance(obj, IPDLFile):
self._ipdl_sources.add(mozpath.join(obj.srcdir, obj.basename))
elif isinstance(obj, Program):
self._process_program(obj.program, backend_file)
self._process_linked_libraries(obj, backend_file)
@ -750,36 +745,6 @@ class RecursiveMakeBackend(CommonBackend):
self._no_skip['tools'].add(mozpath.relpath(objdir,
self.environment.topobjdir))
# Write out a master list of all IPDL source files.
ipdl_dir = mozpath.join(self.environment.topobjdir, 'ipc', 'ipdl')
mk = Makefile()
sorted_ipdl_sources = list(sorted(self._ipdl_sources))
mk.add_statement('ALL_IPDLSRCS := %s' % ' '.join(sorted_ipdl_sources))
def files_from(ipdl):
base = mozpath.basename(ipdl)
root, ext = mozpath.splitext(base)
# Both .ipdl and .ipdlh become .cpp files
files = ['%s.cpp' % root]
if ext == '.ipdl':
# .ipdl also becomes Child/Parent.cpp files
files.extend(['%sChild.cpp' % root,
'%sParent.cpp' % root])
return files
ipdl_cppsrcs = list(itertools.chain(*[files_from(p) for p in sorted_ipdl_sources]))
self._add_unified_build_rules(mk, ipdl_cppsrcs, ipdl_dir,
unified_prefix='UnifiedProtocols',
unified_files_makefile_variable='CPPSRCS')
mk.add_statement('IPDLDIRS := %s' % ' '.join(sorted(set(mozpath.dirname(p)
for p in self._ipdl_sources))))
with self._write_file(mozpath.join(ipdl_dir, 'ipdlsrcs.mk')) as ipdls:
mk.dump(ipdls, removal_guard=False)
self._fill_root_mk()
# Write out a dependency file used to determine whether a config.status
@ -1332,6 +1297,23 @@ INSTALL_TARGETS += %(prefix)s
self.summary.makefile_out_count += 1
def _handle_ipdl_sources(self, sorted_ipdl_sources, ipdl_cppsrcs):
# Write out a master list of all IPDL source files.
ipdl_dir = mozpath.join(self.environment.topobjdir, 'ipc', 'ipdl')
mk = Makefile()
mk.add_statement('ALL_IPDLSRCS := %s' % ' '.join(sorted_ipdl_sources))
self._add_unified_build_rules(mk, ipdl_cppsrcs, ipdl_dir,
unified_prefix='UnifiedProtocols',
unified_files_makefile_variable='CPPSRCS')
mk.add_statement('IPDLDIRS := %s' % ' '.join(sorted(set(mozpath.dirname(p)
for p in self._ipdl_sources))))
with self._write_file(mozpath.join(ipdl_dir, 'ipdlsrcs.mk')) as ipdls:
mk.dump(ipdls, removal_guard=False)
def _handle_webidl_collection(self, webidls):
if not webidls.all_stems():
return

View File

@ -101,16 +101,16 @@ class VisualStudioBackend(CommonBackend):
self._paths_to_configs[reldir] = obj.config
if isinstance(obj, Sources):
self._add_sources(self, reldir, obj)
self._add_sources(reldir, obj)
elif isinstance(obj, HostSources):
self._add_sources(self, reldir, obj)
self._add_sources(reldir, obj)
elif isinstance(obj, GeneratedSources):
self._add_sources(self, reldir, obj)
self._add_sources(reldir, obj)
elif isinstance(obj, UnifiedSources):
self._addr_sources(self, reldir, obj)
self._add_sources(reldir, obj)
elif isinstance(obj, Library):
self._libs_to_paths[obj.basename] = reldir

View File

@ -1109,7 +1109,7 @@ AuthCertificate(CertVerifier& certVerifier,
RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
RefPtr<nsNSSCertificate> nsc;
if (!status || !status->mServerCert) {
if (!status || !status->HasServerCert()) {
if( rv == SECSuccess ){
nsc = nsNSSCertificate::Create(cert, &evOidPolicy);
}
@ -1141,10 +1141,17 @@ AuthCertificate(CertVerifier& certVerifier,
infoObject, status);
}
if (status && !status->mServerCert) {
status->mServerCert = nsc;
if (status && !status->HasServerCert()) {
nsNSSCertificate::EVStatus evStatus;
if (evOidPolicy == SEC_OID_UNKNOWN || rv != SECSuccess) {
evStatus = nsNSSCertificate::ev_status_invalid;
} else {
evStatus = nsNSSCertificate::ev_status_valid;
}
status->SetServerCert(nsc, evStatus);
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("AuthCertificate setting NEW cert %p\n", status->mServerCert.get()));
("AuthCertificate setting NEW cert %p\n", nsc.get()));
}
}

View File

@ -242,11 +242,11 @@ TransportSecurityInfo::formatErrorMessage(MutexAutoLock const & proofOfLock,
nsresult rv;
NS_ConvertASCIItoUTF16 hostNameU(mHostName);
NS_ASSERTION(errorMessageType != OverridableCertErrorMessage ||
(mSSLStatus && mSSLStatus->mServerCert &&
(mSSLStatus && mSSLStatus->HasServerCert() &&
mSSLStatus->mHaveCertErrorBits),
"GetErrorLogMessage called for cert error without cert");
if (errorMessageType == OverridableCertErrorMessage &&
mSSLStatus && mSSLStatus->mServerCert) {
mSSLStatus && mSSLStatus->HasServerCert()) {
rv = formatOverridableCertErrorMessage(*mSSLStatus, errorCode,
mHostName, mPort,
suppressPort443,
@ -296,8 +296,8 @@ TransportSecurityInfo::GetInterface(const nsIID & uuid, void * *result)
// of the previous value. This is so when older versions attempt to
// read a newer serialized TransportSecurityInfo, they will actually
// fail and return NS_ERROR_FAILURE instead of silently failing.
#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x2429, 0x4866, \
{ 0x92, 0x89, 0x45, 0x51, 0xc2, 0x01, 0xca, 0xf2 } }
#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x328f, 0x45ab, \
{ 0xa8, 0xa4, 0x35, 0x18, 0x80, 0x04, 0x77, 0x8d } }
static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
NS_IMETHODIMP
@ -1089,7 +1089,7 @@ TransportSecurityInfo::SetStatusErrorBits(nsIX509Cert & cert,
if (!mSSLStatus)
mSSLStatus = new nsSSLStatus();
mSSLStatus->mServerCert = &cert;
mSSLStatus->SetServerCert(&cert, nsNSSCertificate::ev_status_invalid);
mSSLStatus->mHaveCertErrorBits = true;
mSSLStatus->mIsDomainMismatch =

View File

@ -1288,17 +1288,17 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
if (equals_previous) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("HandshakeCallback using PREV cert %p\n", prevcert.get()));
status->mServerCert = prevcert;
status->SetServerCert(prevcert, nsNSSCertificate::ev_status_unknown);
}
else {
if (status->mServerCert) {
if (status->HasServerCert()) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("HandshakeCallback KEEPING cert %p\n", status->mServerCert.get()));
("HandshakeCallback KEEPING existing cert\n"));
}
else {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("HandshakeCallback using NEW cert %p\n", nssc.get()));
status->mServerCert = nssc;
status->SetServerCert(nssc, nsNSSCertificate::ev_status_unknown);
}
}

View File

@ -49,6 +49,12 @@ public:
SECOidTag* evOidPolicy = nullptr);
static nsNSSCertificate* ConstructFromDER(char* certDER, int derLen);
enum EVStatus {
ev_status_invalid = 0,
ev_status_valid = 1,
ev_status_unknown = 2
};
private:
virtual ~nsNSSCertificate();
@ -65,9 +71,7 @@ private:
nsresult GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg);
enum {
ev_status_invalid = 0, ev_status_valid = 1, ev_status_unknown = 2
} mCachedEVStatus;
EVStatus mCachedEVStatus;
SECOidTag mCachedEVOidTag;
nsresult hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV);
nsresult getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV);

View File

@ -650,9 +650,6 @@ static const CipherPref sCipherPrefs[] = {
{ "security.ssl3.dhe_rsa_aes_256_sha",
TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true },
{ "security.ssl3.dhe_dss_aes_128_sha",
TLS_DHE_DSS_WITH_AES_128_CBC_SHA, false }, // deprecated (DSS)
{ "security.ssl3.ecdhe_rsa_rc4_128_sha",
TLS_ECDHE_RSA_WITH_RC4_128_SHA, true, true }, // deprecated (RC4)
{ "security.ssl3.ecdhe_ecdsa_rc4_128_sha",

View File

@ -398,8 +398,9 @@ nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval)
// Before checking the server certificate we need to make sure the
// handshake has completed.
if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->HasServerCert()) {
return NS_OK;
}
// If the cert has error bits (e.g. it is untrusted) then do not join.
// The value of mHaveCertErrorBits is only reliable because we know that
@ -418,7 +419,10 @@ nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval)
ScopedCERTCertificate nssCert;
nsCOMPtr<nsIX509Cert> cert(SSLStatus()->mServerCert);
nsCOMPtr<nsIX509Cert> cert;
if (NS_FAILED(SSLStatus()->GetServerCert(getter_AddRefs(cert)))) {
return NS_OK;
}
if (cert) {
nssCert = cert->GetCert();
}

View File

@ -121,28 +121,20 @@ nsSSLStatus::GetIsExtendedValidation(bool* aIsEV)
NS_ENSURE_ARG_POINTER(aIsEV);
*aIsEV = false;
#ifdef MOZ_NO_EV_CERTS
return NS_OK;
#else
nsCOMPtr<nsIX509Cert> cert = mServerCert;
// mServerCert should never be null when this method is called because
// nsSSLStatus objects always have mServerCert set right after they are
// constructed and before they are returned. GetIsExtendedValidation should
// only be called in the chrome process (in e10s), and mServerCert will always
// implement nsIIdentityInfo in the chrome process.
nsCOMPtr<nsIIdentityInfo> idinfo = do_QueryInterface(cert);
if (!idinfo) {
NS_ERROR("nsSSLStatus has null mServerCert or was called in the content "
"process");
return NS_ERROR_UNEXPECTED;
}
// Never allow bad certs for EV, regardless of overrides.
if (mHaveCertErrorBits) {
return NS_OK;
}
return idinfo->GetIsExtendedValidation(aIsEV);
if (mHasIsEVStatus) {
*aIsEV = mIsEV;
return NS_OK;
}
#ifdef MOZ_NO_EV_CERTS
return NS_OK;
#else
return NS_ERROR_NOT_AVAILABLE;
#endif
}
@ -169,7 +161,11 @@ nsSSLStatus::Read(nsIObjectInputStream* aStream)
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->ReadBoolean(&mIsUntrusted);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->ReadBoolean(&mIsEV);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->ReadBoolean(&mHasIsEVStatus);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->ReadBoolean(&mHaveCipherSuiteAndProtocol);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->ReadBoolean(&mHaveCertErrorBits);
@ -197,7 +193,11 @@ nsSSLStatus::Write(nsIObjectOutputStream* aStream)
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteBoolean(mIsUntrusted);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteBoolean(mIsEV);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteBoolean(mHasIsEVStatus);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteBoolean(mHaveCipherSuiteAndProtocol);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteBoolean(mHaveCertErrorBits);
@ -274,6 +274,8 @@ nsSSLStatus::nsSSLStatus()
, mIsDomainMismatch(false)
, mIsNotValidAtThisTime(false)
, mIsUntrusted(false)
, mIsEV(false)
, mHasIsEVStatus(false)
, mHaveCipherSuiteAndProtocol(false)
, mHaveCertErrorBits(false)
{
@ -284,3 +286,26 @@ NS_IMPL_ISUPPORTS(nsSSLStatus, nsISSLStatus, nsISerializable, nsIClassInfo)
nsSSLStatus::~nsSSLStatus()
{
}
void
nsSSLStatus::SetServerCert(nsIX509Cert* aServerCert, nsNSSCertificate::EVStatus aEVStatus)
{
mServerCert = aServerCert;
if (aEVStatus != nsNSSCertificate::ev_status_unknown) {
mIsEV = (aEVStatus == nsNSSCertificate::ev_status_valid);
mHasIsEVStatus = true;
return;
}
#ifndef MOZ_NO_EV_CERTS
nsCOMPtr<nsIIdentityInfo> idinfo = do_QueryInterface(mServerCert);
if (idinfo) {
nsresult rv = idinfo->GetIsExtendedValidation(&mIsEV);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
mHasIsEVStatus = true;
}
#endif
}

View File

@ -13,6 +13,7 @@
#include "nsIX509Cert.h"
#include "nsISerializable.h"
#include "nsIClassInfo.h"
#include "nsNSSCertificate.h" // For EVStatus
class nsSSLStatus MOZ_FINAL
: public nsISSLStatus
@ -29,25 +30,34 @@ public:
nsSSLStatus();
/* public for initilization in this file */
nsCOMPtr<nsIX509Cert> mServerCert;
void SetServerCert(nsIX509Cert* aServerCert, nsNSSCertificate::EVStatus aEVStatus);
bool HasServerCert() {
return mServerCert != nullptr;
}
/* public for initilization in this file */
uint16_t mCipherSuite;
uint16_t mProtocolVersion;
bool mIsDomainMismatch;
bool mIsNotValidAtThisTime;
bool mIsUntrusted;
bool mIsEV;
bool mHasIsEVStatus;
bool mHaveCipherSuiteAndProtocol;
/* mHaveCertErrrorBits is relied on to determine whether or not a SPDY
connection is eligible for joining in nsNSSSocketInfo::JoinConnection() */
bool mHaveCertErrorBits;
private:
nsCOMPtr<nsIX509Cert> mServerCert;
};
#define NS_SSLSTATUS_CID \
{ 0x61f69c85, 0x0fed, 0x44fb, \
{ 0x89, 0x8f, 0xa4, 0xb1, 0x3c, 0x33, 0x3c, 0x8d } }
{ 0xe2f14826, 0x9e70, 0x4647, \
{ 0xb2, 0x3f, 0x10, 0x10, 0xf5, 0x12, 0x46, 0x28 } }
#endif

View File

@ -31,7 +31,7 @@ namespace mozilla { namespace pkix {
// Similar to boost::scoped_ptr and std::unique_ptr. Does not support copying
// or assignment.
template <typename T, void (*Destroyer)(T*)>
template <typename T, void (&Destroyer)(T*)>
class ScopedPtr
{
public:
@ -73,28 +73,28 @@ protected:
void operator=(const ScopedPtr&) /* = delete */;
};
template <typename T, void(*Destroyer)(T*)>
template <typename T, void(&Destroyer)(T*)>
inline bool
operator==(T* a, const ScopedPtr<T, Destroyer>& b)
{
return a == b.get();
}
template <typename T, void(*Destroyer)(T*)>
template <typename T, void(&Destroyer)(T*)>
inline bool
operator==(const ScopedPtr<T, Destroyer>& a, T* b)
{
return a.get() == b;
}
template <typename T, void(*Destroyer)(T*)>
template <typename T, void(&Destroyer)(T*)>
inline bool
operator!=(T* a, const ScopedPtr<T, Destroyer>& b)
{
return a != b.get();
}
template <typename T, void(*Destroyer)(T*)>
template <typename T, void(&Destroyer)(T*)>
inline bool
operator!=(const ScopedPtr<T, Destroyer>& a, T* b)
{

View File

@ -74,11 +74,11 @@ template <typename R, typename P1, typename B1>
class Bind1
{
public:
typedef R (*F)(P1 &, B1 &);
Bind1(F f, B1 & b1) : f(f), b1(b1) { }
R operator()(P1 & p1) const { return f(p1, b1); }
typedef R (&F)(P1&, B1&);
Bind1(F f, B1& b1) : f(f), b1(b1) { }
R operator()(P1& p1) const { return f(p1, b1); }
private:
const F f;
F f;
B1& b1;
void operator=(const Bind1&) /*= delete*/;
};
@ -87,11 +87,11 @@ template <typename R, typename P1, typename B1, typename B2>
class Bind2
{
public:
typedef R (*F)(P1&, B1&, B2&);
typedef R (&F)(P1&, B1&, B2&);
Bind2(F f, B1& b1, B2& b2) : f(f), b1(b1), b2(b2) { }
R operator()(P1& p1) const { return f(p1, b1, b2); }
private:
const F f;
F f;
B1& b1;
B2& b2;
void operator=(const Bind2&) /*= delete*/;
@ -101,12 +101,12 @@ template <typename R, typename P1, typename B1, typename B2, typename B3>
class Bind3
{
public:
typedef R (*F)(P1&, B1, B2, B3&);
typedef R (&F)(P1&, B1, B2, B3&);
Bind3(F f, B1& b1, B2& b2, B3& b3)
: f(f), b1(b1), b2(b2), b3(b3) { }
R operator()(P1& p1) const { return f(p1, b1, b2, b3); }
private:
const F f;
F f;
B1& b1;
B2& b2;
B3& b3;
@ -118,12 +118,12 @@ template <typename R, typename P1, typename B1, typename B2, typename B3,
class Bind4
{
public:
typedef R (*F)(P1&, B1, B2, B3&, B4&);
typedef R (&F)(P1&, B1, B2, B3&, B4&);
Bind4(F f, B1& b1, B2& b2, B3& b3, B4& b4)
: f(f), b1(b1), b2(b2), b3(b3), b4(b4) { }
R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4); }
private:
const F f;
F f;
B1& b1;
B2& b2;
B3& b3;
@ -136,12 +136,18 @@ template <typename R, typename C1, typename P1, typename P2, typename P3,
class BindToMemberFunction4
{
public:
// XXX: C++ doesn't have reference-to-member function, only
// pointer-to-member function, so we can't enforce the non-nullness of f
// using the type system.
typedef R (C1::*F)(P1&, P2&, P3, P4&);
BindToMemberFunction4(F f, C1* that) : f(f), that(that) { }
R operator()(P1& p1, P2& p2, P3 p3, P4& p4) const { return (that->*f)(p1, p2, p3, p4); }
BindToMemberFunction4(F f, C1& that) : f(f), that(that) { }
R operator()(P1& p1, P2& p2, P3 p3, P4& p4) const
{
return (that.*f)(p1, p2, p3, p4);
}
private:
const F f;
C1* const that;
C1& that;
void operator=(const BindToMemberFunction4&) /*= delete*/;
};
@ -150,12 +156,12 @@ template <typename R, typename P1, typename B1, typename B2, typename B3,
class Bind5
{
public:
typedef R (*F)(P1&, B1, B2, B3, B4, B5);
typedef R (&F)(P1&, B1, B2, B3, B4, B5);
Bind5(F f, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5)
: f(f), b1(b1), b2(b2), b3(b3), b4(b4), b5(b5) { }
R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4, b5); }
private:
const F f;
F f;
B1 b1;
B2 b2;
B3 b3;
@ -168,21 +174,21 @@ private:
template <typename R, typename P1, typename B1>
inline internal::Bind1<R, P1, B1>
bind(R (*f)(P1&, B1&), Placeholder1&, B1& b1)
bind(R (&f)(P1&, B1&), Placeholder1&, B1& b1)
{
return internal::Bind1<R, P1, B1>(f, b1);
}
template <typename R, typename P1, typename B1, typename B2>
inline internal::Bind2<R, P1, B1, B2>
bind(R (*f)(P1&, B1&, B2&), Placeholder1&, B1& b1, B2& b2)
bind(R (&f)(P1&, B1&, B2&), Placeholder1&, B1& b1, B2& b2)
{
return internal::Bind2<R, P1, B1, B2>(f, b1, b2);
}
template <typename R, typename P1, typename B1, typename B2, typename B3>
inline internal::Bind3<R, P1, const B1, const B2, B3>
bind(R (*f)(P1&, B1, B2, B3&), Placeholder1&, const B1& b1, const B2& b2,
bind(R (&f)(P1&, B1, B2, B3&), Placeholder1&, const B1& b1, const B2& b2,
B3& b3)
{
return internal::Bind3<R, P1, const B1, const B2, B3>(f, b1, b2, b3);
@ -191,17 +197,20 @@ bind(R (*f)(P1&, B1, B2, B3&), Placeholder1&, const B1& b1, const B2& b2,
template <typename R, typename P1, typename B1, typename B2, typename B3,
typename B4>
inline internal::Bind4<R, P1, const B1, const B2, B3, B4>
bind(R (*f)(P1&, B1, B2, B3&, B4&), Placeholder1&, const B1& b1, const B2& b2,
bind(R (&f)(P1&, B1, B2, B3&, B4&), Placeholder1&, const B1& b1, const B2& b2,
B3& b3, B4& b4)
{
return internal::Bind4<R, P1, const B1, const B2, B3, B4>(f, b1, b2, b3, b4);
}
// XXX: C++ doesn't have reference-to-member function, only
// pointer-to-member function, so we can't enforce the non-nullness of f
// using the type system.
template <typename R, typename C1, typename P1, typename P2, typename P3,
typename P4>
inline internal::BindToMemberFunction4<R, C1, P1, P2, P3, P4>
bind(R (C1::*f)(P1&, P2&, P3, P4&), C1* that, Placeholder1&, Placeholder2&,
Placeholder3, Placeholder4&)
bind(R (C1::*f)(P1&, P2&, P3, P4&), C1& that, Placeholder1&,
Placeholder2&, Placeholder3, Placeholder4&)
{
return internal::BindToMemberFunction4<R, C1, P1, P2, P3, P4>(f, that);
}
@ -209,7 +218,7 @@ bind(R (C1::*f)(P1&, P2&, P3, P4&), C1* that, Placeholder1&, Placeholder2&,
template <typename R, typename P1, typename B1, typename B2, typename B3,
typename B4, typename B5>
inline internal::Bind5<R, P1, B1, B2, B3, B4, B5&>
bind(R (*f)(P1&, B1, B2, B3, B4, B5&), Placeholder1&, B1 b1, B2 b2, B3 b3,
bind(R (&f)(P1&, B1, B2, B3, B4, B5&), Placeholder1&, B1 b1, B2 b2, B3 b3,
B4 b4, B5& b5)
{
return internal::Bind5<R, P1, B1, B2, B3, B4, B5&>(f, b1, b2, b3, b4, b5);

View File

@ -141,7 +141,7 @@ BackCert::Init()
}
rv = der::OptionalExtensions(tbsCertificate, CSC | 3,
bind(&BackCert::RememberExtension, this, _1,
bind(&BackCert::RememberExtension, *this, _1,
_2, _3, _4));
if (rv != Success) {
return rv;

View File

@ -22,25 +22,21 @@
* limitations under the License.
*/
#include <map>
#include "cert.h"
#include "nss.h"
#include "pkix/pkix.h"
#include "pkix/pkixnss.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
typedef ScopedPtr<CERTCertificate, CERT_DestroyCertificate>
ScopedCERTCertificate;
typedef ScopedPtr<CERTCertList, CERT_DestroyCertList> ScopedCERTCertList;
static ByteString
CreateCert(const char* issuerCN,
const char* subjectCN,
EndEntityOrCA endEntityOrCA,
/*out*/ ScopedCERTCertificate* subjectCert = nullptr)
/*optional modified*/ std::map<ByteString, ByteString>*
subjectDERToCertDER = nullptr)
{
static long serialNumberValue = 0;
++serialNumberValue;
@ -65,16 +61,11 @@ CreateCert(const char* issuerCN,
*reusedKey, extensions, *reusedKey,
sha256WithRSAEncryption));
EXPECT_FALSE(ENCODING_FAILED(certDER));
if (subjectCert) {
SECItem certDERItem = {
siBuffer,
const_cast<uint8_t*>(certDER.data()),
static_cast<unsigned int>(certDER.length())
};
*subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
&certDERItem, nullptr, false, true);
EXPECT_TRUE(*subjectCert);
if (subjectDERToCertDER) {
(*subjectDERToCertDER)[subjectDER] = certDER;
}
return certDER;
}
@ -90,66 +81,53 @@ public:
"CA1 (Root)", "CA2", "CA3", "CA4", "CA5", "CA6", "CA7"
};
static_assert(MOZILLA_PKIX_ARRAY_LENGTH(names) ==
MOZILLA_PKIX_ARRAY_LENGTH(certChainTail),
"mismatch in sizes of names and certChainTail arrays");
for (size_t i = 0; i < MOZILLA_PKIX_ARRAY_LENGTH(names); ++i) {
const char* issuerName = i == 0 ? names[0] : names[i-1];
(void) CreateCert(issuerName, names[i], EndEntityOrCA::MustBeCA,
&certChainTail[i]);
CreateCACert(issuerName, names[i]);
if (i == 0) {
rootCACertDER = leafCACertDER;
}
}
return true;
}
void CreateCACert(const char* issuerName, const char* subjectName)
{
leafCACertDER = CreateCert(issuerName, subjectName,
EndEntityOrCA::MustBeCA, &subjectDERToCertDER);
assert(!ENCODING_FAILED(leafCACertDER));
}
ByteString GetLeafCACertDER() const { return leafCACertDER; }
private:
virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
Input candidateCert,
/*out*/ TrustLevel& trustLevel)
{
Input rootDER;
Result rv = rootDER.Init(certChainTail[0]->derCert.data,
certChainTail[0]->derCert.len);
EXPECT_EQ(Success, rv);
if (InputsAreEqual(candidateCert, rootDER)) {
trustLevel = TrustLevel::TrustAnchor;
} else {
trustLevel = TrustLevel::InheritsTrust;
}
trustLevel = InputEqualsByteString(candidateCert, rootCACertDER)
? TrustLevel::TrustAnchor
: TrustLevel::InheritsTrust;
return Success;
}
virtual Result FindIssuer(Input encodedIssuerName,
IssuerChecker& checker, Time time)
{
SECItem encodedIssuerNameSECItem =
UnsafeMapInputToSECItem(encodedIssuerName);
ScopedCERTCertList
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
&encodedIssuerNameSECItem, 0,
false));
if (candidates) {
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
bool keepGoing;
Input derCert;
Result rv = derCert.Init(n->cert->derCert.data, n->cert->derCert.len);
EXPECT_EQ(Success, rv);
if (rv != Success) {
return rv;
}
rv = checker.Check(derCert, nullptr/*additionalNameConstraints*/,
keepGoing);
if (rv != Success) {
return rv;
}
if (!keepGoing) {
break;
}
}
ByteString subjectDER(InputToByteString(encodedIssuerName));
ByteString certDER(subjectDERToCertDER[subjectDER]);
Input derCert;
Result rv = derCert.Init(certDER.data(), certDER.length());
if (rv != Success) {
return rv;
}
bool keepGoing;
rv = checker.Check(derCert, nullptr/*additionalNameConstraints*/,
keepGoing);
if (rv != Success) {
return rv;
}
return Success;
}
@ -168,8 +146,7 @@ private:
virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
Input subjectPublicKeyInfo)
{
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
MINIMUM_TEST_KEY_BITS, nullptr);
return TestVerifySignedData(signedData, subjectPublicKeyInfo);
}
virtual Result DigestBuf(Input item, /*out*/ uint8_t *digestBuf,
@ -184,15 +161,9 @@ private:
return TestCheckPublicKey(subjectPublicKeyInfo);
}
// We hold references to CERTCertificates in the cert chain tail so that we
// CERT_CreateSubjectCertList can find them.
ScopedCERTCertificate certChainTail[7];
public:
CERTCertificate* GetLeafCACert() const
{
return certChainTail[MOZILLA_PKIX_ARRAY_LENGTH(certChainTail) - 1].get();
}
std::map<ByteString, ByteString> subjectDERToCertDER;
ByteString leafCACertDER;
ByteString rootCACertDER;
};
class pkixbuild : public ::testing::Test
@ -200,12 +171,6 @@ class pkixbuild : public ::testing::Test
public:
static void SetUpTestCase()
{
// XXX(Bug 1070444): We have to initialize NSS explicitly for these tests,
// unlike other tests, because we're using NSS directly.
if (NSS_NoDB_Init(nullptr) != SECSuccess) {
abort();
}
if (!trustDomain.SetUpCertChainTail()) {
abort();
}
@ -221,9 +186,9 @@ protected:
TEST_F(pkixbuild, MaxAcceptableCertChainLength)
{
{
ByteString leafCACert(trustDomain.GetLeafCACertDER());
Input certDER;
ASSERT_EQ(Success, certDER.Init(trustDomain.GetLeafCACert()->derCert.data,
trustDomain.GetLeafCACert()->derCert.len));
ASSERT_EQ(Success, certDER.Init(leafCACert.data(), leafCACert.length()));
ASSERT_EQ(Success,
BuildCertChain(trustDomain, certDER, Now(),
EndEntityOrCA::MustBeCA,
@ -234,7 +199,6 @@ TEST_F(pkixbuild, MaxAcceptableCertChainLength)
}
{
ScopedCERTCertificate cert;
ByteString certDER(CreateCert("CA7", "Direct End-Entity",
EndEntityOrCA::MustBeEndEntity));
ASSERT_FALSE(ENCODING_FAILED(certDER));
@ -254,14 +218,10 @@ TEST_F(pkixbuild, BeyondMaxAcceptableCertChainLength)
{
static char const* const caCertName = "CA Too Far";
// We need a CERTCertificate for caCert so that the trustdomain's FindIssuer
// method can find it through the NSS cert DB.
ScopedCERTCertificate caCert;
trustDomain.CreateCACert("CA7", caCertName);
{
ByteString certDER(CreateCert("CA7", caCertName, EndEntityOrCA::MustBeCA,
&caCert));
ASSERT_FALSE(ENCODING_FAILED(certDER));
ByteString certDER(trustDomain.GetLeafCACertDER());
Input certDERInput;
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
@ -351,8 +311,7 @@ public:
virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
Input subjectPublicKeyInfo)
{
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
MINIMUM_TEST_KEY_BITS, nullptr);
return TestVerifySignedData(signedData, subjectPublicKeyInfo);
}
virtual Result DigestBuf(Input, /*out*/uint8_t*, size_t)

View File

@ -4,7 +4,6 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
#include "pkix/pkix.h"
#include "pkix/pkixnss.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
@ -110,8 +109,7 @@ private:
Input subjectPublicKeyInfo)
{
EXPECT_NE(SignatureAlgorithm::unsupported_algorithm, signedData.algorithm);
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
MINIMUM_TEST_KEY_BITS, nullptr);
return TestVerifySignedData(signedData, subjectPublicKeyInfo);
}
virtual Result DigestBuf(Input, uint8_t*, size_t)

View File

@ -83,6 +83,20 @@ InputEqualsByteString(Input input, const ByteString& bs)
return InputsAreEqual(input, bsInput);
}
ByteString
InputToByteString(Input input)
{
ByteString result;
Reader reader(input);
for (;;) {
uint8_t b;
if (reader.Read(b) != Success) {
return result;
}
result.push_back(b);
}
}
Result
TamperOnce(/*in/out*/ ByteString& item, const ByteString& from,
const ByteString& to)

View File

@ -67,6 +67,7 @@ public:
};
bool InputEqualsByteString(Input input, const ByteString& bs);
ByteString InputToByteString(Input input);
// python DottedOIDToCode.py --tlv id-kp-OCSPSigning 1.3.6.1.5.5.7.3.9
static const uint8_t tlv_id_kp_OCSPSigning[] = {

View File

@ -338,10 +338,12 @@ function AbstractHealthReporter(branch, policy, sessionRecorder) {
this._initHistogram = hasFirstRun ? TELEMETRY_INIT : TELEMETRY_INIT_FIRSTRUN;
this._dbOpenHistogram = hasFirstRun ? TELEMETRY_DB_OPEN : TELEMETRY_DB_OPEN_FIRSTRUN;
// This is set to the name for the provider that we are currently initializing
// or shutting down, if any. This is used for AsyncShutdownTimeout diagnostics.
// This is set to the name for the provider that we are currently initializing,
// shutting down or collecting data from, if any.
// This is used for AsyncShutdownTimeout diagnostics.
this._currentProviderInShutdown = null;
this._currentProviderInInit = null;
this._currentProviderInCollect = null;
}
AbstractHealthReporter.prototype = Object.freeze({
@ -415,6 +417,7 @@ AbstractHealthReporter.prototype = Object.freeze({
shutdownComplete: this._shutdownComplete,
currentProviderInShutdown: this._currentProviderInShutdown,
currentProviderInInit: this._currentProviderInInit,
currentProviderInCollect: this._currentProviderInCollect,
}));
try {
@ -793,7 +796,8 @@ AbstractHealthReporter.prototype = Object.freeze({
try {
TelemetryStopwatch.start(TELEMETRY_COLLECT_CONSTANT, this);
yield this._providerManager.collectConstantData();
yield this._providerManager.collectConstantData(name => this._currentProviderInCollect = name);
this._currentProviderInCollect = null;
TelemetryStopwatch.finish(TELEMETRY_COLLECT_CONSTANT, this);
} catch (ex) {
TelemetryStopwatch.cancel(TELEMETRY_COLLECT_CONSTANT, this);
@ -813,7 +817,8 @@ AbstractHealthReporter.prototype = Object.freeze({
try {
TelemetryStopwatch.start(TELEMETRY_COLLECT_DAILY, this);
this._lastDailyDate = new Date();
yield this._providerManager.collectDailyData();
yield this._providerManager.collectDailyData(name => this._currentProviderInCollect = name);
this._currentProviderInCollect = null;
TelemetryStopwatch.finish(TELEMETRY_COLLECT_DAILY, this);
} catch (ex) {
TelemetryStopwatch.cancel(TELEMETRY_COLLECT_DAILY, this);

View File

@ -436,8 +436,11 @@ this.ProviderManager.prototype = Object.freeze({
* provided their constant data. A side-effect of this promise fulfillment
* is that the manager is populated with the obtained collection results.
* The resolved value to the promise is this `ProviderManager` instance.
*
* @param providerDiagnostic
* (function) Optional, called with the name of the provider currently being initialized.
*/
collectConstantData: function () {
collectConstantData: function (providerDiagnostic=null) {
let entries = [];
for (let [name, entry] of this._providers) {
@ -455,18 +458,20 @@ this.ProviderManager.prototype = Object.freeze({
};
return this._callCollectOnProviders(entries, "collectConstantData",
onCollect);
onCollect, providerDiagnostic);
},
/**
* Calls collectDailyData on all providers.
*/
collectDailyData: function () {
collectDailyData: function (providerDiagnostic=null) {
return this._callCollectOnProviders(this._providers.values(),
"collectDailyData");
"collectDailyData",
null,
providerDiagnostic);
},
_callCollectOnProviders: function (entries, fnProperty, onCollect=null) {
_callCollectOnProviders: function (entries, fnProperty, onCollect=null, providerDiagnostic=null) {
let promises = [];
for (let entry of entries) {
@ -502,7 +507,7 @@ this.ProviderManager.prototype = Object.freeze({
promises.push([provider.name, promise]);
}
return this._handleCollectionPromises(promises);
return this._handleCollectionPromises(promises, providerDiagnostic);
},
/**
@ -514,9 +519,13 @@ this.ProviderManager.prototype = Object.freeze({
* The promise is resolved even if one of the underlying collection
* promises is rejected.
*/
_handleCollectionPromises: function (promises) {
_handleCollectionPromises: function (promises, providerDiagnostic=null) {
return Task.spawn(function waitForPromises() {
for (let [name, promise] of promises) {
if (providerDiagnostic) {
providerDiagnostic(name);
}
try {
yield promise;
this._log.debug("Provider collected successfully: " + name);

View File

@ -9,6 +9,7 @@ config = {
"--symbols-path=%(symbols_path)s",
"--xre-path=%(abs_app_dir)s"
],
"mac_res_subdir": "MacOS",
"run_filename": "runcppunittests.py",
"testsdir": "cppunittests"
},
@ -20,6 +21,7 @@ config = {
"--tinderbox",
"--tbpl"
],
"mac_res_subdir": "MacOS",
"run_filename": "jit_test.py",
"testsdir": "jit-test/jit-test"
},
@ -36,6 +38,7 @@ config = {
"--quiet",
"--log-raw=%(raw_log_file)s"
],
"mac_res_subdir": "MacOS",
"run_filename": "runtests.py",
"testsdir": "mochitest"
},
@ -44,6 +47,7 @@ config = {
"-b",
"%(binary_path)s"
],
"mac_res_subdir": "MacOS",
"run_filename": "test.py",
"testsdir": "mozbase"
},
@ -54,6 +58,7 @@ config = {
"--extra-profile-file=tests/bin/plugins",
"--symbols-path=%(symbols_path)s"
],
"mac_res_subdir": "MacOS",
"run_filename": "runreftest.py",
"testsdir": "reftest"
},
@ -70,6 +75,7 @@ config = {
"--testing-modules-dir=tests/modules",
"--quiet"
],
"mac_res_subdir": "MacOS",
"run_filename": "runtests.py",
"testsdir": "mochitest"
},
@ -79,8 +85,9 @@ config = {
"--test-plugin-path=%(test_plugin_path)s",
"--log-raw=%(raw_log_file)s"
],
"mac_res_subdir": "MacOS",
"run_filename": "runxpcshelltests.py",
"testsdir": "xpcshell"
}
}
}
}

View File

@ -6,6 +6,7 @@ let outOfProcess = __marionetteParams[0]
let mochitestUrl = __marionetteParams[1]
let onDevice = __marionetteParams[2]
let wifiSettings = __marionetteParams[3]
let chrome = __marionetteParams[4]
let prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch)
let settings = window.navigator.mozSettings;
@ -86,6 +87,11 @@ if (outOfProcess) {
mm.loadFrameScript("data:,(" + encodeURI(contentScript.toSource()) + ")();", true);
}
if (chrome) {
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://mochikit/content/browser-test.js");
b2gStart();
}
if (onDevice) {
var cpuLock = Cc["@mozilla.org/power/powermanagerservice;1"]
@ -133,5 +139,7 @@ if (onDevice) {
};
}
} else {
container.src = mochitestUrl;
if (!chrome) {
container.src = mochitestUrl;
}
}

View File

@ -5,7 +5,11 @@ var gConfig;
if (Cc === undefined) {
var Cc = Components.classes;
}
if (Ci === undefined) {
var Ci = Components.interfaces;
}
if (Cu === undefined) {
var Cu = Components.utils;
}
@ -32,6 +36,15 @@ window.addEventListener("load", function testOnLoad() {
});
});
function b2gStart() {
let homescreen = document.getElementById('systemapp');
var webNav = homescreen.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation);
var url = "chrome://mochikit/content/harness.xul?manifestFile=tests.json";
webNav.loadURI(url, null, null, null, null);
}
function testInit() {
gConfig = readConfig();
if (gConfig.testRoot == "browser" ||

Some files were not shown because too many files have changed in this diff Show More