Bug 976787 part 2: Add the grid-template-areas property to the style system. r=dholbert

This commit is contained in:
Simon Sapin 2014-03-10 15:54:14 -07:00
Родитель 12935dcb17
Коммит 27ad62a36d
13 изменённых файлов: 397 добавлений и 6 удалений

Просмотреть файл

@ -636,6 +636,11 @@ protected:
bool ParseGridTrackBreadth(nsCSSValue& aValue);
bool ParseGridTrackSize(nsCSSValue& aValue);
bool ParseGridTrackList(nsCSSProperty aPropID);
bool ParseGridTemplateAreasLine(const nsAutoString& aInput,
nsTArray<nsCSSGridNamedArea>& aNamedAreas,
uint32_t aRow,
uint32_t& aColumns);
bool ParseGridTemplateAreas();
// for 'clip' and '-moz-image-region'
bool ParseRect(nsCSSProperty aPropID);
@ -5762,7 +5767,7 @@ CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
if (eCSSToken_AtKeyword == tk->mType) {
SkipAtRule(checkForBraces);
return true; // Not a declaration, but dont skip until ';'
return true; // Not a declaration, but don't skip until ';'
}
}
// Not a declaration...
@ -6999,6 +7004,116 @@ CSSParserImpl::ParseGridTrackList(nsCSSProperty aPropID)
return true;
}
bool
CSSParserImpl::ParseGridTemplateAreasLine(const nsAutoString& aInput,
nsTArray<nsCSSGridNamedArea>& aNamedAreas,
uint32_t aRow,
uint32_t& aColumns)
{
nsCSSGridTemplateAreaScanner scanner(aInput);
nsCSSGridTemplateAreaToken token;
nsCSSGridNamedArea* currentArea = nullptr;
uint32_t column;
for (column = 1; scanner.Next(token); column++) {
if (token.isTrash) {
return false;
}
if (currentArea) {
if (token.mName == currentArea->mName) {
if (currentArea->mRowStart == aRow) {
// Next column in the first row of this named area.
currentArea->mColumnEnd++;
}
continue;
}
// We're exiting |currentArea|, so currentArea is ending at |column|.
// Make sure that this is consistent with currentArea on previous rows:
if (currentArea->mColumnEnd != column) {
NS_ASSERTION(currentArea->mRowStart != aRow,
"Inconsistent column end for the first row of a named area.");
// Not a rectangle
return false;
}
currentArea = nullptr;
}
if (!token.mName.IsEmpty()) {
// Named cell that doesn't have a cell with the same name on its left.
// Check if this is the continuation of an existing named area:
for (uint32_t i = 0, end = aNamedAreas.Length(); i < end; i++) {
if (aNamedAreas[i].mName == token.mName) {
currentArea = &aNamedAreas[i];
if (currentArea->mColumnStart != column || currentArea->mRowEnd != aRow) {
// Existing named area, but not forming a rectangle
return false;
}
// Next row of an existing named area
currentArea->mRowEnd++;
break;
}
}
if (!currentArea) {
// New named area
currentArea = aNamedAreas.AppendElement();
currentArea->mName = token.mName;
// For column or row N (starting at 1),
// the start line is N, the end line is N + 1
currentArea->mColumnStart = column;
currentArea->mColumnEnd = column + 1;
currentArea->mRowStart = aRow;
currentArea->mRowEnd = aRow + 1;
}
}
}
if (currentArea && currentArea->mColumnEnd != column) {
NS_ASSERTION(currentArea->mRowStart != aRow,
"Inconsistent column end for the first row of a named area.");
// Not a rectangle
return false;
}
aColumns = column;
return true;
}
bool
CSSParserImpl::ParseGridTemplateAreas()
{
nsCSSValue value;
if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
AppendValue(eCSSProperty_grid_template_areas, value);
return true;
}
nsCSSValueGridTemplateAreas& result = value.SetGridTemplateAreas();
uint32_t row = 1;
uint32_t firstRowColumns;
do {
if (!GetToken(true)) {
return false;
}
if (eCSSToken_String != mToken.mType) {
UngetToken(); // In case it's opening a block or function.
return false;
}
uint32_t columns;
if (!ParseGridTemplateAreasLine(mToken.mIdent, result.mNamedAreas,
row, columns)) {
return false;
}
if (row == 1) {
firstRowColumns = columns;
} else if (columns != firstRowColumns) {
return false;
}
result.mTemplates.AppendElement(mToken.mIdent);
row++;
} while (!CheckEndProperty());
AppendValue(eCSSProperty_grid_template_areas, value);
return true;
}
// <color-stop> : <color> [ <percentage> | <length> ]?
bool
CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient)
@ -8013,6 +8128,8 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
return ParseFlexFlow();
case eCSSProperty_font:
return ParseFont();
case eCSSProperty_grid_template_areas:
return ParseGridTemplateAreas();
case eCSSProperty_grid_template_columns:
case eCSSProperty_grid_template_rows:
return ParseGridTrackList(aPropID);

Просмотреть файл

@ -2008,6 +2008,16 @@ CSS_PROP_UIRESET(
nullptr,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None) // bug 58646
CSS_PROP_POSITION(
grid-template-areas,
grid_template_areas,
GridTemplateAreas,
CSS_PROPERTY_PARSE_FUNCTION,
"layout.css.grid.enabled",
0,
nullptr,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_POSITION(
grid-template-columns,
grid_template_columns,

Просмотреть файл

@ -1327,3 +1327,44 @@ nsCSSScanner::Next(nsCSSToken& aToken, bool aSkipWS)
Advance();
return true;
}
/* nsCSSGridTemplateAreaScanner methods. */
nsCSSGridTemplateAreaScanner::nsCSSGridTemplateAreaScanner(const nsAString& aBuffer)
: mBuffer(aBuffer.BeginReading())
, mOffset(0)
, mCount(aBuffer.Length())
{
}
bool
nsCSSGridTemplateAreaScanner::Next(nsCSSGridTemplateAreaToken& aTokenResult)
{
int32_t ch;
// Skip whitespace
do {
if (mOffset >= mCount) {
return false;
}
ch = mBuffer[mOffset];
mOffset++;
} while (IsWhitespace(ch));
if (IsOpenCharClass(ch, IS_IDCHAR)) {
// Named cell token
uint32_t start = mOffset - 1; // offset of |ch|
while (mOffset < mCount && IsOpenCharClass(mBuffer[mOffset], IS_IDCHAR)) {
mOffset++;
}
aTokenResult.mName.Assign(&mBuffer[start], mOffset - start);
aTokenResult.isTrash = false;
} else if (ch == '.') {
// Null cell token
aTokenResult.mName.Truncate();
aTokenResult.isTrash = false;
} else {
// Trash token
aTokenResult.isTrash = true;
}
return true;
}

Просмотреть файл

@ -353,4 +353,26 @@ protected:
bool mSeenVariableReference;
};
// Token for the grid-template-areas micro-syntax
// http://dev.w3.org/csswg/css-grid/#propdef-grid-template-areas
struct MOZ_STACK_CLASS nsCSSGridTemplateAreaToken {
nsAutoString mName; // Empty for a null cell, non-empty for a named cell
bool isTrash; // True for a trash token, mName is ignored in this case.
};
// Scanner for the grid-template-areas micro-syntax
class nsCSSGridTemplateAreaScanner {
public:
nsCSSGridTemplateAreaScanner(const nsAString& aBuffer);
// Get the next token. Return false on EOF.
// aTokenResult is filled in with the data for the token.
bool Next(nsCSSGridTemplateAreaToken& aTokenResult);
private:
const char16_t *mBuffer;
uint32_t mOffset;
uint32_t mCount;
};
#endif /* nsCSSScanner_h___ */

Просмотреть файл

@ -178,6 +178,10 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
else if (eCSSUnit_PairListDep == mUnit) {
mValue.mPairListDependent = aCopy.mValue.mPairListDependent;
}
else if (eCSSUnit_GridTemplateAreas == mUnit) {
mValue.mGridTemplateAreas = aCopy.mValue.mGridTemplateAreas;
mValue.mGridTemplateAreas->AddRef();
}
else {
NS_ABORT_IF_FALSE(false, "unknown unit");
}
@ -250,6 +254,9 @@ bool nsCSSValue::operator==(const nsCSSValue& aOther) const
else if (eCSSUnit_PairList == mUnit) {
return *mValue.mPairList == *aOther.mValue.mPairList;
}
else if (eCSSUnit_GridTemplateAreas == mUnit) {
return *mValue.mGridTemplateAreas == *aOther.mValue.mGridTemplateAreas;
}
else {
return mValue.mFloat == aOther.mValue.mFloat;
}
@ -336,6 +343,8 @@ void nsCSSValue::DoReset()
mValue.mSharedList->Release();
} else if (eCSSUnit_PairList == mUnit) {
mValue.mPairList->Release();
} else if (eCSSUnit_GridTemplateAreas == mUnit) {
mValue.mGridTemplateAreas->Release();
}
mUnit = eCSSUnit_Null;
}
@ -587,6 +596,15 @@ void nsCSSValue::SetDependentPairListValue(nsCSSValuePairList* aList)
}
}
nsCSSValueGridTemplateAreas& nsCSSValue::SetGridTemplateAreas()
{
Reset();
mUnit = eCSSUnit_GridTemplateAreas;
mValue.mGridTemplateAreas = new nsCSSValueGridTemplateAreas;
mValue.mGridTemplateAreas->AddRef();
return *mValue.mGridTemplateAreas;
}
void nsCSSValue::SetAutoValue()
{
Reset();
@ -1307,6 +1325,8 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
GetPairListValue()->AppendToString(aProperty, aResult, aSerialization);
break;
}
} else if (eCSSUnit_GridTemplateAreas == unit) {
GetGridTemplateAreas().AppendToString(aProperty, aResult, aSerialization);
}
switch (unit) {
@ -1368,6 +1388,7 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
case eCSSUnit_SharedList: break;
case eCSSUnit_PairList: break;
case eCSSUnit_PairListDep: break;
case eCSSUnit_GridTemplateAreas: break;
case eCSSUnit_Inch: aResult.AppendLiteral("in"); break;
case eCSSUnit_Millimeter: aResult.AppendLiteral("mm"); break;
@ -1509,6 +1530,11 @@ nsCSSValue::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
case eCSSUnit_PairListDep:
break;
// GridTemplateAreas
case eCSSUnit_GridTemplateAreas:
n += mValue.mGridTemplateAreas->SizeOfIncludingThis(aMallocSizeOf);
break;
// Int: nothing extra to measure.
case eCSSUnit_Integer:
case eCSSUnit_Enumerated:
@ -2335,3 +2361,28 @@ nsCSSCornerSizes::corners[4] = {
&nsCSSCornerSizes::mBottomRight,
&nsCSSCornerSizes::mBottomLeft,
};
void
nsCSSValueGridTemplateAreas::AppendToString(nsCSSProperty aProperty,
nsAString& aResult,
nsCSSValue::Serialization aValueSerialization) const
{
uint32_t length = mTemplates.Length();
if (length == 0) {
aResult.AppendLiteral("none");
} else {
nsStyleUtil::AppendEscapedCSSString(mTemplates[0], aResult);
for (uint32_t i = 1; i < length; i++) {
aResult.Append(char16_t(' '));
nsStyleUtil::AppendEscapedCSSString(mTemplates[i], aResult);
}
}
}
size_t
nsCSSValueGridTemplateAreas::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
size_t n = mNamedAreas.SizeOfExcludingThis(aMallocSizeOf);
n += mTemplates.SizeOfIncludingThis(aMallocSizeOf);
return n;
}

Просмотреть файл

@ -206,6 +206,8 @@ enum nsCSSUnit {
eCSSUnit_PairListDep = 57, // (nsCSSValuePairList*) same as PairList
// but does not own the list
eCSSUnit_GridTemplateAreas = 60, // (nsCSSValueGridTemplateAreas*) for grid-template-areas
eCSSUnit_Integer = 70, // (int) simple value
eCSSUnit_Enumerated = 71, // (int) value has enumerated meaning
@ -277,6 +279,7 @@ struct nsCSSValuePairList;
struct nsCSSValuePairList_heap;
struct nsCSSValueTriplet;
struct nsCSSValueTriplet_heap;
struct nsCSSValueGridTemplateAreas;
class nsCSSValueFloatColor;
class nsCSSValue {
@ -497,6 +500,9 @@ public:
inline nsCSSValueTriplet& GetTripletValue();
inline const nsCSSValueTriplet& GetTripletValue() const;
inline nsCSSValueGridTemplateAreas& GetGridTemplateAreas();
inline const nsCSSValueGridTemplateAreas& GetGridTemplateAreas() const;
mozilla::css::URLValue* GetURLStructValue() const
{
// Not allowing this for Image values, because if the caller takes
@ -575,6 +581,7 @@ public:
nsCSSRect& SetRectValue();
nsCSSValueList* SetListValue();
nsCSSValuePairList* SetPairListValue();
nsCSSValueGridTemplateAreas& SetGridTemplateAreas();
void StartImageLoad(nsIDocument* aDocument) const; // Only pretend const
@ -617,6 +624,7 @@ protected:
nsCSSValueSharedList* mSharedList;
nsCSSValuePairList_heap* mPairList;
nsCSSValuePairList* mPairListDependent;
nsCSSValueGridTemplateAreas* mGridTemplateAreas;
nsCSSValueFloatColor* mFloatColor;
} mValue;
};
@ -1152,6 +1160,22 @@ nsCSSValue::GetPairListValue() const
}
}
inline nsCSSValueGridTemplateAreas&
nsCSSValue::GetGridTemplateAreas()
{
NS_ABORT_IF_FALSE (mUnit == eCSSUnit_GridTemplateAreas,
"not a grid-template-areas value");
return *mValue.mGridTemplateAreas;
}
inline const nsCSSValueGridTemplateAreas&
nsCSSValue::GetGridTemplateAreas() const
{
NS_ABORT_IF_FALSE (mUnit == eCSSUnit_GridTemplateAreas,
"not a grid-template-areas value");
return *mValue.mGridTemplateAreas;
}
struct nsCSSValueGradientStop {
public:
nsCSSValueGradientStop();
@ -1425,5 +1449,45 @@ protected:
static const corner_type corners[4];
};
struct nsCSSGridNamedArea {
nsString mName;
uint32_t mColumnStart;
uint32_t mColumnEnd;
uint32_t mRowStart;
uint32_t mRowEnd;
};
struct nsCSSValueGridTemplateAreas {
nsTArray<nsCSSGridNamedArea> mNamedAreas; // Parsed value
nsTArray<nsString> mTemplates; // Original <string> values, for serialization
nsCSSValueGridTemplateAreas()
{
}
nsCSSValueGridTemplateAreas(const nsCSSValueGridTemplateAreas& aOther)
: mNamedAreas(aOther.mNamedAreas)
, mTemplates(aOther.mTemplates)
{
}
void AppendToString(nsCSSProperty aProperty, nsAString& aResult,
nsCSSValue::Serialization aValueSerialization) const;
bool operator==(const nsCSSValueGridTemplateAreas& aOther) const
{
return mTemplates == aOther.mTemplates;
}
bool operator!=(const nsCSSValueGridTemplateAreas& aOther) const
{
return !(*this == aOther);
}
NS_INLINE_DECL_REFCOUNTING(nsCSSValueGridTemplateAreas)
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
};
#endif /* nsCSSValue_h___ */

Просмотреть файл

@ -2271,6 +2271,28 @@ nsComputedDOMStyle::DoGetBackgroundSize()
return valueList;
}
CSSValue*
nsComputedDOMStyle::DoGetGridTemplateAreas()
{
const nsTArray<nsString>& templates =
StylePosition()->mGridTemplateAreas.mTemplates;
if (templates.IsEmpty()) {
nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
val->SetIdent(eCSSKeyword_none);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
for (uint32_t i = 0; i < templates.Length(); i++) {
nsAutoString str;
nsStyleUtil::AppendEscapedCSSString(templates[i], str);
nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
val->SetString(str);
valueList->AppendCSSValue(val);
}
return valueList;
}
// aLineNames must not be empty
CSSValue*
nsComputedDOMStyle::GetGridLineNames(const nsTArray<nsString>& aLineNames)

Просмотреть файл

@ -263,6 +263,7 @@ private:
mozilla::dom::CSSValue* DoGetFontWeight();
/* Grid properties */
mozilla::dom::CSSValue* DoGetGridTemplateAreas();
mozilla::dom::CSSValue* DoGetGridTemplateColumns();
mozilla::dom::CSSValue* DoGetGridTemplateRows();

Просмотреть файл

@ -130,6 +130,7 @@ COMPUTED_STYLE_PROP(font_variant_ligatures, FontVariantLigatures)
COMPUTED_STYLE_PROP(font_variant_numeric, FontVariantNumeric)
COMPUTED_STYLE_PROP(font_variant_position, FontVariantPosition)
COMPUTED_STYLE_PROP(font_weight, FontWeight)
COMPUTED_STYLE_PROP(grid_template_areas, GridTemplateAreas)
COMPUTED_STYLE_PROP(grid_template_columns, GridTemplateColumns)
COMPUTED_STYLE_PROP(grid_template_rows, GridTemplateRows)
COMPUTED_STYLE_PROP(height, Height)

Просмотреть файл

@ -7177,6 +7177,36 @@ SetGridTrackList(const nsCSSValue& aValue,
}
}
static void
SetGridTemplateAreas(const nsCSSValue& aValue,
nsCSSValueGridTemplateAreas& aResult,
const nsCSSValueGridTemplateAreas& aParentValue,
bool& aCanStoreInRuleTree)
{
switch (aValue.GetUnit()) {
case eCSSUnit_Null:
break;
case eCSSUnit_Inherit:
aCanStoreInRuleTree = false;
aResult.mNamedAreas = aParentValue.mNamedAreas;
aResult.mTemplates = aParentValue.mTemplates;
break;
case eCSSUnit_Initial:
case eCSSUnit_Unset:
case eCSSUnit_None:
aResult.mNamedAreas.Clear();
aResult.mTemplates.Clear();
break;
default:
const nsCSSValueGridTemplateAreas& value = aValue.GetGridTemplateAreas();
aResult.mNamedAreas = value.mNamedAreas;
aResult.mTemplates = value.mTemplates;
}
}
const void*
nsRuleNode::ComputePositionData(void* aStartStruct,
const nsRuleData* aRuleData,
@ -7360,6 +7390,11 @@ nsRuleNode::ComputePositionData(void* aStartStruct,
pos->mGridTemplateRows, parentPos->mGridTemplateRows,
aContext, mPresContext, canStoreInRuleTree);
// grid-tempate-areas
SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
pos->mGridTemplateAreas, parentPos->mGridTemplateAreas,
canStoreInRuleTree);
// z-index
const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,

Просмотреть файл

@ -1239,9 +1239,10 @@ nsStylePosition::nsStylePosition(void)
mFlexGrow = 0.0f;
mFlexShrink = 1.0f;
mZIndex.SetAutoValue();
// mGridTemplateRows and mGridTemplateColumns get their default constructors
// which initializes them to empty arrays,
// which represent the propertys initial value 'none'
// mGridTemplateRows, mGridTemplateColumns, and mGridTemplateAreas
// get their default constructors
// which initialize them to empty arrays,
// which represent the properties' initial value 'none'.
}
nsStylePosition::~nsStylePosition(void)
@ -1252,6 +1253,7 @@ nsStylePosition::~nsStylePosition(void)
nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
: mGridTemplateColumns(aSource.mGridTemplateColumns)
, mGridTemplateRows(aSource.mGridTemplateRows)
, mGridTemplateAreas(aSource.mGridTemplateAreas)
{
MOZ_COUNT_CTOR(nsStylePosition);
// If you add any memcpy'able member vars,
@ -1262,7 +1264,9 @@ nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
// and update this static-assert to include their "sizeof()"
static_assert(sizeof(nsStylePosition) ==
offsetof(nsStylePosition, mGridTemplateColumns) +
sizeof(mGridTemplateColumns) + sizeof(mGridTemplateRows),
sizeof(mGridTemplateColumns) +
sizeof(mGridTemplateRows) +
sizeof(mGridTemplateAreas),
"Unexpected size or offset in nsStylePosition");
memcpy((nsStylePosition*) this,
&aSource,
@ -1318,7 +1322,8 @@ nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) cons
// Properties that apply to grid containers:
if (mGridTemplateColumns != aOther.mGridTemplateColumns ||
mGridTemplateRows != aOther.mGridTemplateRows) {
mGridTemplateRows != aOther.mGridTemplateRows ||
mGridTemplateAreas != aOther.mGridTemplateAreas) {
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
}

Просмотреть файл

@ -1234,6 +1234,7 @@ struct nsStylePosition {
// in nsStyleStruct.cpp
nsStyleGridTrackList mGridTemplateColumns;
nsStyleGridTrackList mGridTemplateRows;
nsCSSValueGridTemplateAreas mGridTemplateAreas;
bool WidthDependsOnContainer() const
{ return WidthCoordDependsOnContainer(mWidth); }

Просмотреть файл

@ -4850,6 +4850,27 @@ if (SpecialPowers.getBoolPref("layout.css.grid.enabled")) {
other_values: gCSSProperties["grid-template-columns"].other_values,
invalid_values: gCSSProperties["grid-template-columns"].invalid_values
};
gCSSProperties["grid-template-areas"] = {
domProp: "gridTemplateAreas",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [
"''",
"'' ''",
"'1a-é_ .' \"b .\"",
"' Z\t\\aZ' 'Z Z'",
" '. . a b' '..a b' ",
],
invalid_values: [
"'a b' 'a/b'",
"'a . a'",
"'. a a' 'a a a'",
"'a a .' 'a a a'",
"'a a' 'a .'",
"'a a'\n'..'\n'a a'",
]
};
}
if (SpecialPowers.getBoolPref("layout.css.image-orientation.enabled")) {