mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-i to m-c
This commit is contained in:
commit
be1c8eb709
@ -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
|
||||
|
@ -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
|
||||
|
@ -15,7 +15,6 @@ DOMCI_CLASS(CSSCharsetRule)
|
||||
DOMCI_CLASS(CSSImportRule)
|
||||
DOMCI_CLASS(CSSMediaRule)
|
||||
DOMCI_CLASS(CSSNameSpaceRule)
|
||||
DOMCI_CLASS(CSSRuleList)
|
||||
DOMCI_CLASS(CSSStyleSheet)
|
||||
|
||||
// XUL classes
|
||||
|
@ -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')
|
||||
|
@ -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}
|
||||
|
10
dom/webidl/CSSRuleList.webidl
Normal file
10
dom/webidl/CSSRuleList.webidl
Normal 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);
|
||||
};
|
@ -7,7 +7,6 @@
|
||||
* http://dev.w3.org/csswg/cssom/
|
||||
*/
|
||||
|
||||
interface CSSRuleList;
|
||||
interface CSSRule;
|
||||
|
||||
interface CSSStyleSheet : StyleSheet {
|
||||
|
@ -63,6 +63,7 @@ WEBIDL_FILES = [
|
||||
'Coordinates.webidl',
|
||||
'CSS.webidl',
|
||||
'CSSPrimitiveValue.webidl',
|
||||
'CSSRuleList.webidl',
|
||||
'CSSStyleDeclaration.webidl',
|
||||
'CSSStyleSheet.webidl',
|
||||
'CSSValue.webidl',
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -508,52 +508,122 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand &value,
|
||||
const LDefinition *scratch1, const LDefinition *scratch2,
|
||||
FloatRegister fr,
|
||||
Label *ifTruthy, Label *ifFalsy,
|
||||
OutOfLineTestObject *ool)
|
||||
OutOfLineTestObject *ool,
|
||||
MDefinition *valueMIR)
|
||||
{
|
||||
Register tag = masm.splitTagForTest(value);
|
||||
// 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);
|
||||
|
||||
// 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).
|
||||
masm.branchTestUndefined(Assembler::Equal, tag, ifFalsy);
|
||||
masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
|
||||
MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0);
|
||||
|
||||
Label notBoolean;
|
||||
masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean);
|
||||
masm.branchTestBooleanTruthy(false, value, ifFalsy);
|
||||
masm.jump(ifTruthy);
|
||||
masm.bind(¬Boolean);
|
||||
|
||||
Label notInt32;
|
||||
masm.branchTestInt32(Assembler::NotEqual, tag, ¬Int32);
|
||||
masm.branchTestInt32Truthy(false, value, ifFalsy);
|
||||
masm.jump(ifTruthy);
|
||||
masm.bind(¬Int32);
|
||||
|
||||
if (ool) {
|
||||
Label notObject;
|
||||
|
||||
masm.branchTestObject(Assembler::NotEqual, tag, ¬Object);
|
||||
|
||||
Register objreg = masm.extractObject(value, ToRegister(scratch1));
|
||||
testObjectEmulatesUndefined(objreg, ifFalsy, ifTruthy, ToRegister(scratch2), ool);
|
||||
|
||||
masm.bind(¬Object);
|
||||
} else {
|
||||
masm.branchTestObject(Assembler::Equal, tag, ifTruthy);
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Test if a string is non-empty.
|
||||
Label notString;
|
||||
masm.branchTestString(Assembler::NotEqual, tag, ¬String);
|
||||
masm.branchTestStringTruthy(false, value, ifFalsy);
|
||||
masm.jump(ifTruthy);
|
||||
masm.bind(¬String);
|
||||
Register tag = masm.splitTagForTest(value);
|
||||
|
||||
// If we reach here the value is a double.
|
||||
masm.unboxDouble(value, fr);
|
||||
masm.branchTestDoubleTruthy(false, fr, ifFalsy);
|
||||
if (mightBeUndefined) {
|
||||
MOZ_ASSERT(tagCount > 1);
|
||||
masm.branchTestUndefined(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, ¬Boolean);
|
||||
masm.branchTestBooleanTruthy(false, value, ifFalsy);
|
||||
if (tagCount != 1)
|
||||
masm.jump(ifTruthy);
|
||||
// Else just fall through to truthiness.
|
||||
masm.bind(¬Boolean);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
if (mightBeInt32) {
|
||||
MOZ_ASSERT(tagCount != 0);
|
||||
Label notInt32;
|
||||
if (tagCount != 1)
|
||||
masm.branchTestInt32(Assembler::NotEqual, tag, ¬Int32);
|
||||
masm.branchTestInt32Truthy(false, value, ifFalsy);
|
||||
if (tagCount != 1)
|
||||
masm.jump(ifTruthy);
|
||||
// Else just fall through to truthiness.
|
||||
masm.bind(¬Int32);
|
||||
--tagCount;
|
||||
}
|
||||
|
||||
if (mightBeObject) {
|
||||
MOZ_ASSERT(tagCount != 0);
|
||||
if (ool) {
|
||||
Label notObject;
|
||||
|
||||
if (tagCount != 1)
|
||||
masm.branchTestObject(Assembler::NotEqual, tag, ¬Object);
|
||||
|
||||
Register objreg = masm.extractObject(value, ToRegister(scratch1));
|
||||
testObjectEmulatesUndefined(objreg, ifFalsy, ifTruthy, ToRegister(scratch2), ool);
|
||||
|
||||
masm.bind(¬Object);
|
||||
} 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, ¬String);
|
||||
masm.branchTestStringTruthy(false, value, ifFalsy);
|
||||
if (tagCount != 1)
|
||||
masm.jump(ifTruthy);
|
||||
// Else just fall through to truthiness.
|
||||
masm.bind(¬String);
|
||||
--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());
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -278,6 +278,10 @@ class JitRuntime
|
||||
return ionAlloc_;
|
||||
}
|
||||
|
||||
bool hasIonAlloc() const {
|
||||
return !!ionAlloc_;
|
||||
}
|
||||
|
||||
bool ionCodeProtected() {
|
||||
return ionCodeProtected_;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
if(!QueryPerformanceFrequency(&liFreq)) {
|
||||
/* High-performance timer is unavailable */
|
||||
LARGE_INTEGER liFreq;
|
||||
if (!QueryPerformanceFrequency(&liFreq)) {
|
||||
// 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 */
|
||||
if(calibration.offset == cachedOffset) {
|
||||
/* Since calibration can take a while, make any other
|
||||
threads immediately wait */
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for clock skew */
|
||||
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);*/
|
||||
|
||||
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. */
|
||||
needsCalibration = true;
|
||||
}
|
||||
} else {
|
||||
/* No detectable clock skew */
|
||||
returnedTime = int64_t(highresTime);
|
||||
needsCalibration = false;
|
||||
// Default to 15.625 ms if the syscall fails.
|
||||
skewThreshold = 15625.25;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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.
|
||||
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 high resolution timer is available, so fall back */
|
||||
// No high resolution timer is available, so fall back.
|
||||
returnedTime = int64_t(lowresTime);
|
||||
}
|
||||
} while (needsCalibration);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -2448,9 +2448,9 @@ 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,
|
||||
element->IsRootOfNativeAnonymousSubtree());
|
||||
TreeMatchContext::AutoFlexOrGridItemStyleFixupSkipper
|
||||
flexOrGridFixupSkipper(mTreeMatchContext,
|
||||
element->IsRootOfNativeAnonymousSubtree());
|
||||
newContext = styleSet->ResolveStyleFor(element, parentContext,
|
||||
mTreeMatchContext);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,14 +1020,15 @@ 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,
|
||||
FrameConstructionItemList& aItems,
|
||||
nsIFrame* aParentFrame);
|
||||
void CreateNeededAnonFlexOrGridItems(nsFrameConstructorState& aState,
|
||||
FrameConstructionItemList& aItems,
|
||||
nsIFrame* aParentFrame);
|
||||
|
||||
/**
|
||||
* Function to create the table pseudo items we need.
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
55
layout/reftests/css-grid/grid-whitespace-handling-1a.xhtml
Normal file
55
layout/reftests/css-grid/grid-whitespace-handling-1a.xhtml
Normal 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>
|
||||
|
48
layout/reftests/css-grid/grid-whitespace-handling-1b.xhtml
Normal file
48
layout/reftests/css-grid/grid-whitespace-handling-1b.xhtml
Normal 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>
|
||||
|
@ -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>
|
||||
|
53
layout/reftests/css-grid/grid-whitespace-handling-2.xhtml
Normal file
53
layout/reftests/css-grid/grid-whitespace-handling-2.xhtml
Normal 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>
|
7
layout/reftests/css-grid/reftest.list
Normal file
7
layout/reftests/css-grid/reftest.list
Normal 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
|
4
layout/reftests/css-grid/support/ahem.css
Normal file
4
layout/reftests/css-grid/support/ahem.css
Normal file
@ -0,0 +1,4 @@
|
||||
@font-face {
|
||||
font-family: "Ahem";
|
||||
src: url(../../fonts/Ahem.ttf);
|
||||
}
|
BIN
layout/reftests/css-grid/support/solidblue.png
Normal file
BIN
layout/reftests/css-grid/support/solidblue.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 B |
@ -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
|
||||
|
||||
|
@ -112,6 +112,7 @@ UNIFIED_SOURCES += [
|
||||
'nsDOMCSSValueList.cpp',
|
||||
'nsHTMLCSSStyleSheet.cpp',
|
||||
'nsHTMLStyleSheet.cpp',
|
||||
'nsICSSRuleList.cpp',
|
||||
'nsLayoutStylesheetCache.cpp',
|
||||
'nsMediaFeatures.cpp',
|
||||
'nsNthIndexCache.cpp',
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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!
|
||||
|
@ -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;
|
||||
|
30
layout/style/nsICSSRuleList.cpp
Normal file
30
layout/style/nsICSSRuleList.cpp
Normal 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);
|
||||
}
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mAutoRestorer(aTreeMatchContext.mSkippingFlexItemStyleFixup)
|
||||
AutoFlexOrGridItemStyleFixupSkipper(TreeMatchContext& aTreeMatchContext,
|
||||
bool aSkipFlexOrGridItemStyleFixup = true
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: 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)
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
@ -623,7 +623,7 @@ class BaseMarionetteTestRunner(object):
|
||||
# for XML output
|
||||
self.testvars['xml_output'] = self.xml_output
|
||||
self.results = []
|
||||
|
||||
|
||||
@property
|
||||
def capabilities(self):
|
||||
if self._capabilities:
|
||||
|
Loading…
Reference in New Issue
Block a user