Merge m-i to m-c

This commit is contained in:
Phil Ringnalda 2014-05-03 17:35:09 -07:00
commit be1c8eb709
53 changed files with 829 additions and 609 deletions

View File

@ -85,7 +85,6 @@
// CSS related includes
#include "nsCSSRules.h"
#include "nsIDOMCSSRule.h"
#include "nsICSSRuleList.h"
#include "nsAutoPtr.h"
#include "nsMemory.h"
@ -312,8 +311,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSNameSpaceRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSRuleList, nsCSSRuleListSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSStyleSheet, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -928,10 +925,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRule)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CSSRuleList, nsIDOMCSSRuleList)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRuleList)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CSSStyleSheet, nsIDOMCSSStyleSheet)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleSheet)
DOM_CLASSINFO_MAP_END
@ -3500,168 +3493,6 @@ nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
target->PreserveWrapper(aNative);
}
// Generic array scriptable helper.
NS_IMETHODIMP
nsGenericArraySH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *aObj, jsid aId, JSObject **objp,
bool *_retval)
{
JS::Rooted<JSObject*> obj(cx, aObj);
JS::Rooted<jsid> id(cx, aId);
if (id == sLength_id) {
// Bail early; this isn't something we're interested in
return NS_OK;
}
bool is_number = false;
int32_t n = GetArrayIndexFromId(cx, id, &is_number);
if (is_number && n >= 0) {
// XXX The following is a cheap optimization to avoid hitting xpconnect to
// get the length. We may want to consider asking our concrete
// implementation for the length, and falling back onto the GetProperty if
// it doesn't provide one.
uint32_t length;
nsresult rv = GetLength(wrapper, cx, obj, &length);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t index = uint32_t(n);
if (index < length) {
*_retval = ::JS_DefineElement(cx, obj, index, JS::UndefinedHandleValue,
JSPROP_ENUMERATE | JSPROP_SHARED);
*objp = obj;
}
}
return NS_OK;
}
nsresult
nsGenericArraySH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JS::Handle<JSObject*> obj, uint32_t *length)
{
*length = 0;
JS::Rooted<JS::Value> lenval(cx);
if (!JS_GetProperty(cx, obj, "length", &lenval)) {
return NS_ERROR_UNEXPECTED;
}
if (!lenval.isInt32()) {
// This can apparently happen with some sparse array impls falling back
// onto this code.
return NS_OK;
}
int32_t slen = lenval.toInt32();
if (slen < 0) {
return NS_OK;
}
*length = (uint32_t)slen;
return NS_OK;
}
NS_IMETHODIMP
nsGenericArraySH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *aObj, bool *_retval)
{
// Recursion protection in case someone tries to be smart and call
// the enumerate hook from a user defined .length getter, or
// somesuch.
JS::Rooted<JSObject*> obj(cx, aObj);
static bool sCurrentlyEnumerating;
if (sCurrentlyEnumerating) {
// Don't recurse to death.
return NS_OK;
}
sCurrentlyEnumerating = true;
JS::Rooted<JS::Value> len_val(cx);
bool ok = ::JS_GetProperty(cx, obj, "length", &len_val);
if (ok && len_val.isInt32()) {
int32_t length = len_val.toInt32();
for (int32_t i = 0; ok && i < length; ++i) {
ok = ::JS_DefineElement(cx, obj, i, JS::UndefinedHandleValue,
JSPROP_ENUMERATE | JSPROP_SHARED);
}
}
sCurrentlyEnumerating = false;
return ok ? NS_OK : NS_ERROR_UNEXPECTED;
}
// Array scriptable helper
NS_IMETHODIMP
nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *aObj, jsid aId, jsval *vp, bool *_retval)
{
JS::Rooted<JSObject*> obj(cx, aObj);
JS::Rooted<jsid> id(cx, aId);
bool is_number = false;
int32_t n = GetArrayIndexFromId(cx, id, &is_number);
nsresult rv = NS_OK;
if (is_number) {
if (n < 0) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Make sure rv == NS_OK here, so GetItemAt implementations that never fail
// don't have to set rv.
rv = NS_OK;
nsWrapperCache *cache = nullptr;
nsISupports* array_item =
GetItemAt(GetNative(wrapper, obj), n, &cache, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (array_item) {
JS::Rooted<JS::Value> rval(cx);
rv = WrapNative(cx, array_item, cache, true, &rval);
NS_ENSURE_SUCCESS(rv, rv);
*vp = rval;
rv = NS_SUCCESS_I_DID_SOMETHING;
}
}
return rv;
}
// CSSRuleList scriptable helper
nsISupports*
nsCSSRuleListSH::GetItemAt(nsISupports *aNative, uint32_t aIndex,
nsWrapperCache **aCache, nsresult *aResult)
{
nsICSSRuleList* list = static_cast<nsICSSRuleList*>(aNative);
#ifdef DEBUG
{
nsCOMPtr<nsICSSRuleList> list_qi = do_QueryInterface(aNative);
// If this assertion fires the QI implementation for the object in
// question doesn't use the nsICSSRuleList pointer as the nsISupports
// pointer. That must be fixed, or we'll crash...
NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
}
#endif
return list->Item(aIndex);
}
// Storage2SH
// One reason we need a newResolve hook is that in order for

View File

@ -310,87 +310,6 @@ public:
};
// Generic array scriptable helper
class nsGenericArraySH : public nsDOMClassInfo
{
protected:
nsGenericArraySH(nsDOMClassInfoData* aData) : nsDOMClassInfo(aData)
{
}
virtual ~nsGenericArraySH()
{
}
public:
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, JSObject **objp,
bool *_retval) MOZ_OVERRIDE;
NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, bool *_retval) MOZ_OVERRIDE;
virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JS::Handle<JSObject*> obj, uint32_t *length);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsGenericArraySH(aData);
}
};
// Array scriptable helper
class nsArraySH : public nsGenericArraySH
{
protected:
nsArraySH(nsDOMClassInfoData* aData) : nsGenericArraySH(aData)
{
}
virtual ~nsArraySH()
{
}
// Subclasses need to override this, if the implementation can't fail it's
// allowed to not set *aResult.
virtual nsISupports* GetItemAt(nsISupports *aNative, uint32_t aIndex,
nsWrapperCache **aCache, nsresult *aResult) = 0;
public:
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE;
private:
// Not implemented, nothing should create an instance of this class.
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData);
};
// CSSRuleList helper
class nsCSSRuleListSH : public nsArraySH
{
protected:
nsCSSRuleListSH(nsDOMClassInfoData* aData) : nsArraySH(aData)
{
}
virtual ~nsCSSRuleListSH()
{
}
virtual nsISupports* GetItemAt(nsISupports *aNative, uint32_t aIndex,
nsWrapperCache **aCache, nsresult *aResult) MOZ_OVERRIDE;
public:
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsCSSRuleListSH(aData);
}
};
// WebApps Storage helpers
class nsStorage2SH : public nsDOMGenericSH

View File

@ -15,7 +15,6 @@ DOMCI_CLASS(CSSCharsetRule)
DOMCI_CLASS(CSSImportRule)
DOMCI_CLASS(CSSMediaRule)
DOMCI_CLASS(CSSNameSpaceRule)
DOMCI_CLASS(CSSRuleList)
DOMCI_CLASS(CSSStyleSheet)
// XUL classes

View File

@ -262,6 +262,10 @@ DOMInterfaces = {
'resultNotAddRefed': ['getRGBColorValue', 'getRectValue']
},
'CSSRuleList': {
'nativeType': 'nsICSSRuleList',
},
'CSSStyleDeclaration': {
'nativeType': 'nsICSSDeclaration'
},
@ -1890,7 +1894,6 @@ addExternalIface('ApplicationCache', nativeType='nsIDOMOfflineResourceList')
addExternalIface('Counter')
addExternalIface('CSSRule')
addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h')
addExternalIface('CSSRuleList')
addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
addExternalIface('File')
addExternalIface('HitRegionOptions', nativeType='nsISupports')

View File

@ -2966,6 +2966,9 @@ class CGWrapGlobalMethod(CGAbstractMethod):
aOptions,
aPrincipal);
// obj is a new global, so has a new compartment. Enter it
// before doing anything with it.
JSAutoCompartment ac(aCx, obj);
$*{unforgeable}
$*{slots}

View File

@ -0,0 +1,10 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
interface CSSRuleList {
readonly attribute unsigned long length;
getter CSSRule? item(unsigned long index);
};

View File

@ -7,7 +7,6 @@
* http://dev.w3.org/csswg/cssom/
*/
interface CSSRuleList;
interface CSSRule;
interface CSSStyleSheet : StyleSheet {

View File

@ -63,6 +63,7 @@ WEBIDL_FILES = [
'Coordinates.webidl',
'CSS.webidl',
'CSSPrimitiveValue.webidl',
'CSSRuleList.webidl',
'CSSStyleDeclaration.webidl',
'CSSStyleSheet.webidl',
'CSSValue.webidl',

View File

@ -1873,7 +1873,7 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
" TLOPTIONS=disableMainThread"),
JS_FN_HELP("stopTraceLogger", DisableTraceLogger, 0, 0,
"startTraceLogger()",
"stopTraceLogger()",
" Stop logging the mainThread."),
JS_FS_HELP_END
};

View File

@ -199,6 +199,12 @@ sub get_manager_address
return $1;
}
sub logging_suffix {
my ($show_logs, $log_file) = @_;
return $show_logs ? "2>&1 | tee $log_file"
: "> $log_file 2>&1";
}
sub run_build
{
print "build started: ";
@ -214,7 +220,8 @@ sub run_build
if (!$pid) {
# this is the child process, fork another process to run a manager.
defined(my $pid = fork) or die;
exec("$xmanager -terminate-on-assert > $manager_log_file 2>&1") if (!$pid);
my $logging = logging_suffix($suppress_logs, $manager_log_file);
exec("$xmanager -terminate-on-assert $logging") if (!$pid);
$kill_on_exit{$pid} = 1;
if (!$suppress_logs) {
@ -286,7 +293,8 @@ sub run_pass
# fork off a manager process for the analysis.
defined(my $pid = fork) or die;
exec("$xmanager $manager_extra > $log_file 2>&1") if (!$pid);
my $logging = logging_suffix($suppress_logs, $log_file);
exec("$xmanager $manager_extra $logging") if (!$pid);
my $address = get_manager_address($log_file);

View File

@ -508,32 +508,80 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand &value,
const LDefinition *scratch1, const LDefinition *scratch2,
FloatRegister fr,
Label *ifTruthy, Label *ifFalsy,
OutOfLineTestObject *ool)
OutOfLineTestObject *ool,
MDefinition *valueMIR)
{
// Count the number of possible type tags we might have, so we'll know when
// we've checked them all and hence can avoid emitting a tag check for the
// last one. In particular, whenever tagCount is 1 that means we've tried
// all but one of them already so we know exactly what's left based on the
// mightBe* booleans.
bool mightBeUndefined = valueMIR->mightBeType(MIRType_Undefined);
bool mightBeNull = valueMIR->mightBeType(MIRType_Null);
bool mightBeBoolean = valueMIR->mightBeType(MIRType_Boolean);
bool mightBeInt32 = valueMIR->mightBeType(MIRType_Int32);
bool mightBeObject = valueMIR->mightBeType(MIRType_Object);
bool mightBeString = valueMIR->mightBeType(MIRType_String);
bool mightBeDouble = valueMIR->mightBeType(MIRType_Double);
int tagCount = int(mightBeUndefined) + int(mightBeNull) +
int(mightBeBoolean) + int(mightBeInt32) + int(mightBeObject) +
int(mightBeString) + int(mightBeDouble);
MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0);
// If we know we're null or undefined, we're definitely falsy, no
// need to even check the tag.
if (int(mightBeNull) + int(mightBeUndefined) == tagCount) {
masm.jump(ifFalsy);
return;
}
Register tag = masm.splitTagForTest(value);
// Eventually we will want some sort of type filter here. For now, just
// emit all easy cases. For speed we use the cached tag for all comparison,
// except for doubles, which we test last (as the operation can clobber the
// tag, which may be in ScratchReg).
if (mightBeUndefined) {
MOZ_ASSERT(tagCount > 1);
masm.branchTestUndefined(Assembler::Equal, tag, ifFalsy);
masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
--tagCount;
}
if (mightBeNull) {
MOZ_ASSERT(tagCount > 1);
masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
--tagCount;
}
if (mightBeBoolean) {
MOZ_ASSERT(tagCount != 0);
Label notBoolean;
if (tagCount != 1)
masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
masm.branchTestBooleanTruthy(false, value, ifFalsy);
if (tagCount != 1)
masm.jump(ifTruthy);
// Else just fall through to truthiness.
masm.bind(&notBoolean);
--tagCount;
}
if (mightBeInt32) {
MOZ_ASSERT(tagCount != 0);
Label notInt32;
if (tagCount != 1)
masm.branchTestInt32(Assembler::NotEqual, tag, &notInt32);
masm.branchTestInt32Truthy(false, value, ifFalsy);
if (tagCount != 1)
masm.jump(ifTruthy);
// Else just fall through to truthiness.
masm.bind(&notInt32);
--tagCount;
}
if (mightBeObject) {
MOZ_ASSERT(tagCount != 0);
if (ool) {
Label notObject;
if (tagCount != 1)
masm.branchTestObject(Assembler::NotEqual, tag, &notObject);
Register objreg = masm.extractObject(value, ToRegister(scratch1));
@ -541,19 +589,41 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand &value,
masm.bind(&notObject);
} else {
if (tagCount != 1)
masm.branchTestObject(Assembler::Equal, tag, ifTruthy);
// Else just fall through to truthiness.
}
--tagCount;
} else {
MOZ_ASSERT(!ool,
"We better not have an unused OOL path, since the code generator will try to "
"generate code for it but we never set up its labels, which will cause null "
"derefs of those labels.");
}
if (mightBeString) {
// Test if a string is non-empty.
MOZ_ASSERT(tagCount != 0);
Label notString;
if (tagCount != 1)
masm.branchTestString(Assembler::NotEqual, tag, &notString);
masm.branchTestStringTruthy(false, value, ifFalsy);
if (tagCount != 1)
masm.jump(ifTruthy);
// Else just fall through to truthiness.
masm.bind(&notString);
--tagCount;
}
if (mightBeDouble) {
MOZ_ASSERT(tagCount == 1);
// If we reach here the value is a double.
masm.unboxDouble(value, fr);
masm.branchTestDoubleTruthy(false, fr, ifFalsy);
--tagCount;
}
MOZ_ASSERT(tagCount == 0);
// Fall through for truthy.
}
@ -563,9 +633,10 @@ CodeGenerator::testValueTruthy(const ValueOperand &value,
const LDefinition *scratch1, const LDefinition *scratch2,
FloatRegister fr,
Label *ifTruthy, Label *ifFalsy,
OutOfLineTestObject *ool)
OutOfLineTestObject *ool,
MDefinition *valueMIR)
{
testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool);
testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool, valueMIR);
masm.jump(ifTruthy);
}
@ -612,7 +683,12 @@ bool
CodeGenerator::visitTestVAndBranch(LTestVAndBranch *lir)
{
OutOfLineTestObject *ool = nullptr;
if (lir->mir()->operandMightEmulateUndefined()) {
MDefinition* input = lir->mir()->input();
// Unfortunately, it's possible that someone (e.g. phi elimination) switched
// out our input after we did cacheOperandMightEmulateUndefined. So we
// might think it can emulate undefined _and_ know that it can't be an
// object.
if (lir->mir()->operandMightEmulateUndefined() && input->mightBeType(MIRType_Object)) {
ool = new(alloc()) OutOfLineTestObject();
if (!addOutOfLineCode(ool))
return false;
@ -624,7 +700,7 @@ CodeGenerator::visitTestVAndBranch(LTestVAndBranch *lir)
testValueTruthy(ToValue(lir, LTestVAndBranch::Input),
lir->temp1(), lir->temp2(),
ToFloatRegister(lir->tempFloat()),
truthy, falsy, ool);
truthy, falsy, ool, input);
return true;
}
@ -5291,6 +5367,7 @@ CodeGenerator::visitNotV(LNotV *lir)
OutOfLineTestObjectWithLabels *ool = nullptr;
if (lir->mir()->operandMightEmulateUndefined()) {
MOZ_ASSERT(lir->mir()->operand()->mightBeType(MIRType_Object));
ool = new(alloc()) OutOfLineTestObjectWithLabels();
if (!addOutOfLineCode(ool))
return false;
@ -5305,7 +5382,7 @@ CodeGenerator::visitNotV(LNotV *lir)
testValueTruthyKernel(ToValue(lir, LNotV::Input), lir->temp1(), lir->temp2(),
ToFloatRegister(lir->tempFloat()),
ifTruthy, ifFalsy, ool);
ifTruthy, ifFalsy, ool, lir->mir()->operand());
Label join;
Register output = ToRegister(lir->output());

View File

@ -389,7 +389,8 @@ class CodeGenerator : public CodeGeneratorSpecific
const LDefinition *scratch1, const LDefinition *scratch2,
FloatRegister fr,
Label *ifTruthy, Label *ifFalsy,
OutOfLineTestObject *ool);
OutOfLineTestObject *ool,
MDefinition *valueMIR);
// Test whether value is truthy or not and jump to the corresponding label.
// If the value can be an object that emulates |undefined|, |ool| must be
@ -400,7 +401,8 @@ class CodeGenerator : public CodeGeneratorSpecific
const LDefinition *scratch1, const LDefinition *scratch2,
FloatRegister fr,
Label *ifTruthy, Label *ifFalsy,
OutOfLineTestObject *ool);
OutOfLineTestObject *ool,
MDefinition *valueMIR);
// This function behaves like testObjectEmulatesUndefined with the exception
// that it can choose to let control flow fall through when the object

View File

@ -2168,7 +2168,7 @@ IonBuilder::processDoWhileCondEnd(CFGState &state)
}
// Create the test instruction and end the current block.
MTest *test = MTest::New(alloc(), vins, state.loop.entry, successor);
MTest *test = newTest(vins, state.loop.entry, successor);
current->end(test);
return finishLoop(state, successor);
}
@ -2189,9 +2189,9 @@ IonBuilder::processWhileCondEnd(CFGState &state)
MTest *test;
if (JSOp(*pc) == JSOP_IFNE)
test = MTest::New(alloc(), ins, body, state.loop.successor);
test = newTest(ins, body, state.loop.successor);
else
test = MTest::New(alloc(), ins, state.loop.successor, body);
test = newTest(ins, state.loop.successor, body);
current->end(test);
state.state = CFGState::WHILE_LOOP_BODY;
@ -2229,7 +2229,7 @@ IonBuilder::processForCondEnd(CFGState &state)
if (!body || !state.loop.successor)
return ControlStatus_Error;
MTest *test = MTest::New(alloc(), ins, body, state.loop.successor);
MTest *test = newTest(ins, body, state.loop.successor);
current->end(test);
state.state = CFGState::FOR_LOOP_BODY;
@ -3352,7 +3352,7 @@ IonBuilder::processCondSwitchCase(CFGState &state)
cmpResult->infer(inspector, pc);
JS_ASSERT(!cmpResult->isEffectful());
current->add(cmpResult);
current->end(MTest::New(alloc(), cmpResult, bodyBlock, caseBlock));
current->end(newTest(cmpResult, bodyBlock, caseBlock));
// Add last case as predecessor of the body if the body is aliasing
// the previous case body.
@ -3463,9 +3463,8 @@ IonBuilder::jsop_andor(JSOp op)
return false;
MTest *test = (op == JSOP_AND)
? MTest::New(alloc(), lhs, evalRhs, join)
: MTest::New(alloc(), lhs, join, evalRhs);
test->infer();
? newTest(lhs, evalRhs, join)
: newTest(lhs, join, evalRhs);
current->end(test);
if (!cfgStack_.append(CFGState::AndOr(joinStart, join)))
@ -3516,7 +3515,7 @@ IonBuilder::jsop_ifeq(JSOp op)
if (!ifTrue || !ifFalse)
return false;
MTest *test = MTest::New(alloc(), ins, ifTrue, ifFalse);
MTest *test = newTest(ins, ifTrue, ifFalse);
current->end(test);
// The bytecode for if/ternary gets emitted either like this:
@ -3645,7 +3644,7 @@ IonBuilder::jsop_try()
// Add MTest(true, tryBlock, successorBlock).
MConstant *true_ = MConstant::New(alloc(), BooleanValue(true));
current->add(true_);
current->end(MTest::New(alloc(), true_, tryBlock, successor));
current->end(newTest(true_, tryBlock, successor));
} else {
successor = nullptr;
current->end(MGoto::New(alloc(), tryBlock));
@ -4180,10 +4179,6 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo)
types::TypeObjectKey *targetType = types::TypeObjectKey::get(target);
targetType->watchStateChangeForInlinedCall(constraints());
// We mustn't relazify functions that have been inlined, because there's
// no way to tell if it safe to do so.
script()->setHasBeenInlined();
return InliningDecision_Inline;
}
@ -6005,6 +6000,14 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
return block;
}
MTest *
IonBuilder::newTest(MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse)
{
MTest *test = MTest::New(alloc(), ins, ifTrue, ifFalse);
test->cacheOperandMightEmulateUndefined();
return test;
}
// A resume point is a mapping of stack slots to MDefinitions. It is used to
// capture the environment such that if a guard fails, and IonMonkey needs
// to exit back to the interpreter, the interpreter state can be
@ -8284,7 +8287,7 @@ IonBuilder::jsop_not()
MNot *ins = MNot::New(alloc(), value);
current->add(ins);
current->push(ins);
ins->infer();
ins->cacheOperandMightEmulateUndefined();
return true;
}
@ -9772,7 +9775,7 @@ IonBuilder::jsop_typeof()
MDefinition *input = current->pop();
MTypeOf *ins = MTypeOf::New(alloc(), input, input->type());
ins->infer();
ins->cacheInputMaybeCallableOrEmulatesUndefined();
current->add(ins);
current->push(ins);

View File

@ -289,6 +289,14 @@ class IonBuilder : public MIRGenerator
return newBlockAfter(at, nullptr, pc);
}
// We want to make sure that our MTest instructions all check whether the
// thing being tested might emulate undefined. So we funnel their creation
// through this method, to make sure that happens. We don't want to just do
// the check in MTest::New, because that can run on background compilation
// threads, and we're not sure it's safe to touch that part of the typeset
// from a background thread.
MTest *newTest(MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
// Given a list of pending breaks, creates a new block and inserts a Goto
// linking each break to the new block.
MBasicBlock *createBreakCatchBlock(DeferredEdge *edge, jsbytecode *pc);

View File

@ -278,6 +278,10 @@ class JitRuntime
return ionAlloc_;
}
bool hasIonAlloc() const {
return !!ionAlloc_;
}
bool ionCodeProtected() {
return ionCodeProtected_;
}

View File

@ -1637,10 +1637,10 @@ IonBuilder::inlineHasClasses(CallInfo &callInfo, const Class *clasp1, const Clas
current->add(either);
// Convert to bool with the '!!' idiom
MNot *resultInverted = MNot::New(alloc(), either);
resultInverted->infer();
resultInverted->cacheOperandMightEmulateUndefined();
current->add(resultInverted);
MNot *result = MNot::New(alloc(), resultInverted);
result->infer();
result->cacheOperandMightEmulateUndefined();
current->add(result);
current->push(result);
}

View File

@ -230,7 +230,7 @@ MTest::New(TempAllocator &alloc, MDefinition *ins, MBasicBlock *ifTrue, MBasicBl
}
void
MTest::infer()
MTest::cacheOperandMightEmulateUndefined()
{
JS_ASSERT(operandMightEmulateUndefined());
@ -2174,7 +2174,7 @@ MTypeOf::foldsTo(TempAllocator &alloc, bool useValueNumbers)
}
void
MTypeOf::infer()
MTypeOf::cacheInputMaybeCallableOrEmulatesUndefined()
{
JS_ASSERT(inputMaybeCallableOrEmulatesUndefined());
@ -2669,7 +2669,7 @@ MCompare::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *f
}
void
MNot::infer()
MNot::cacheOperandMightEmulateUndefined()
{
JS_ASSERT(operandMightEmulateUndefined());

View File

@ -1304,7 +1304,13 @@ class MTest
AliasSet getAliasSet() const {
return AliasSet::None();
}
void infer();
// We cache whether our operand might emulate undefined, but we don't want
// to do that from New() or the constructor, since those can be called on
// background threads. So make callers explicitly call it if they want us
// to check whether the operand might do this. If this method is never
// called, we'll assume our operand can emulate undefined.
void cacheOperandMightEmulateUndefined();
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
void filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
bool *filtersNull);
@ -3272,7 +3278,7 @@ class MTypeOf
}
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
void infer();
void cacheInputMaybeCallableOrEmulatesUndefined();
bool inputMaybeCallableOrEmulatesUndefined() const {
return inputMaybeCallableOrEmulatesUndefined_;
@ -5839,7 +5845,7 @@ class MNot
INSTRUCTION_HEADER(Not);
void infer();
void cacheOperandMightEmulateUndefined();
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
void markOperandCantEmulateUndefined() {

View File

@ -576,7 +576,6 @@ JSFunction::trace(JSTracer *trc)
// - they are not in the self-hosting compartment
// - they aren't generators
// - they don't have JIT code attached
// - they haven't ever been inlined
// - they don't have child functions
// - they have information for un-lazifying them again later
// This information can either be a LazyScript, or the name of a

View File

@ -4043,6 +4043,12 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
/* Clear out any small pools that we're hanging on to. */
if (JSC::ExecutableAllocator *execAlloc = rt->maybeExecAlloc())
execAlloc->purge();
#ifdef JS_ION
if (rt->jitRuntime() && rt->jitRuntime()->hasIonAlloc()) {
JSRuntime::AutoLockForInterrupt lock(rt);
rt->jitRuntime()->ionAlloc(rt)->purge();
}
#endif
/*
* This removes compartments from rt->compartment, so we do it last to make

View File

@ -834,9 +834,6 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
// Script has been reused for a clone.
bool hasBeenCloned_:1;
// Script has been inlined at least once, and can't be relazified.
bool hasBeenInlined_:1;
// Script came from eval(), and is still active.
bool isActiveEval_:1;
@ -1026,12 +1023,10 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
}
bool hasRunOnce() const { return hasRunOnce_; }
bool hasBeenCloned() const { return hasBeenCloned_; }
bool hasBeenInlined() const { return hasBeenInlined_; }
void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
void setHasRunOnce() { hasRunOnce_ = true; }
void setHasBeenCloned() { hasBeenCloned_ = true; }
void setHasBeenInlined() { hasBeenInlined_ = true; }
bool isActiveEval() const { return isActiveEval_; }
bool isCachedEval() const { return isCachedEval_; }
@ -1252,7 +1247,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
bool isRelazifiable() const {
return (selfHosted() || lazyScript) &&
!isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !hasBeenInlined();
!isGenerator() && !hasBaselineScript() && !hasAnyIonScript();
}
void setLazyScript(js::LazyScript *lazy) {
lazyScript = lazy;

View File

@ -68,14 +68,26 @@ extern int gettimeofday(struct timeval *tv);
#if defined(XP_WIN)
static const int64_t win2un = 0x19DB1DED53E8000;
// Returns the number of microseconds since the Unix epoch.
static double
FileTimeToUnixMicroseconds(const FILETIME &ft)
{
// Get the time in 100ns intervals.
int64_t t = (int64_t(ft.dwHighDateTime) << 32) | int64_t(ft.dwLowDateTime);
#define FILETIME2INT64(ft) (((int64_t)ft.dwHighDateTime) << 32LL | (int64_t)ft.dwLowDateTime)
// The Windows epoch is around 1600. The Unix epoch is around 1970.
// Subtract the difference.
static const int64_t TimeToEpochIn100ns = 0x19DB1DED53E8000;
t -= TimeToEpochIn100ns;
typedef struct CalibrationData {
long double freq; /* The performance counter frequency */
long double offset; /* The low res 'epoch' */
long double timer_offset; /* The high res 'epoch' */
// Divide by 10 to convert to microseconds.
return double(t) * 0.1;
}
struct CalibrationData {
double freq; /* The performance counter frequency */
double offset; /* The low res 'epoch' */
double timer_offset; /* The high res 'epoch' */
/* The last high res time that we returned since recalibrating */
int64_t last;
@ -86,51 +98,38 @@ typedef struct CalibrationData {
CRITICAL_SECTION data_lock;
CRITICAL_SECTION calibration_lock;
#endif
} CalibrationData;
};
static CalibrationData calibration = { 0 };
static void
NowCalibrate()
{
FILETIME ft, ftStart;
LARGE_INTEGER liFreq, now;
if (calibration.freq == 0.0) {
LARGE_INTEGER liFreq;
if (!QueryPerformanceFrequency(&liFreq)) {
/* High-performance timer is unavailable */
// High-performance timer is unavailable.
calibration.freq = -1.0;
} else {
calibration.freq = (long double) liFreq.QuadPart;
return;
}
calibration.freq = double(liFreq.QuadPart);
}
if (calibration.freq > 0.0) {
int64_t calibrationDelta = 0;
/* By wrapping a timeBegin/EndPeriod pair of calls around this loop,
the loop seems to take much less time (1 ms vs 15ms) on Vista. */
// By wrapping a timeBegin/EndPeriod pair of calls around this loop,
// the loop seems to take much less time (1 ms vs 15ms) on Vista.
timeBeginPeriod(1);
FILETIME ft, ftStart;
GetSystemTimeAsFileTime(&ftStart);
do {
GetSystemTimeAsFileTime(&ft);
} while (memcmp(&ftStart,&ft, sizeof(ft)) == 0);
timeEndPeriod(1);
/*
calibrationDelta = (FILETIME2INT64(ft) - FILETIME2INT64(ftStart))/10;
fprintf(stderr, "Calibration delta was %I64d us\n", calibrationDelta);
*/
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
calibration.offset = (long double) FILETIME2INT64(ft);
calibration.timer_offset = (long double) now.QuadPart;
/* The windows epoch is around 1600. The unix epoch is around
1970. win2un is the difference (in windows time units which
are 10 times more highres than the JS time unit) */
calibration.offset -= win2un;
calibration.offset *= 0.1;
calibration.offset = FileTimeToUnixMicroseconds(ft);
calibration.timer_offset = double(now.QuadPart);
calibration.last = 0;
calibration.calibrated = true;
@ -180,7 +179,7 @@ static PRCallOnceType calibrationOnce = { 0 };
#if defined(XP_UNIX)
int64_t
PRMJ_Now(void)
PRMJ_Now()
{
struct timeval tv;
@ -258,16 +257,12 @@ def PRMJ_Now():
*/
int64_t
PRMJ_Now(void)
PRMJ_Now()
{
static int nCalls = 0;
long double lowresTime, highresTimerValue;
FILETIME ft;
LARGE_INTEGER now;
bool calibrated = false;
bool needsCalibration = false;
int64_t returnedTime;
long double cachedOffset = 0.0;
double cachedOffset = 0.0;
/* For non threadsafe platforms, NowInit is not necessary */
#ifdef JS_THREADSAFE
@ -278,17 +273,17 @@ PRMJ_Now(void)
MUTEX_LOCK(&calibration.calibration_lock);
MUTEX_LOCK(&calibration.data_lock);
/* Recalibrate only if no one else did before us */
// Recalibrate only if no one else did before us.
if (calibration.offset == cachedOffset) {
/* Since calibration can take a while, make any other
threads immediately wait */
// Since calibration can take a while, make any other
// threads immediately wait.
MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
NowCalibrate();
calibrated = true;
/* Restore spin count */
// Restore spin count.
MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT);
}
MUTEX_UNLOCK(&calibration.data_lock);
@ -296,34 +291,32 @@ PRMJ_Now(void)
}
/* Calculate a low resolution time */
// Calculate a low resolution time.
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
lowresTime = 0.1*(long double)(FILETIME2INT64(ft) - win2un);
double lowresTime = FileTimeToUnixMicroseconds(ft);
if (calibration.freq > 0.0) {
long double highresTime, diff;
DWORD timeAdjustment, timeIncrement;
BOOL timeAdjustmentDisabled;
/* Default to 15.625 ms if the syscall fails */
long double skewThreshold = 15625.25;
/* Grab high resolution time */
// Grab high resolution time.
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
highresTimerValue = (long double)now.QuadPart;
double highresTimerValue = double(now.QuadPart);
MUTEX_LOCK(&calibration.data_lock);
highresTime = calibration.offset + PRMJ_USEC_PER_SEC*
double highresTime = calibration.offset + PRMJ_USEC_PER_SEC *
(highresTimerValue-calibration.timer_offset)/calibration.freq;
cachedOffset = calibration.offset;
/* On some dual processor/core systems, we might get an earlier time
so we cache the last time that we returned */
// On some dual processor/core systems, we might get an earlier time
// so we cache the last time that we returned.
calibration.last = js::Max(calibration.last, int64_t(highresTime));
returnedTime = calibration.last;
MUTEX_UNLOCK(&calibration.data_lock);
/* Rather than assume the NT kernel ticks every 15.6ms, ask it */
// Rather than assume the NT kernel ticks every 15.6ms, ask it.
double skewThreshold;
DWORD timeAdjustment, timeIncrement;
BOOL timeAdjustmentDisabled;
if (GetSystemTimeAdjustment(&timeAdjustment,
&timeIncrement,
&timeAdjustmentDisabled)) {
@ -334,50 +327,49 @@ PRMJ_Now(void)
/* timeIncrement is in units of 100ns */
skewThreshold = timeIncrement/10.0;
}
} else {
// Default to 15.625 ms if the syscall fails.
skewThreshold = 15625.25;
}
/* Check for clock skew */
diff = lowresTime - highresTime;
// Check for clock skew.
double diff = lowresTime - highresTime;
/* For some reason that I have not determined, the skew can be
up to twice a kernel tick. This does not seem to happen by
itself, but I have only seen it triggered by another program
doing some kind of file I/O. The symptoms are a negative diff
followed by an equally large positive diff. */
if (mozilla::Abs(diff) > 2 * skewThreshold) {
/*fprintf(stderr,"Clock skew detected (diff = %f)!\n", diff);*/
// For some reason that I have not determined, the skew can be
// up to twice a kernel tick. This does not seem to happen by
// itself, but I have only seen it triggered by another program
// doing some kind of file I/O. The symptoms are a negative diff
// followed by an equally large positive diff.
if (mozilla::Abs(diff) <= 2 * skewThreshold) {
// No detectable clock skew.
return int64_t(highresTime);
}
if (calibrated) {
/* If we already calibrated once this instance, and the
clock is still skewed, then either the processor(s) are
wildly changing clockspeed or the system is so busy that
we get switched out for long periods of time. In either
case, it would be infeasible to make use of high
resolution results for anything, so let's resort to old
behavior for this call. It's possible that in the
future, the user will want the high resolution timer, so
we don't disable it entirely. */
returnedTime = int64_t(lowresTime);
needsCalibration = false;
} else {
/* It is possible that when we recalibrate, we will return a
value less than what we have returned before; this is
unavoidable. We cannot tell the different between a
faulty QueryPerformanceCounter implementation and user
changes to the operating system time. Since we must
respect user changes to the operating system time, we
cannot maintain the invariant that Date.now() never
decreases; the old implementation has this behavior as
well. */
// If we already calibrated once this instance, and the
// clock is still skewed, then either the processor(s) are
// wildly changing clockspeed or the system is so busy that
// we get switched out for long periods of time. In either
// case, it would be infeasible to make use of high
// resolution results for anything, so let's resort to old
// behavior for this call. It's possible that in the
// future, the user will want the high resolution timer, so
// we don't disable it entirely.
return int64_t(lowresTime);
}
// It is possible that when we recalibrate, we will return a
// value less than what we have returned before; this is
// unavoidable. We cannot tell the different between a
// faulty QueryPerformanceCounter implementation and user
// changes to the operating system time. Since we must
// respect user changes to the operating system time, we
// cannot maintain the invariant that Date.now() never
// decreases; the old implementation has this behavior as
// well.
needsCalibration = true;
}
} else {
/* No detectable clock skew */
returnedTime = int64_t(highresTime);
needsCalibration = false;
}
} else {
/* No high resolution timer is available, so fall back */
// No high resolution timer is available, so fall back.
returnedTime = int64_t(lowresTime);
}
} while (needsCalibration);

View File

@ -32,7 +32,7 @@ struct PRMJTime {
/* Return the current local time in micro-seconds */
extern int64_t
PRMJ_Now(void);
PRMJ_Now();
/* Release the resources associated with PRMJ_Now; don't call PRMJ_Now again */
#if defined(JS_THREADSAFE) && defined(XP_WIN)

View File

@ -8,6 +8,9 @@
#include "mozilla/DebugOnly.h"
#if defined XP_MACOSX
#include <libkern/OSByteOrder.h>
#endif
#include <string.h>
#include "jsapi.h"
@ -26,6 +29,14 @@ using namespace js;
# endif
#endif
#if defined XP_MACOSX
#define htobe32(x) OSSwapHostToBigInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#endif
#if defined(__i386__)
static __inline__ uint64_t
rdtsc(void)
@ -379,11 +390,11 @@ TraceLogger::createTextId(JSScript *script)
int written;
if (textId > 0) {
written = fprintf(dictFile, ",\n\"script %s:%d:%d\"", script->filename(),
script->lineno(), script->column());
written = fprintf(dictFile, ",\n\"script %s:%u:%u\"", script->filename(),
(unsigned)script->lineno(), (unsigned)script->column());
} else {
written = fprintf(dictFile, "\"script %s:%d:%d\"", script->filename(),
script->lineno(), script->column());
written = fprintf(dictFile, "\"script %s:%u:%u\"", script->filename(),
(unsigned)script->lineno(), (unsigned)script->column());
}
if (written < 0)

View File

@ -2448,8 +2448,8 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint)
NS_ASSERTION(aSelf->GetContent(),
"non pseudo-element frame without content node");
// Skip flex-item style fixup for anonymous subtrees:
TreeMatchContext::AutoFlexItemStyleFixupSkipper
flexFixupSkipper(mTreeMatchContext,
TreeMatchContext::AutoFlexOrGridItemStyleFixupSkipper
flexOrGridFixupSkipper(mTreeMatchContext,
element->IsRootOfNativeAnonymousSubtree());
newContext = styleSet->ResolveStyleFor(element, parentContext,
mTreeMatchContext);

View File

@ -302,14 +302,38 @@ static int32_t FFWC_recursions=0;
static int32_t FFWC_nextInFlows=0;
#endif
// Returns true if aFrame is an anonymous flex item
// Returns true if aFrame is an anonymous flex/grid item.
static inline bool
IsAnonymousFlexItem(const nsIFrame* aFrame)
IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
{
const nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
return pseudoType == nsCSSAnonBoxes::anonymousFlexItem;
return pseudoType == nsCSSAnonBoxes::anonymousFlexItem ||
pseudoType == nsCSSAnonBoxes::anonymousGridItem;
}
#if DEBUG
static void
AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
const nsIFrame* aParent)
{
MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
"expected an anonymous flex or grid item child frame");
MOZ_ASSERT(aParent, "expected a parent frame");
const nsIAtom* pseudoType = aChild->StyleContext()->GetPseudo();
if (pseudoType == nsCSSAnonBoxes::anonymousFlexItem) {
MOZ_ASSERT(aParent->GetType() == nsGkAtoms::flexContainerFrame,
"anonymous flex items should only exist as children "
"of flex container frames");
} else {
MOZ_ASSERT(aParent->GetType() == nsGkAtoms::gridContainerFrame,
"anonymous grid items should only exist as children "
"of grid container frames");
}
}
#else
#define AssertAnonymousFlexOrGridItemParent(x, y) do { /* nothing */ } while(0)
#endif
static inline nsIFrame*
GetFieldSetBlockFrame(nsIFrame* aFieldsetFrame)
{
@ -3857,8 +3881,8 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
FrameConstructionItemList items;
{
// Skip flex item style-fixup during our AddFrameConstructionItems() call:
TreeMatchContext::AutoFlexItemStyleFixupSkipper
flexItemStyleFixupSkipper(aState.mTreeMatchContext);
TreeMatchContext::AutoFlexOrGridItemStyleFixupSkipper
flexOrGridItemStyleFixupSkipper(aState.mTreeMatchContext);
AddFrameConstructionItems(aState, content, true, aParentFrame, items);
}
@ -8541,10 +8565,8 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
// we're only interested in anonymous flex items here, and those can never
// be adjacent to whitespace, since they absorb contiguous runs of inline
// non-replaced content (including whitespace).
if (nextSibling && IsAnonymousFlexItem(nextSibling)) {
NS_ABORT_IF_FALSE(parent->GetType() == nsGkAtoms::flexContainerFrame,
"anonymous flex items should only exist as children "
"of flex container frames");
if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
AssertAnonymousFlexOrGridItemParent(nextSibling, parent);
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
@ -8561,11 +8583,8 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
// Might need to reconstruct things if the removed frame's nextSibling is
// null and its parent is an anonymous flex item. (This might be the last
// remaining child of that anonymous flex item, which can then go away.)
if (!nextSibling && IsAnonymousFlexItem(parent)) {
NS_ABORT_IF_FALSE(parent->GetParent() &&
parent->GetParent()->GetType() == nsGkAtoms::flexContainerFrame,
"anonymous flex items should only exist as children "
"of flex container frames");
if (!nextSibling && IsAnonymousFlexOrGridItem(parent)) {
AssertAnonymousFlexOrGridItemParent(parent, parent->GetParent());
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
@ -8875,20 +8894,24 @@ nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = {
};
void
nsCSSFrameConstructor::CreateNeededAnonFlexItems(
nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
nsFrameConstructorState& aState,
FrameConstructionItemList& aItems,
nsIFrame* aParentFrame)
{
if (aItems.IsEmpty() ||
aParentFrame->GetType() != nsGkAtoms::flexContainerFrame) {
if (aItems.IsEmpty()) {
return;
}
nsIAtom* containerType = aParentFrame->GetType();
if (containerType != nsGkAtoms::flexContainerFrame &&
containerType != nsGkAtoms::gridContainerFrame) {
return;
}
FCItemIterator iter(aItems);
do {
// Advance iter past children that don't want to be wrapped
if (iter.SkipItemsThatDontNeedAnonFlexItem(aState)) {
if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState)) {
// Hit the end of the items without finding any remaining children that
// need to be wrapped. We're finished!
return;
@ -8897,22 +8920,22 @@ nsCSSFrameConstructor::CreateNeededAnonFlexItems(
// If our next potentially-wrappable child is whitespace, then see if
// there's anything wrappable immediately after it. If not, we just drop
// the whitespace and move on. (We're not supposed to create any anonymous
// flex items that _only_ contain whitespace).
// flex/grid items that _only_ contain whitespace).
// (BUT if this is generated content, then we don't give whitespace nodes
// any special treatment, because they're probably not really whitespace --
// they're just temporarily empty, waiting for their generated text.)
// XXXdholbert If this node's generated text will *actually end up being
// entirely whitespace*, then we technically should still skip over it, per
// the flexbox spec. I'm not bothering with that at this point, since it's
// a pretty extreme edge case.
// the CSS grid & flexbox specs. I'm not bothering with that at this point,
// since it's a pretty extreme edge case.
if (!aParentFrame->IsGeneratedContentFrame() &&
iter.item().IsWhitespace(aState)) {
FCItemIterator afterWhitespaceIter(iter);
bool hitEnd = afterWhitespaceIter.SkipWhitespace(aState);
bool nextChildNeedsAnonFlexItem =
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexItem(aState);
bool nextChildNeedsAnonItem =
!hitEnd && afterWhitespaceIter.item().NeedsAnonFlexOrGridItem(aState);
if (!nextChildNeedsAnonFlexItem) {
if (!nextChildNeedsAnonItem) {
// There's nothing after the whitespace that we need to wrap, so we
// just drop this run of whitespace.
iter.DeleteItemsTo(afterWhitespaceIter);
@ -8924,24 +8947,25 @@ nsCSSFrameConstructor::CreateNeededAnonFlexItems(
// we jump back to the beginning of the loop to skip over that child
// (and anything else non-wrappable after it)
NS_ABORT_IF_FALSE(!iter.IsDone() &&
!iter.item().NeedsAnonFlexItem(aState),
"hitEnd and/or nextChildNeedsAnonFlexItem lied");
!iter.item().NeedsAnonFlexOrGridItem(aState),
"hitEnd and/or nextChildNeedsAnonItem lied");
continue;
}
}
// Now |iter| points to the first child that needs to be wrapped in an
// anonymous flex item. Now we see how many children after it also want
// to be wrapped in an anonymous flex item.
// anonymous flex/grid item. Now we see how many children after it also want
// to be wrapped in an anonymous flex/grid item.
FCItemIterator endIter(iter); // iterator to find the end of the group
endIter.SkipItemsThatNeedAnonFlexItem(aState);
endIter.SkipItemsThatNeedAnonFlexOrGridItem(aState);
NS_ASSERTION(iter != endIter,
"Should've had at least one wrappable child to seek past");
// Now, we create the anonymous flex item to contain the children
// Now, we create the anonymous flex or grid item to contain the children
// between |iter| and |endIter|.
nsIAtom* pseudoType = nsCSSAnonBoxes::anonymousFlexItem;
nsIAtom* pseudoType = containerType == nsGkAtoms::flexContainerFrame ?
nsCSSAnonBoxes::anonymousFlexItem : nsCSSAnonBoxes::anonymousGridItem;
nsStyleContext* parentStyle = aParentFrame->StyleContext();
nsIContent* parentContent = aParentFrame->GetContent();
already_AddRefed<nsStyleContext> wrapperStyle =
@ -8968,11 +8992,11 @@ nsCSSFrameConstructor::CreateNeededAnonFlexItems(
newItem->mIsBlock = !newItem->mIsAllInline;
NS_ABORT_IF_FALSE(!newItem->mIsAllInline && newItem->mIsBlock,
"expecting anonymous flex items to be block-level "
"expecting anonymous flex/grid items to be block-level "
"(this will make a difference when we encounter "
"'flex-align: baseline')");
"'align-items: baseline')");
// Anonymous flex items induce line boundaries around their
// Anonymous flex and grid items induce line boundaries around their
// contents.
newItem->mChildItems.SetLineBoundaryAtStart(true);
newItem->mChildItems.SetLineBoundaryAtEnd(true);
@ -9205,7 +9229,7 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta
nsFrameItems& aFrameItems)
{
CreateNeededTablePseudos(aState, aItems, aParentFrame);
CreateNeededAnonFlexItems(aState, aItems, aParentFrame);
CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
aItems.SetTriedConstructingFrames();
for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
@ -9249,8 +9273,8 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
"Why is someone creating garbage anonymous content");
nsRefPtr<nsStyleContext> styleContext;
TreeMatchContext::AutoFlexItemStyleFixupSkipper
flexItemStyleFixupSkipper(aState.mTreeMatchContext);
TreeMatchContext::AutoFlexOrGridItemStyleFixupSkipper
flexOrGridItemStyleFixupSkipper(aState.mTreeMatchContext);
if (aAnonymousItems[i].mStyleContext) {
styleContext = aAnonymousItems[i].mStyleContext.forget();
} else {
@ -10785,56 +10809,53 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
FCItemIterator iter(aItems);
// Check if we're adding to-be-wrapped content right *after* an existing
// anonymous flex item (which would need to absorb this content).
if (aPrevSibling && IsAnonymousFlexItem(aPrevSibling) &&
iter.item().NeedsAnonFlexItem(aState)) {
// anonymous flex or grid item (which would need to absorb this content).
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
iter.item().NeedsAnonFlexOrGridItem(aState)) {
RecreateFramesForContent(aFrame->GetContent(), true);
return true;
}
// Check if we're adding to-be-wrapped content right *before* an existing
// anonymous flex item (which would need to absorb this content).
if (nextSibling && IsAnonymousFlexItem(nextSibling)) {
// anonymous flex or grid item (which would need to absorb this content).
if (nextSibling && IsAnonymousFlexOrGridItem(nextSibling)) {
// Jump to the last entry in the list
iter.SetToEnd();
iter.Prev();
if (iter.item().NeedsAnonFlexItem(aState)) {
if (iter.item().NeedsAnonFlexOrGridItem(aState)) {
RecreateFramesForContent(aFrame->GetContent(), true);
return true;
}
}
}
// Situation #3 is an anonymous flex item that's getting new children who
// don't want to be wrapped.
if (IsAnonymousFlexItem(aFrame)) {
nsIFrame* flexContainerFrame = aFrame->GetParent();
NS_ABORT_IF_FALSE(flexContainerFrame &&
flexContainerFrame->GetType() == nsGkAtoms::flexContainerFrame,
"anonymous flex items should only exist as children "
"of flex container frames");
// Situation #3 is an anonymous flex or grid item that's getting new children
// who don't want to be wrapped.
if (IsAnonymousFlexOrGridItem(aFrame)) {
AssertAnonymousFlexOrGridItemParent(aFrame, aFrame->GetParent());
// We need to push a null float containing block to be sure that
// "NeedsAnonFlexItem" will know we're not honoring floats for this
// "NeedsAnonFlexOrGridItem" will know we're not honoring floats for this
// inserted content. (In particular, this is necessary in order for
// NeedsAnonFlexItem's "GetGeometricParent" call to return the correct
// result.) We're not honoring floats on this content because it has the
// _flex container_ as its parent in the content tree.
// its "GetGeometricParent" call to return the correct result.)
// We're not honoring floats on this content because it has the
// _flex/grid container_ as its parent in the content tree.
nsFrameConstructorSaveState floatSaveState;
aState.PushFloatContainingBlock(nullptr, floatSaveState);
FCItemIterator iter(aItems);
// Skip over things that _do_ need an anonymous flex item, because
// they're perfectly happy to go here -- they won't cause a reframe.
if (!iter.SkipItemsThatNeedAnonFlexItem(aState)) {
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState)) {
// We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out.
RecreateFramesForContent(flexContainerFrame->GetContent(), true);
nsIFrame* containerFrame = aFrame->GetParent();
RecreateFramesForContent(containerFrame->GetContent(), true);
return true;
}
// If we get here, then everything in |aItems| needs to be wrapped in
// an anonymous flex item. That's where it's already going - good!
// an anonymous flex or grid item. That's where it's already going - good!
}
// Situation #4 is a case when table pseudo-frames don't work out right
@ -11239,7 +11260,7 @@ Iterator::SkipItemsWantingParentType(ParentType aParentType)
bool
nsCSSFrameConstructor::FrameConstructionItem::
NeedsAnonFlexItem(const nsFrameConstructorState& aState)
NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState)
{
if (mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) {
// This will be an inline non-replaced box.
@ -11260,11 +11281,11 @@ nsCSSFrameConstructor::FrameConstructionItem::
inline bool
nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatNeedAnonFlexItem(
Iterator::SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState)
{
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (item().NeedsAnonFlexItem(aState)) {
while (item().NeedsAnonFlexOrGridItem(aState)) {
Next();
if (IsDone()) {
return true;
@ -11275,11 +11296,11 @@ Iterator::SkipItemsThatNeedAnonFlexItem(
inline bool
nsCSSFrameConstructor::FrameConstructionItemList::
Iterator::SkipItemsThatDontNeedAnonFlexItem(
Iterator::SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState)
{
NS_PRECONDITION(!IsDone(), "Shouldn't be done yet");
while (!(item().NeedsAnonFlexItem(aState))) {
while (!(item().NeedsAnonFlexOrGridItem(aState))) {
Next();
if (IsDone()) {
return true;

View File

@ -791,13 +791,13 @@ private:
// Skip over non-replaced inline frames and positioned frames.
// Return whether the iterator is done after doing that.
// The iterator must not be done when this is called.
inline bool SkipItemsThatNeedAnonFlexItem(
inline bool SkipItemsThatNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState);
// Skip to the first frame that is a non-replaced inline or is
// positioned. Return whether the iterator is done after doing that.
// The iterator must not be done when this is called.
inline bool SkipItemsThatDontNeedAnonFlexItem(
inline bool SkipItemsThatDontNeedAnonFlexOrGridItem(
const nsFrameConstructorState& aState);
// Skip over whitespace. Return whether the iterator is done after doing
@ -928,9 +928,9 @@ private:
return FCDATA_DESIRED_PARENT_TYPE(mFCData->mBits);
}
// Indicates whether (when in a flexbox container) this item needs to be
// wrapped in an anonymous block.
bool NeedsAnonFlexItem(const nsFrameConstructorState& aState);
// Indicates whether (when in a flex or grid container) this item needs
// to be wrapped in an anonymous block.
bool NeedsAnonFlexOrGridItem(const nsFrameConstructorState& aState);
// Don't call this unless the frametree really depends on the answer!
// Especially so for generated content, where we don't want to reframe
@ -1020,12 +1020,13 @@ private:
};
/**
* Function to create the anonymous flex items that we need.
* If aParentFrame is not a nsFlexContainerFrame then this method is a NOP.
* Function to create the anonymous flex or grid items that we need.
* If aParentFrame is not a nsFlexContainerFrame or nsGridContainerFrame then
* this method is a NOP.
* @param aItems the child frame construction items before pseudo creation
* @param aParentFrame the parent frame
*/
void CreateNeededAnonFlexItems(nsFrameConstructorState& aState,
void CreateNeededAnonFlexOrGridItems(nsFrameConstructorState& aState,
FrameConstructionItemList& aItems,
nsIFrame* aParentFrame);

View File

@ -560,10 +560,6 @@ nsDocumentViewer::LoadStart(nsIDocument* aDocument)
if (!mDocument) {
mDocument = aDocument;
} else if (mDocument == aDocument) {
// Reset the document viewer's state back to what it was
// when the document load started.
PrepareToStartLoad();
}
}

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!--
Reference case, with inline-blocks instead of grid/grid items,
with positioning done using margins.
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<style>
div { height: 100px; }
div.grid {
border: 1px dashed blue;
width: 200px;
}
div.a {
width: 30px;
background: lightgreen;
display: inline-block;
}
div.b {
width: 20px;
background: lightblue;
display: inline-block;
}
img {
width: 40px;
height: 100%;
}
</style>
</head>
<body>
<div class="grid">
<div class="a" style="margin-left: 85px"/>
</div>
<div class="grid">
<div class="a" style="margin-left: 37.5px"
/><div class="b" style="margin-left: 75px"/>
</div>
<div class="grid">
<img src="solidblue.png" style="margin-left: 30px"
/><img src="solidblue.png" style="margin-left: 60px"/>
</div>
</body>
</html>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!--
This test verifies that we don't create anonymous grid items around
runs of inline content that are _purely_ whitespace.
The test uses "white-space: pre", to try to tempt us into honoring
that whitespace. (but we should resist that temptation).
The test also uses 'justify-content: space-around' to be sure we can
tell whether anonymous grid items are being created around the whitespace
(since they'd claim a share of the packing space if they were there).
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Test that anonymous grid items aren't created for pure-whitespace inline content</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<link rel="help" href="http://www.w3.org/TR/css3-grid/#grid-items"/>
<link rel="match" href="grid-whitespace-handling-1-ref.xhtml"/>
<style>
div { height: 100px; }
div.grid {
white-space: pre;
border: 1px dashed blue;
width: 200px;
display: grid;
justify-content: space-around;
}
div.a {
width: 30px;
background: lightgreen;
}
div.b {
width: 20px;
background: lightblue;
}
img { width: 40px; }
</style>
</head>
<body>
<!-- whitespace & tab after grid item -->
<div class="grid"><div class="a"/> </div>
<!-- 2 spaces before grid item -->
<div class="grid"> <div class="a"/><div class="b"/></div>
<!-- newline & whitespace between grid items -->
<div class="grid"><img src="solidblue.png"/>
<img src="solidblue.png"/></div>
</body>
</html>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!--
This test is like the -1a variant, but with the whitespace removed between
grid items (since that whitespace should be ignored anyway, if we're
doing things right).
-->
<!-- XXXdholbert Does this testcase add value?
(Maybe it should be an alternate reference case.) -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Test that grid items are created correctly</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<link rel="help" href="http://www.w3.org/TR/css3-grid/#grid-items"/>
<link rel="match" href="grid-whitespace-handling-1-ref.xhtml"/>
<style>
div { height: 100px; }
div.grid {
border: 1px dashed blue;
width: 200px;
display: grid;
justify-content: space-around;
}
div.a {
width: 30px;
background: lightgreen;
}
div.b {
width: 20px;
background: lightblue;
}
img { width: 40px; }
</style>
</head>
<body>
<div class="grid"><div class="a"/></div>
<div class="grid"><div class="a"/><div class="b"/></div>
<div class="grid"
><img src="solidblue.png"
/><img src="solidblue.png"/></div>
</body>
</html>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!--
This reference case is the same as the testcase, but with an explicit <div>
around each run of content that we expect to turn into an anonymous
grid item (to ensure that the whitespace is included).
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<link rel="stylesheet" type="text/css" href="support/ahem.css" />
<style>
div { height: 100px; }
div.grid {
white-space: pre;
border: 1px dashed blue;
width: 200px;
display: grid;
justify-content: space-around;
}
div.a {
width: 30px;
background: lightgreen;
}
div.b {
width: 20px;
background: lightblue;
}
</style>
</head>
<body>
<!-- spaces around inline content at the beginning of grid -->
<div class="grid"><div> abc</div><div class="a"/></div>
<div class="grid"><div>abc </div><div class="a"/></div>
<div class="grid"><div> abc </div><div class="a"/></div>
<!-- spaces around inline content at the end of grid -->
<div class="grid"><div class="a"/><div> abc</div></div>
<div class="grid"><div class="a"/><div>abc </div></div>
<div class="grid"><div class="a"/><div> abc </div></div>
<!-- whitespace around inline content in between grid items -->
<div class="grid"><div class="a"/><div> abc</div><div class="b"/></div>
<div class="grid"><div class="a"/><div>abc </div><div class="b"/></div>
<div class="grid"><div class="a"/><div> abc </div><div class="b"/></div>
</body>
</html>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!--
This test verifies that we preserve whitespace at the beginning & end of
anonymous grid items (using "white-space: pre" so that it actually
occupies space and affects the rendering).
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Test that whitespace is preserved at the edges of anonymous grid items if 'white-space: pre' is set</title>
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
<link rel="help" href="http://www.w3.org/TR/css3-grid/#grid-items"/>
<link rel="match" href="grid-whitespace-handling-2-ref.xhtml"/>
<link rel="stylesheet" type="text/css" href="support/ahem.css" />
<style>
div { height: 100px; }
div.grid {
white-space: pre;
border: 1px dashed blue;
width: 200px;
display: grid;
justify-content: space-around;
}
div.a {
width: 30px;
background: lightgreen;
}
div.b {
width: 20px;
background: lightblue;
}
</style>
</head>
<body>
<!-- spaces around inline content at the beginning of grid -->
<div class="grid"> abc<div class="a"/></div>
<div class="grid">abc <div class="a"/></div>
<div class="grid"> abc <div class="a"/></div>
<!-- spaces around inline content at the end of grid -->
<div class="grid"><div class="a"/> abc</div>
<div class="grid"><div class="a"/>abc </div>
<div class="grid"><div class="a"/> abc </div>
<!-- whitespace around inline content in between grid items -->
<div class="grid"><div class="a"/> abc<div class="b"/></div>
<div class="grid"><div class="a"/>abc <div class="b"/></div>
<div class="grid"><div class="a"/> abc <div class="b"/></div>
</body>
</html>

View File

@ -0,0 +1,7 @@
default-preferences pref(layout.css.grid.enabled,true)
# TODO these are only for detecting assertions/crashes for now since
# grid layout is not implemented yet
fails == grid-whitespace-handling-1a.xhtml grid-whitespace-handling-1-ref.xhtml
fails == grid-whitespace-handling-1b.xhtml grid-whitespace-handling-1-ref.xhtml
== grid-whitespace-handling-2.xhtml grid-whitespace-handling-2-ref.xhtml

View File

@ -0,0 +1,4 @@
@font-face {
font-family: "Ahem";
src: url(../../fonts/Ahem.ttf);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

View File

@ -155,6 +155,9 @@ include first-line/reftest.list
# flexbox (display: flex, display: inline-flex)
include flexbox/reftest.list
# CSS Grid (display: grid, display: inline-grid)
include css-grid/reftest.list
# floats/
include floats/reftest.list

View File

@ -112,6 +112,7 @@ UNIFIED_SOURCES += [
'nsDOMCSSValueList.cpp',
'nsHTMLCSSStyleSheet.cpp',
'nsHTMLStyleSheet.cpp',
'nsICSSRuleList.cpp',
'nsLayoutStylesheetCache.cpp',
'nsMediaFeatures.cpp',
'nsNthIndexCache.cpp',

View File

@ -62,10 +62,14 @@ CSS_ANON_BOX(columnContent, ":-moz-column-content")
CSS_ANON_BOX(viewport, ":-moz-viewport")
CSS_ANON_BOX(viewportScroll, ":-moz-viewport-scroll")
// Inside a flex container, a contiguous run of non-replaced inline children
// gets wrapped in an anonymous block, which is then treated as a flex item.
// Inside a flex container, a contiguous run of text gets wrapped in
// an anonymous block, which is then treated as a flex item.
CSS_ANON_BOX(anonymousFlexItem, ":-moz-anonymous-flex-item")
// Inside a grid container, a contiguous run of text gets wrapped in
// an anonymous block, which is then treated as a grid item.
CSS_ANON_BOX(anonymousGridItem, ":-moz-anonymous-grid-item")
#ifdef MOZ_XUL
CSS_ANON_BOX(moztreecolumn, ":-moz-tree-column")
CSS_ANON_BOX(moztreerow, ":-moz-tree-row")

View File

@ -7487,8 +7487,11 @@ CSSParserImpl::ParseGridTemplateAreasLine(const nsAutoString& aInput,
nsCSSGridTemplateAreaToken token;
css::GridNamedArea* currentArea = nullptr;
uint32_t row = aAreas->NRows();
uint32_t column;
for (column = 1; scanner.Next(token); column++) {
// Column numbers starts at 1, but we might not have any, eg
// grid-template-areas:""; which will result in mNColumns == 0.
uint32_t column = 0;
while (scanner.Next(token)) {
++column;
if (token.isTrash) {
return false;
}
@ -7540,7 +7543,7 @@ CSSParserImpl::ParseGridTemplateAreasLine(const nsAutoString& aInput,
}
}
}
if (currentArea && currentArea->mColumnEnd != column) {
if (currentArea && currentArea->mColumnEnd != column + 1) {
NS_ASSERTION(currentArea->mRowStart != row,
"Inconsistent column end for the first row of a named area.");
// Not a rectangle

View File

@ -135,7 +135,7 @@ class GroupRuleRuleList MOZ_FINAL : public nsICSSRuleList
public:
GroupRuleRuleList(GroupRule *aGroupRule);
NS_DECL_ISUPPORTS
virtual nsCSSStyleSheet* GetParentObject() MOZ_OVERRIDE;
virtual nsIDOMCSSRule*
IndexedGetter(uint32_t aIndex, bool& aFound) MOZ_OVERRIDE;
@ -162,17 +162,15 @@ GroupRuleRuleList::~GroupRuleRuleList()
{
}
// QueryInterface implementation for GroupRuleRuleList
NS_INTERFACE_MAP_BEGIN(GroupRuleRuleList)
NS_INTERFACE_MAP_ENTRY(nsICSSRuleList)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSRuleList)
NS_INTERFACE_MAP_END
nsCSSStyleSheet*
GroupRuleRuleList::GetParentObject()
{
if (!mGroupRule) {
return nullptr;
}
NS_IMPL_ADDREF(GroupRuleRuleList)
NS_IMPL_RELEASE(GroupRuleRuleList)
return mGroupRule->GetStyleSheet();
}
uint32_t
GroupRuleRuleList::Length()

View File

@ -55,7 +55,7 @@ class CSSRuleListImpl : public nsICSSRuleList
public:
CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet);
NS_DECL_ISUPPORTS
virtual nsCSSStyleSheet* GetParentObject() MOZ_OVERRIDE;
virtual nsIDOMCSSRule*
IndexedGetter(uint32_t aIndex, bool& aFound) MOZ_OVERRIDE;
@ -81,20 +81,11 @@ CSSRuleListImpl::~CSSRuleListImpl()
{
}
DOMCI_DATA(CSSRuleList, CSSRuleListImpl)
// QueryInterface implementation for CSSRuleList
NS_INTERFACE_MAP_BEGIN(CSSRuleListImpl)
NS_INTERFACE_MAP_ENTRY(nsICSSRuleList)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSRuleList)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(CSSRuleListImpl)
NS_IMPL_RELEASE(CSSRuleListImpl)
nsCSSStyleSheet*
CSSRuleListImpl::GetParentObject()
{
return mStyleSheet;
}
uint32_t
CSSRuleListImpl::Length()
@ -1790,7 +1781,7 @@ nsCSSStyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules)
return rv.ErrorCode();
}
nsIDOMCSSRuleList*
nsICSSRuleList*
nsCSSStyleSheet::GetCssRules(ErrorResult& aRv)
{
// No doing this on incomplete sheets!

View File

@ -96,6 +96,7 @@ private:
//
class CSSRuleListImpl;
class nsICSSRuleList;
// CID for the nsCSSStyleSheet class
// ca926f30-2a7e-477e-8467-803fb32af20a
@ -275,7 +276,7 @@ public:
// called GetOwnerRule because that would be ambiguous with the ImportRule
// version.
nsIDOMCSSRule* GetDOMOwnerRule() const;
nsIDOMCSSRuleList* GetCssRules(mozilla::ErrorResult& aRv);
nsICSSRuleList* GetCssRules(mozilla::ErrorResult& aRv);
uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
mozilla::ErrorResult& aRv) {
uint32_t retval;

View File

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; 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 "nsICSSRuleList.h"
#include "mozilla/dom/CSSRuleListBinding.h"
using namespace mozilla;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsICSSRuleList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsICSSRuleList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsICSSRuleList)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsICSSRuleList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsICSSRuleList)
/* virtual */ JSObject*
nsICSSRuleList::WrapObject(JSContext* aCx)
{
return dom::CSSRuleListBinding::Wrap(aCx, this);
}

View File

@ -8,17 +8,33 @@
#include "nsIDOMCSSRule.h"
#include "nsIDOMCSSRuleList.h"
#include "nsWrapperCache.h"
class nsCSSStyleSheet;
// IID for the nsICSSRuleList interface
#define NS_ICSSRULELIST_IID \
{ 0xccc0135a, 0xbcb6, 0x4654, \
{ 0x8c, 0x78, 0x74, 0x35, 0x97, 0x9b, 0x88, 0x19 } }
{ 0x56ac8d1c, 0xc1ed, 0x45fe, \
{ 0x9a, 0x4d, 0x3a, 0xdc, 0xf9, 0xd1, 0xb9, 0x3f } }
class nsICSSRuleList : public nsIDOMCSSRuleList
, public nsWrapperCache
{
public:
nsICSSRuleList()
{
SetIsDOMBinding();
}
virtual ~nsICSSRuleList() {}
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICSSRULELIST_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsICSSRuleList)
virtual nsCSSStyleSheet* GetParentObject() = 0;
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE MOZ_FINAL;
NS_IMETHOD
GetLength(uint32_t* aLength) MOZ_OVERRIDE MOZ_FINAL
{

View File

@ -299,23 +299,23 @@ struct MOZ_STACK_CLASS TreeMatchContext {
};
/* Helper class for tracking whether we're skipping the ApplyStyleFixups
* code for flex items.
* code for flex/grid items.
*
* The optional second parameter aSkipFlexItemStyleFixup allows this
* class to be instantiated but only conditionally activated (e.g.
* in cases where we may or may not want to be skipping flex-item
* The optional second parameter aSkipFlexOrGridItemStyleFixup allows
* this class to be instantiated but only conditionally activated (e.g.
* in cases where we may or may not want to be skipping flex/grid-item
* style fixup for a particular chunk of code).
*/
class MOZ_STACK_CLASS AutoFlexItemStyleFixupSkipper {
class MOZ_STACK_CLASS AutoFlexOrGridItemStyleFixupSkipper {
public:
AutoFlexItemStyleFixupSkipper(TreeMatchContext& aTreeMatchContext,
bool aSkipFlexItemStyleFixup = true
AutoFlexOrGridItemStyleFixupSkipper(TreeMatchContext& aTreeMatchContext,
bool aSkipFlexOrGridItemStyleFixup = true
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mAutoRestorer(aTreeMatchContext.mSkippingFlexItemStyleFixup)
: mAutoRestorer(aTreeMatchContext.mSkippingFlexOrGridItemStyleFixup)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (aSkipFlexItemStyleFixup) {
aTreeMatchContext.mSkippingFlexItemStyleFixup = true;
if (aSkipFlexOrGridItemStyleFixup) {
aTreeMatchContext.mSkippingFlexOrGridItemStyleFixup = true;
}
}
@ -373,10 +373,10 @@ struct MOZ_STACK_CLASS TreeMatchContext {
// Whether this document is using PB mode
bool mUsingPrivateBrowsing;
// Whether we're currently skipping the flex item chunk of ApplyStyleFixups
// when resolving style (e.g. for children of elements that have a mandatory
// frame-type and can't be flex containers despite having "display:flex").
bool mSkippingFlexItemStyleFixup;
// Whether we're currently skipping the flex/grid item chunk of
// ApplyStyleFixups when resolving style (e.g. for children of elements that
// have a mandatory frame-type for which we ignore "display:flex/grid").
bool mSkippingFlexOrGridItemStyleFixup;
// Whether this TreeMatchContext is being used with an nsCSSRuleProcessor
// for an HTML5 scoped style sheet.
@ -408,7 +408,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
, mIsHTMLDocument(aDocument->IsHTML())
, mCompatMode(aDocument->GetCompatibilityMode())
, mUsingPrivateBrowsing(false)
, mSkippingFlexItemStyleFixup(false)
, mSkippingFlexOrGridItemStyleFixup(false)
, mForScopedStyle(false)
, mCurrentStyleScope(nullptr)
{

View File

@ -35,7 +35,7 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent,
nsIAtom* aPseudoTag,
nsCSSPseudoElements::Type aPseudoType,
nsRuleNode* aRuleNode,
bool aSkipFlexItemStyleFixup)
bool aSkipFlexOrGridItemStyleFixup)
: mParent(aParent),
mChild(nullptr),
mEmptyChild(nullptr),
@ -71,7 +71,7 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent,
mRuleNode->AddRef();
mRuleNode->SetUsedDirectly(); // before ApplyStyleFixups()!
ApplyStyleFixups(aSkipFlexItemStyleFixup);
ApplyStyleFixups(aSkipFlexOrGridItemStyleFixup);
#define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
@ -294,7 +294,7 @@ nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
}
void
nsStyleContext::ApplyStyleFixups(bool aSkipFlexItemStyleFixup)
nsStyleContext::ApplyStyleFixups(bool aSkipFlexOrGridItemStyleFixup)
{
// See if we have any text decorations.
// First see if our parent has text decorations. If our parent does, then we inherit the bit.
@ -359,7 +359,7 @@ nsStyleContext::ApplyStyleFixups(bool aSkipFlexItemStyleFixup)
// # The computed 'display' of a flex item is determined
// # by applying the table in CSS 2.1 Chapter 9.7.
// ...which converts inline-level elements to their block-level equivalents.
if (!aSkipFlexItemStyleFixup && mParent) {
if (!aSkipFlexOrGridItemStyleFixup && mParent) {
const nsStyleDisplay* parentDisp = mParent->StyleDisplay();
if ((parentDisp->mDisplay == NS_STYLE_DISPLAY_FLEX ||
parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_FLEX ||
@ -382,10 +382,11 @@ nsStyleContext::ApplyStyleFixups(bool aSkipFlexItemStyleFixup)
NS_STYLE_DISPLAY_TABLE_CELL != displayVal) {
// NOTE: Technically, we shouldn't modify the 'display' value of
// positioned elements, since they aren't flex items. However, we don't
// need to worry about checking for that, because if we're positioned,
// we'll have already been through a call to EnsureBlockDisplay() in
// nsRuleNode, so this call here won't change anything. So we're OK.
// positioned elements, since they aren't flex/grid items. However,
// we don't need to worry about checking for that, because if we're
// positioned, we'll have already been through a call to
// EnsureBlockDisplay() in nsRuleNode, so this call here won't change
// anything. So we're OK.
nsRuleNode::EnsureBlockDisplay(displayVal);
if (displayVal != disp->mDisplay) {
NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(),
@ -735,12 +736,12 @@ NS_NewStyleContext(nsStyleContext* aParentContext,
nsIAtom* aPseudoTag,
nsCSSPseudoElements::Type aPseudoType,
nsRuleNode* aRuleNode,
bool aSkipFlexItemStyleFixup)
bool aSkipFlexOrGridItemStyleFixup)
{
nsRefPtr<nsStyleContext> context =
new (aRuleNode->PresContext())
nsStyleContext(aParentContext, aPseudoTag, aPseudoType, aRuleNode,
aSkipFlexItemStyleFixup);
aSkipFlexOrGridItemStyleFixup);
return context.forget();
}

View File

@ -56,15 +56,15 @@ public:
* rules that any element, pseudo-element, or
* anonymous box that this style context is for
* matches. See |nsRuleNode| and |nsIStyleRule|.
* @param aSkipFlexItemStyleFixup
* @param aSkipFlexOrGridItemStyleFixup
* If set, this flag indicates that we should skip
* the chunk of ApplyStyleFixups() that modifies flex
* items' display values.
* and grid items' display values.
*/
nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag,
nsCSSPseudoElements::Type aPseudoType,
nsRuleNode* aRuleNode,
bool aSkipFlexItemStyleFixup);
bool aSkipFlexOrGridItemStyleFixup);
~nsStyleContext();
void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW;
@ -348,7 +348,7 @@ protected:
void AddChild(nsStyleContext* aChild);
void RemoveChild(nsStyleContext* aChild);
void ApplyStyleFixups(bool aSkipFlexItemStyleFixup);
void ApplyStyleFixups(bool aSkipFlexOrGridItemStyleFixup);
void FreeAllocations(nsPresContext* aPresContext);
@ -442,5 +442,5 @@ NS_NewStyleContext(nsStyleContext* aParentContext,
nsIAtom* aPseudoTag,
nsCSSPseudoElements::Type aPseudoType,
nsRuleNode* aRuleNode,
bool aSkipFlexItemStyleFixup);
bool aSkipFlexOrGridItemStyleFixup);
#endif

View File

@ -794,12 +794,13 @@ nsStyleSet::GetContext(nsStyleContext* aParentContext,
if (!result) {
result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
aRuleNode, aFlags & eSkipFlexItemStyleFixup);
aRuleNode,
aFlags & eSkipFlexOrGridItemStyleFixup);
if (aVisitedRuleNode) {
nsRefPtr<nsStyleContext> resultIfVisited =
NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
aVisitedRuleNode,
aFlags & eSkipFlexItemStyleFixup);
aFlags & eSkipFlexOrGridItemStyleFixup);
if (!parentIfVisited) {
mRoots.AppendElement(resultIfVisited);
}
@ -1214,8 +1215,8 @@ nsStyleSet::ResolveStyleFor(Element* aElement,
HasState(NS_EVENT_STATE_VISITED)) {
flags |= eIsVisitedLink;
}
if (aTreeMatchContext.mSkippingFlexItemStyleFixup) {
flags |= eSkipFlexItemStyleFixup;
if (aTreeMatchContext.mSkippingFlexOrGridItemStyleFixup) {
flags |= eSkipFlexOrGridItemStyleFixup;
}
return GetContext(aParentContext, ruleNode, visitedRuleNode,
@ -1378,10 +1379,11 @@ nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
aType == nsCSSPseudoElements::ePseudo_after) {
flags |= eDoAnimation;
} else {
// Flex containers don't expect to have any pseudo-element children aside
// from ::before and ::after. So if we have such a child, we're not
// actually in a flex container, and we should skip flex-item style fixup.
flags |= eSkipFlexItemStyleFixup;
// Flex and grid containers don't expect to have any pseudo-element children
// aside from ::before and ::after. So if we have such a child, we're not
// actually in a flex/grid container, and we should skip flex/grid item
// style fixup.
flags |= eSkipFlexOrGridItemStyleFixup;
}
return GetContext(aParentContext, ruleNode, visitedRuleNode,
@ -1449,10 +1451,11 @@ nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
aType == nsCSSPseudoElements::ePseudo_after) {
flags |= eDoAnimation;
} else {
// Flex containers don't expect to have any pseudo-element children aside
// from ::before and ::after. So if we have such a child, we're not
// actually in a flex container, and we should skip flex-item style fixup.
flags |= eSkipFlexItemStyleFixup;
// Flex and grid containers don't expect to have any pseudo-element children
// aside from ::before and ::after. So if we have such a child, we're not
// actually in a flex/grid container, and we should skip flex/grid item
// style fixup.
flags |= eSkipFlexOrGridItemStyleFixup;
}
nsRefPtr<nsStyleContext> result =
@ -1856,11 +1859,11 @@ nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
}
if (aElement && aElement->IsRootOfAnonymousSubtree()) {
// For anonymous subtree roots, don't tweak "display" value based on
// whether or not the parent is styled as a flex container. (If the parent
// For anonymous subtree roots, don't tweak "display" value based on whether
// or not the parent is styled as a flex/grid container. (If the parent
// has anonymous-subtree kids, then we know it's not actually going to get
// a flex container frame, anyway.)
flags |= eSkipFlexItemStyleFixup;
// a flex/grid container frame, anyway.)
flags |= eSkipFlexOrGridItemStyleFixup;
}
return GetContext(aNewParentContext, ruleNode, visitedRuleNode,

View File

@ -397,12 +397,12 @@ class nsStyleSet
eIsVisitedLink = 1 << 1,
eDoAnimation = 1 << 2,
// Indicates that we should skip the flex-item-specific chunk of
// Indicates that we should skip the flex/grid item specific chunk of
// ApplyStyleFixups(). This is useful if our parent has "display: flex"
// but we can tell it's not going to actually be a flex container (e.g. if
// or "display: grid" but we can tell we're not going to honor that (e.g. if
// it's the outer frame of a button widget, and we're the inline frame for
// the button's label).
eSkipFlexItemStyleFixup = 1 << 3
eSkipFlexOrGridItemStyleFixup = 1 << 3
};
already_AddRefed<nsStyleContext>

View File

@ -181,9 +181,10 @@
height: 100%;
}
*|*::-moz-anonymous-flex-item {
/* Anonymous blocks that wrap contiguous runs of inline non-replaced
* content inside of a flex container. */
*|*::-moz-anonymous-flex-item,
*|*::-moz-anonymous-grid-item {
/* Anonymous blocks that wrap contiguous runs of text
* inside of a flex or grid container. */
display: block;
}

View File

@ -1898,6 +1898,9 @@ pref("layout.css.variables.enabled", true);
// Is support for CSS overflow-clip-box enabled for non-UA sheets?
pref("layout.css.overflow-clip-box.enabled", false);
// Is support for CSS grid enabled?
pref("layout.css.grid.enabled", false);
// pref for which side vertical scrollbars should be on
// 0 = end-side in UI direction
// 1 = end-side in document/content direction

View File

@ -222,7 +222,7 @@ class MarionetteTestResult(unittest._TextTestResult, TestResultCollection):
lastline = None
fail_present = None
for line in err:
if not line.startswith('\t'):
if not line.startswith('\t') and line != '':
lastline = line
if 'TEST-UNEXPECTED-FAIL' in line:
fail_present = True
@ -231,7 +231,7 @@ class MarionetteTestResult(unittest._TextTestResult, TestResultCollection):
self.stream.writeln("%s" % line)
else:
self.stream.writeln("TEST-UNEXPECTED-FAIL | %s | %s" %
(self.getInfo(error), line))
(self.getInfo(error), error.reason))
def stopTest(self, *args, **kwargs):
unittest._TextTestResult.stopTest(self, *args, **kwargs)