diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index b6b17907706..78f2e28dce4 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -376,11 +376,14 @@ CSS_KEY(margin-box, margin_box) CSS_KEY(markers, markers) CSS_KEY(matrix, matrix) CSS_KEY(matrix3d, matrix3d) +CSS_KEY(max-content, max_content) CSS_KEY(medium, medium) CSS_KEY(menu, menu) CSS_KEY(menutext, menutext) CSS_KEY(message-box, message_box) CSS_KEY(middle, middle) +CSS_KEY(min-content, min_content) +CSS_KEY(minmax, minmax) CSS_KEY(mix, mix) CSS_KEY(mm, mm) CSS_KEY(monospace, monospace) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 160340fca83..d68319ca9a4 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -631,6 +631,12 @@ protected: // For "flex-flow" shorthand property, defined in CSS Flexbox spec bool ParseFlexFlow(); + // CSS Grid + bool ParseGridLineNames(nsCSSValue& aValue); + bool ParseGridTrackBreadth(nsCSSValue& aValue); + bool ParseGridTrackSize(nsCSSValue& aValue); + bool ParseGridTrackList(nsCSSProperty aPropID); + // for 'clip' and '-moz-image-region' bool ParseRect(nsCSSProperty aPropID); bool ParseColumns(); @@ -781,6 +787,24 @@ protected: bool ParseOneOrLargerVariant(nsCSSValue& aValue, int32_t aVariantMask, const KTableValue aKeywordTable[]); + + // http://dev.w3.org/csswg/css-values/#custom-idents + // Parse an identifier that is none of: + // * a CSS-wide keyword + // * "default" + // * a keyword in |aExcludedKeywords| + // * a keyword in |aPropertyKTable| + // + // |aExcludedKeywords| is an array of nsCSSKeyword + // that ends with a eCSSKeyword_UNKNOWN marker. + // + // |aPropertyKTable| can be used if some of the keywords to exclude + // also appear in an existing nsCSSProps::KTableValue, + // to avoid duplicating them. + bool ParseCustomIdent(nsCSSValue& aValue, + const nsAutoString& aIdentValue, + const nsCSSKeyword aExcludedKeywords[] = nullptr, + const nsCSSProps::KTableValue aPropertyKTable[] = nullptr); bool ParseCounter(nsCSSValue& aValue); bool ParseAttr(nsCSSValue& aValue); bool SetValueToURL(nsCSSValue& aValue, const nsString& aURL); @@ -6159,6 +6183,9 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue, // XXX Should we check IsParsingCompoundProperty, or do all // callers handle it? (Not all callers set it, though, since // they want the quirks that are disabled by setting it.) + + // IMPORTANT: If new keywords are added here, + // they probably need to be added in ParseCustomIdent as well. if (eCSSKeyword_inherit == keyword) { aValue.SetInheritValue(); return true; @@ -6392,6 +6419,40 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue, return false; } +bool +CSSParserImpl::ParseCustomIdent(nsCSSValue& aValue, + const nsAutoString& aIdentValue, + const nsCSSKeyword aExcludedKeywords[], + const nsCSSProps::KTableValue aPropertyKTable[]) +{ + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aIdentValue); + if (keyword == eCSSKeyword_UNKNOWN) { + // Fast path for identifiers that are not known CSS keywords: + aValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident); + return true; + } + if (keyword == eCSSKeyword_inherit || + keyword == eCSSKeyword_initial || + keyword == eCSSKeyword_unset || + keyword == eCSSKeyword_default || + (aPropertyKTable && + nsCSSProps::FindIndexOfKeyword(keyword, aPropertyKTable) >= 0)) { + return false; + } + if (aExcludedKeywords) { + for (uint32_t i = 0;; i++) { + nsCSSKeyword excludedKeyword = aExcludedKeywords[i]; + if (excludedKeyword == eCSSKeyword_UNKNOWN) { + break; + } + if (excludedKeyword == keyword) { + return false; + } + } + } + aValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident); + return true; +} bool CSSParserImpl::ParseCounter(nsCSSValue& aValue) @@ -6808,6 +6869,136 @@ CSSParserImpl::ParseFlexFlow() return true; } +// Parse an optional expression. +// If successful, leaves aValue with eCSSUnit_Null for the empty list, +// or sets it to a eCSSUnit_List of eCSSUnit_Ident. +// Not finding an open paren is considered the same as an empty list. + +// aPropertyKeywords contains additional keywords for the 'grid' shorthand. +bool +CSSParserImpl::ParseGridLineNames(nsCSSValue& aValue) +{ + MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Null, + "Unexpected unit, aValue should not be initialized yet"); + if (!GetToken(true)) { + return true; + } + if (!mToken.IsSymbol('(')) { + UngetToken(); + return true; + } + if (!GetToken(true) || mToken.IsSymbol(')')) { + return true; + } + // 'return true' so far keeps eCSSUnit_Null, to represent an empty list. + + nsCSSValueList* item = aValue.SetListValue(); + for (;;) { + if (!(eCSSToken_Ident == mToken.mType && + ParseCustomIdent(item->mValue, mToken.mIdent))) { + UngetToken(); + SkipUntil(')'); + return false; + } + if (!GetToken(true) || mToken.IsSymbol(')')) { + return true; + } + item->mNext = new nsCSSValueList; + item = item->mNext; + } +} + +// Parse a +bool +CSSParserImpl::ParseGridTrackBreadth(nsCSSValue& aValue) +{ + if (ParseNonNegativeVariant(aValue, + VARIANT_LPCALC | VARIANT_KEYWORD, + nsCSSProps::kGridTrackBreadthKTable)) { + return true; + } + + // Attempt to parse (a dimension with the "fr" unit) + if (!GetToken(true)) { + return false; + } + if (!(eCSSToken_Dimension == mToken.mType && + mToken.mIdent.LowerCaseEqualsLiteral("fr") && + mToken.mNumber >= 0)) { + UngetToken(); + return false; + } + aValue.SetFloatValue(mToken.mNumber, eCSSUnit_FlexFraction); + return true; +} + +// Parse a +bool +CSSParserImpl::ParseGridTrackSize(nsCSSValue& aValue) +{ + // Attempt to parse 'auto' or a single + if (ParseGridTrackBreadth(aValue) || + ParseVariant(aValue, VARIANT_AUTO, nullptr)) { + return true; + } + + // Attempt to parse a minmax() function + if (!GetToken(true)) { + return false; + } + if (!(eCSSToken_Function == mToken.mType && + mToken.mIdent.LowerCaseEqualsLiteral("minmax"))) { + UngetToken(); + return false; + } + nsCSSValue::Array* func = aValue.InitFunction(eCSSKeyword_minmax, 2); + if (ParseGridTrackBreadth(func->Item(1)) && + ExpectSymbol(',', true) && + ParseGridTrackBreadth(func->Item(2)) && + ExpectSymbol(')', true)) { + return true; + } + SkipUntil(')'); + return false; +} + +bool +CSSParserImpl::ParseGridTrackList(nsCSSProperty aPropID) +{ + nsCSSValue value; + if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { + AppendValue(aPropID, value); + return true; + } + // FIXME: add subgrid + + // |value| will be a list of odd length >= 3, + // starting with a (which is itself a list) + // and alternating between that and + nsCSSValueList* item = value.SetListValue(); + if (!ParseGridLineNames(item->mValue)) { + return false; + } + do { + item->mNext = new nsCSSValueList; + item = item->mNext; + // FIXME: add repeat() + if (!ParseGridTrackSize(item->mValue)) { + return false; + } + item->mNext = new nsCSSValueList; + item = item->mNext; + if (!ParseGridLineNames(item->mValue)) { + return false; + } + } while (!CheckEndProperty()); + MOZ_ASSERT(value.GetListValue() && value.GetListValue()->mNext && + value.GetListValue()->mNext->mNext, + " should have a minimum length of 3"); + AppendValue(aPropID, value); + return true; +} + // : [ | ]? bool CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient) @@ -7822,6 +8013,9 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID) return ParseFlexFlow(); case eCSSProperty_font: return ParseFont(); + case eCSSProperty_grid_template_columns: + case eCSSProperty_grid_template_rows: + return ParseGridTrackList(aPropID); case eCSSProperty_image_region: return ParseRect(eCSSProperty_image_region); case eCSSProperty_list_style: @@ -9799,6 +9993,10 @@ CSSParserImpl::ParseContent() bool CSSParserImpl::ParseCounterData(nsCSSProperty aPropID) { + static const nsCSSKeyword kCounterDataKTable[] = { + eCSSKeyword_none, + eCSSKeyword_UNKNOWN + }; nsCSSValue value; if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { if (!GetToken(true) || mToken.mType != eCSSToken_Ident) { @@ -9807,17 +10005,9 @@ CSSParserImpl::ParseCounterData(nsCSSProperty aPropID) nsCSSValuePairList *cur = value.SetPairListValue(); for (;;) { - // check for "none", "default" and the CSS-wide keywords, - // which can't be used as counter names - nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); - if (keyword == eCSSKeyword_inherit || - keyword == eCSSKeyword_default || - keyword == eCSSKeyword_none || - keyword == eCSSKeyword_unset || - keyword == eCSSKeyword_initial) { + if (!ParseCustomIdent(cur->mXValue, mToken.mIdent, kCounterDataKTable)) { return false; } - cur->mXValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident); if (!GetToken(true)) { break; } diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index 6e597cc8873..59871609931 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -2008,6 +2008,30 @@ CSS_PROP_UIRESET( nullptr, CSS_PROP_NO_OFFSET, eStyleAnimType_None) // bug 58646 +CSS_PROP_POSITION( + grid-template-columns, + grid_template_columns, + GridTemplateColumns, + CSS_PROPERTY_PARSE_FUNCTION | + CSS_PROPERTY_STORES_CALC | + CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, + "layout.css.grid.enabled", + 0, + kGridTrackBreadthKTable, + CSS_PROP_NO_OFFSET, + eStyleAnimType_None) +CSS_PROP_POSITION( + grid-template-rows, + grid_template_rows, + GridTemplateRows, + CSS_PROPERTY_PARSE_FUNCTION | + CSS_PROPERTY_STORES_CALC | + CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH, + "layout.css.grid.enabled", + 0, + kGridTrackBreadthKTable, + CSS_PROP_NO_OFFSET, + eStyleAnimType_None) CSS_PROP_POSITION( height, height, diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index d9e8edcd51b..49af2f069be 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -1251,6 +1251,12 @@ const KTableValue nsCSSProps::kFontWeightKTable[] = { eCSSKeyword_UNKNOWN,-1 }; +const KTableValue nsCSSProps::kGridTrackBreadthKTable[] = { + eCSSKeyword_min_content, NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT, + eCSSKeyword_max_content, NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT, + eCSSKeyword_UNKNOWN,-1 +}; + const KTableValue nsCSSProps::kImageOrientationKTable[] = { eCSSKeyword_flip, NS_STYLE_IMAGE_ORIENTATION_FLIP, eCSSKeyword_from_image, NS_STYLE_IMAGE_ORIENTATION_FROM_IMAGE, diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index 734cd655710..b0f9a265921 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -572,6 +572,7 @@ public: static const KTableValue kFontVariantNumericKTable[]; static const KTableValue kFontVariantPositionKTable[]; static const KTableValue kFontWeightKTable[]; + static const KTableValue kGridTrackBreadthKTable[]; static const KTableValue kImageOrientationKTable[]; static const KTableValue kImageOrientationFlipKTable[]; static const KTableValue kIMEModeKTable[]; diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index 5cb313f8c61..c78f29098db 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -1398,6 +1398,8 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult, case eCSSUnit_Seconds: aResult.Append(char16_t('s')); break; case eCSSUnit_Milliseconds: aResult.AppendLiteral("ms"); break; + + case eCSSUnit_FlexFraction: aResult.AppendLiteral("fr"); break; } } @@ -1554,6 +1556,7 @@ nsCSSValue::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const case eCSSUnit_Kilohertz: case eCSSUnit_Seconds: case eCSSUnit_Milliseconds: + case eCSSUnit_FlexFraction: break; default: @@ -1594,11 +1597,11 @@ nsCSSValueList::CloneInto(nsCSSValueList* aList) const aList->mNext = mNext ? mNext->Clone() : nullptr; } -void -nsCSSValueList::AppendToString(nsCSSProperty aProperty, nsAString& aResult, - nsCSSValue::Serialization aSerialization) const +static void +AppendValueListToString(const nsCSSValueList* val, + nsCSSProperty aProperty, nsAString& aResult, + nsCSSValue::Serialization aSerialization) { - const nsCSSValueList* val = this; for (;;) { val->mValue.AppendToString(aProperty, aResult, aSerialization); val = val->mNext; @@ -1612,6 +1615,55 @@ nsCSSValueList::AppendToString(nsCSSProperty aProperty, nsAString& aResult, } } +static void +AppendGridTemplateToString(const nsCSSValueList* val, + nsCSSProperty aProperty, nsAString& aResult, + nsCSSValue::Serialization aSerialization) +{ + // This is called for the "list" that's the top-level value of the property. + for (;;) { + bool addSpaceSpearator = true; + nsCSSUnit unit = val->mValue.GetUnit(); + + if (unit == eCSSUnit_Null) { + // Empty or omitted . Serializes to nothing. + addSpaceSpearator = false; // Avoid a double space. + + } else if (unit == eCSSUnit_List || unit == eCSSUnit_ListDep) { + // Non-empty + aResult.AppendLiteral("("); + AppendValueListToString(val->mValue.GetListValue(), aProperty, + aResult, aSerialization); + aResult.AppendLiteral(")"); + + } else { + // + val->mValue.AppendToString(aProperty, aResult, aSerialization); + } + + val = val->mNext; + if (!val) { + break; + } + + if (addSpaceSpearator) { + aResult.Append(char16_t(' ')); + } + } +} + +void +nsCSSValueList::AppendToString(nsCSSProperty aProperty, nsAString& aResult, + nsCSSValue::Serialization aSerialization) const +{ + if (aProperty == eCSSProperty_grid_template_columns || + aProperty == eCSSProperty_grid_template_rows) { + AppendGridTemplateToString(this, aProperty, aResult, aSerialization); + } else { + AppendValueListToString(this, aProperty, aResult, aSerialization); + } +} + bool nsCSSValueList::operator==(const nsCSSValueList& aOther) const { diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index 4e9af5429b1..5b94fb11ca8 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -258,7 +258,10 @@ enum nsCSSUnit { // Time units eCSSUnit_Seconds = 3000, // (float) Standard time - eCSSUnit_Milliseconds = 3001 // (float) 1/1000 second + eCSSUnit_Milliseconds = 3001, // (float) 1/1000 second + + // Flexible fraction (CSS Grid) + eCSSUnit_FlexFraction = 4000 // (float) Fraction of free space }; struct nsCSSValueGradient; diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 1d2ae6f58c5..d0003e3a118 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -2271,6 +2271,106 @@ nsComputedDOMStyle::DoGetBackgroundSize() return valueList; } +// aLineNames must not be empty +CSSValue* +nsComputedDOMStyle::GetGridLineNames(const nsTArray& aLineNames) +{ + nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; + nsAutoString lineNamesString; + uint32_t i_end = aLineNames.Length(); + MOZ_ASSERT(i_end > 0, "GetGridLineNames called with an empty array"); + lineNamesString.AssignLiteral("("); + for (uint32_t i = 0;;) { + nsStyleUtil::AppendEscapedCSSIdent(aLineNames[i], lineNamesString); + if (++i == i_end) { + break; + } + lineNamesString.AppendLiteral(" "); + } + lineNamesString.AppendLiteral(")"); + val->SetString(lineNamesString); + return val; +} + +CSSValue* +nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue, + const nsStyleCoord& aMaxValue) +{ + // FIXME bug 978212: If we have frame, every should + // be resolved into 'px' here, based on layout results. + if (aMinValue == aMaxValue) { + nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; + SetValueToCoord(val, aMinValue, true, + nullptr, nsCSSProps::kGridTrackBreadthKTable); + return val; + } + + nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; + nsAutoString argumentStr, minmaxStr; + minmaxStr.AppendLiteral("minmax("); + + SetValueToCoord(val, aMinValue, true, + nullptr, nsCSSProps::kGridTrackBreadthKTable); + val->GetCssText(argumentStr); + minmaxStr.Append(argumentStr); + + minmaxStr.AppendLiteral(", "); + + SetValueToCoord(val, aMaxValue, true, + nullptr, nsCSSProps::kGridTrackBreadthKTable); + val->GetCssText(argumentStr); + minmaxStr.Append(argumentStr); + + minmaxStr.Append(char16_t(')')); + val->SetString(minmaxStr); + return val; +} + +CSSValue* +nsComputedDOMStyle::GetGridTrackList(const nsStyleGridTrackList& aTrackList) +{ + uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length(); + MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes, + "Different number of min and max track sizing functions"); + // An empty is represented as "none" in syntax. + if (numSizes == 0) { + nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; + val->SetIdent(eCSSKeyword_none); + return val; + } + + nsDOMCSSValueList* valueList = GetROCSSValueList(false); + // Delimiting N tracks requires N+1 lines: + // one before each track, plus one at the very end. + MOZ_ASSERT(aTrackList.mLineNameLists.Length() == numSizes + 1, + "Unexpected number of line name lists"); + for (uint32_t i = 0;; i++) { + const nsTArray& lineNames = aTrackList.mLineNameLists[i]; + if (!lineNames.IsEmpty()) { + valueList->AppendCSSValue(GetGridLineNames(aTrackList.mLineNameLists[i])); + } + if (i == numSizes) { + break; + } + valueList->AppendCSSValue(GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i], + aTrackList.mMaxTrackSizingFunctions[i])); + } + + return valueList; +} + +CSSValue* +nsComputedDOMStyle::DoGetGridTemplateColumns() +{ + return GetGridTrackList(StylePosition()->mGridTemplateColumns); +} + +CSSValue* +nsComputedDOMStyle::DoGetGridTemplateRows() +{ + return GetGridTrackList(StylePosition()->mGridTemplateRows); +} + CSSValue* nsComputedDOMStyle::DoGetPaddingTop() { @@ -4402,6 +4502,14 @@ nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue, aValue->SetTurn(aCoord.GetAngleValue()); break; + case eStyleUnit_FlexFraction: { + nsAutoString tmpStr; + nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr); + tmpStr.AppendLiteral("fr"); + aValue->SetString(tmpStr); + break; + } + default: NS_ERROR("Can't handle this unit"); break; diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index d5662dc9a27..78e85d765cc 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -189,6 +189,11 @@ private: mozilla::dom::CSSValue* GetSVGPaintFor(bool aFill); + mozilla::dom::CSSValue* GetGridLineNames(const nsTArray& aLineNames); + mozilla::dom::CSSValue* GetGridTrackSize(const nsStyleCoord& aMinSize, + const nsStyleCoord& aMaxSize); + mozilla::dom::CSSValue* GetGridTrackList(const nsStyleGridTrackList& aTrackList); + bool GetLineHeightCoord(nscoord& aCoord); mozilla::dom::CSSValue* GetCSSShadowArray(nsCSSShadowArray* aArray, @@ -257,6 +262,10 @@ private: mozilla::dom::CSSValue* DoGetFontVariantPosition(); mozilla::dom::CSSValue* DoGetFontWeight(); + /* Grid properties */ + mozilla::dom::CSSValue* DoGetGridTemplateColumns(); + mozilla::dom::CSSValue* DoGetGridTemplateRows(); + /* Background properties */ mozilla::dom::CSSValue* DoGetBackgroundAttachment(); mozilla::dom::CSSValue* DoGetBackgroundColor(); diff --git a/layout/style/nsComputedDOMStylePropertyList.h b/layout/style/nsComputedDOMStylePropertyList.h index f6190f2d558..2caba165e8d 100644 --- a/layout/style/nsComputedDOMStylePropertyList.h +++ b/layout/style/nsComputedDOMStylePropertyList.h @@ -130,6 +130,8 @@ 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_columns, GridTemplateColumns) +COMPUTED_STYLE_PROP(grid_template_rows, GridTemplateRows) COMPUTED_STYLE_PROP(height, Height) COMPUTED_STYLE_PROP(image_orientation, ImageOrientation) COMPUTED_STYLE_PROP(ime_mode, IMEMode) diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 9c054dbc15e..989efbf502f 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -683,7 +683,8 @@ GetFloatFromBoxPosition(int32_t aEnumValue) #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT) #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT) #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH) -#define SETCOORD_LPEH (SETCOORD_LP | SETCOORD_ENUMERATED | SETCOORD_INHERIT) +#define SETCOORD_LPE (SETCOORD_LP | SETCOORD_ENUMERATED) +#define SETCOORD_LPEH (SETCOORD_LPE | SETCOORD_INHERIT) #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED) #define SETCOORD_LPO (SETCOORD_LP | SETCOORD_NONE) #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE) @@ -7062,6 +7063,120 @@ nsRuleNode::ComputeListData(void* aStartStruct, COMPUTE_END_INHERITED(List, list) } +static void +SetGridTrackBreadth(const nsCSSValue& aValue, + nsStyleCoord& aResult, + nsStyleContext* aStyleContext, + nsPresContext* aPresContext, + bool& aCanStoreInRuleTree) +{ + nsCSSUnit unit = aValue.GetUnit(); + if (unit == eCSSUnit_FlexFraction) { + aResult.SetFlexFractionValue(aValue.GetFloatValue()); + } else { + MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset, + "Unexpected value that would use dummyParentCoord"); + const nsStyleCoord dummyParentCoord; + SetCoord(aValue, aResult, dummyParentCoord, + SETCOORD_LPE | SETCOORD_STORE_CALC, + aStyleContext, aPresContext, aCanStoreInRuleTree); + } +} + +static void +SetGridTrackList(const nsCSSValue& aValue, + nsStyleGridTrackList& aResult, + const nsStyleGridTrackList& aParentValue, + nsStyleContext* aStyleContext, + nsPresContext* aPresContext, + bool& aCanStoreInRuleTree) + +{ + switch (aValue.GetUnit()) { + case eCSSUnit_Null: + break; + + case eCSSUnit_Inherit: + aCanStoreInRuleTree = false; + aResult.mLineNameLists = aParentValue.mLineNameLists; + aResult.mMinTrackSizingFunctions = aParentValue.mMinTrackSizingFunctions; + aResult.mMaxTrackSizingFunctions = aParentValue.mMaxTrackSizingFunctions; + break; + + case eCSSUnit_Initial: + case eCSSUnit_Unset: + case eCSSUnit_None: + aResult.mLineNameLists.Clear(); + aResult.mMinTrackSizingFunctions.Clear(); + aResult.mMaxTrackSizingFunctions.Clear(); + break; + + default: + aResult.mLineNameLists.Clear(); + aResult.mMinTrackSizingFunctions.Clear(); + aResult.mMaxTrackSizingFunctions.Clear(); + // This list is expected to have odd number of items, at least 3 + // starting with a (sub list of identifiers), + // and alternating between that and . + const nsCSSValueList* item = aValue.GetListValue(); + for (;;) { + // Compute a value + nsTArray* nameList = aResult.mLineNameLists.AppendElement(); + // Null unit means empty list, nothing more to do. + if (item->mValue.GetUnit() != eCSSUnit_Null) { + const nsCSSValueList* subItem = item->mValue.GetListValue(); + do { + nsString* name = nameList->AppendElement(); + subItem->mValue.GetStringValue(*name); + subItem = subItem->mNext; + } while (subItem); + } + item = item->mNext; + + if (!item) { + break; + } + + // Compute a value + nsStyleCoord minSizingFunction; + nsStyleCoord maxSizingFunction; + if (item->mValue.GetUnit() == eCSSUnit_Function) { + // A minmax() function. + nsCSSValue::Array* func = item->mValue.GetArrayValue(); + NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax, + "Expected minmax(), got another function name."); + SetGridTrackBreadth(func->Item(1), minSizingFunction, + aStyleContext, aPresContext, aCanStoreInRuleTree); + SetGridTrackBreadth(func->Item(2), maxSizingFunction, + aStyleContext, aPresContext, aCanStoreInRuleTree); + } else if (item->mValue.GetUnit() == eCSSUnit_Auto) { + // 'auto' computes to 'minmax(min-content, max-content)' + minSizingFunction.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT, + eStyleUnit_Enumerated); + maxSizingFunction.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT, + eStyleUnit_Enumerated); + } else { + // A single , + // specifies identical min and max sizing functions. + SetGridTrackBreadth(item->mValue, minSizingFunction, + aStyleContext, aPresContext, aCanStoreInRuleTree); + maxSizingFunction = minSizingFunction; + } + + aResult.mMinTrackSizingFunctions.AppendElement(minSizingFunction); + aResult.mMaxTrackSizingFunctions.AppendElement(maxSizingFunction); + item = item->mNext; + MOZ_ASSERT(item, "Expected a eCSSUnit_List of odd length"); + } + MOZ_ASSERT(!aResult.mMinTrackSizingFunctions.IsEmpty() && + aResult.mMinTrackSizingFunctions.Length() == + aResult.mMaxTrackSizingFunctions.Length() && + aResult.mMinTrackSizingFunctions.Length() + 1 == + aResult.mLineNameLists.Length(), + "Inconstistent array lengths for nsStyleGridTrackList"); + } +} + const void* nsRuleNode::ComputePositionData(void* aStartStruct, const nsRuleData* aRuleData, @@ -7235,6 +7350,16 @@ nsRuleNode::ComputePositionData(void* aStartStruct, parentPos->mJustifyContent, NS_STYLE_JUSTIFY_CONTENT_FLEX_START, 0, 0, 0, 0); + // grid-template-columns + SetGridTrackList(*aRuleData->ValueForGridTemplateColumns(), + pos->mGridTemplateColumns, parentPos->mGridTemplateColumns, + aContext, mPresContext, canStoreInRuleTree); + + // grid-template-rows + SetGridTrackList(*aRuleData->ValueForGridTemplateRows(), + pos->mGridTemplateRows, parentPos->mGridTemplateRows, + aContext, mPresContext, canStoreInRuleTree); + // z-index const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex(); if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex, diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index c007cb23617..7da3127aac8 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -539,6 +539,10 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) { #define NS_STYLE_FONT_LIST 15 #define NS_STYLE_FONT_FIELD 16 +// CSS Grid keywords +#define NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT 1 +#define NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT 2 + // defaults per MathML spec #define NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER 0.71f #define NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT 8 diff --git a/layout/style/nsStyleCoord.cpp b/layout/style/nsStyleCoord.cpp index 407ddaa02ca..d72b5e89ae2 100644 --- a/layout/style/nsStyleCoord.cpp +++ b/layout/style/nsStyleCoord.cpp @@ -63,6 +63,7 @@ bool nsStyleCoord::operator==(const nsStyleCoord& aOther) const case eStyleUnit_Grad: case eStyleUnit_Radian: case eStyleUnit_Turn: + case eStyleUnit_FlexFraction: return mValue.mFloat == aOther.mValue.mFloat; case eStyleUnit_Coord: case eStyleUnit_Integer: @@ -91,6 +92,7 @@ uint32_t nsStyleCoord::HashValue(uint32_t aHash = 0) const case eStyleUnit_Grad: case eStyleUnit_Radian: case eStyleUnit_Turn: + case eStyleUnit_FlexFraction: return mozilla::AddToHash(aHash, mValue.mFloat); case eStyleUnit_Coord: case eStyleUnit_Integer: @@ -160,6 +162,12 @@ void nsStyleCoord::SetAngleValue(float aValue, nsStyleUnit aUnit) } } +void nsStyleCoord::SetFlexFractionValue(float aValue) +{ + mUnit = eStyleUnit_FlexFraction; + mValue.mFloat = aValue; +} + void nsStyleCoord::SetCalcValue(Calc* aValue) { mUnit = eStyleUnit_Calc; diff --git a/layout/style/nsStyleCoord.h b/layout/style/nsStyleCoord.h index 2d825c1cdfa..46cab4aac03 100644 --- a/layout/style/nsStyleCoord.h +++ b/layout/style/nsStyleCoord.h @@ -22,6 +22,7 @@ enum nsStyleUnit { eStyleUnit_Grad = 13, // (float) angle in grads eStyleUnit_Radian = 14, // (float) angle in radians eStyleUnit_Turn = 15, // (float) angle in turns + eStyleUnit_FlexFraction = 16, // (float) in fr units eStyleUnit_Coord = 20, // (nscoord) value is twips eStyleUnit_Integer = 30, // (int) value is simple integer eStyleUnit_Enumerated = 32, // (int) value has enumerated meaning @@ -129,6 +130,7 @@ public: float GetFactorValue() const; float GetAngleValue() const; double GetAngleValueInRadians() const; + float GetFlexFractionValue() const; Calc* GetCalcValue() const; void GetUnionValue(nsStyleUnion& aValue) const; uint32_t HashValue(uint32_t aHash) const; @@ -139,6 +141,7 @@ public: void SetPercentValue(float aValue); void SetFactorValue(float aValue); void SetAngleValue(float aValue, nsStyleUnit aUnit); + void SetFlexFractionValue(float aValue); void SetNormalValue(); void SetAutoValue(); void SetNoneValue(); @@ -300,6 +303,15 @@ inline float nsStyleCoord::GetAngleValue() const return 0.0f; } +inline float nsStyleCoord::GetFlexFractionValue() const +{ + NS_ASSERTION(mUnit == eStyleUnit_FlexFraction, "not a fr value"); + if (mUnit == eStyleUnit_FlexFraction) { + return mValue.mFloat; + } + return 0.0f; +} + inline nsStyleCoord::Calc* nsStyleCoord::GetCalcValue() const { NS_ASSERTION(IsCalcUnit(), "not a pointer value"); diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 40c61a70ffc..48cfe090e5e 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1212,8 +1212,8 @@ bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const // -------------------- // nsStylePosition // -nsStylePosition::nsStylePosition(void) -{ +nsStylePosition::nsStylePosition(void) +{ MOZ_COUNT_CTOR(nsStylePosition); // positioning values not inherited nsStyleCoord autoCoord(eStyleUnit_Auto); @@ -1239,17 +1239,34 @@ 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 property’s initial value 'none' } -nsStylePosition::~nsStylePosition(void) -{ +nsStylePosition::~nsStylePosition(void) +{ MOZ_COUNT_DTOR(nsStylePosition); } nsStylePosition::nsStylePosition(const nsStylePosition& aSource) + : mGridTemplateColumns(aSource.mGridTemplateColumns) + , mGridTemplateRows(aSource.mGridTemplateRows) { MOZ_COUNT_CTOR(nsStylePosition); - memcpy((nsStylePosition*)this, &aSource, sizeof(nsStylePosition)); + // If you add any memcpy'able member vars, + // they should be declared before mGridTemplateColumns. + // If you add any non-memcpy'able member vars, + // they should be declared after mGridTemplateColumns, + // and you should invoke their copy constructor in the init list above + // and update this static-assert to include their "sizeof()" + static_assert(sizeof(nsStylePosition) == + offsetof(nsStylePosition, mGridTemplateColumns) + + sizeof(mGridTemplateColumns) + sizeof(mGridTemplateRows), + "Unexpected size or offset in nsStylePosition"); + memcpy((nsStylePosition*) this, + &aSource, + offsetof(nsStylePosition, mGridTemplateColumns)); } static bool @@ -1299,6 +1316,13 @@ nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) cons } + // Properties that apply to grid containers: + if (mGridTemplateColumns != aOther.mGridTemplateColumns || + mGridTemplateRows != aOther.mGridTemplateRows) { + return NS_CombineHint(hint, nsChangeHint_AllReflowHints); + } + + // Changing justify-content on a flexbox might affect the positioning of its // children, but it won't affect any sizing. if (mJustifyContent != aOther.mJustifyContent) { diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 8e722fa57c9..80a3371ef18 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1152,6 +1152,38 @@ public: nsRect mImageRegion; // [inherited] the rect to use within an image }; +struct nsStyleGridTrackList { + // http://dev.w3.org/csswg/css-grid/#track-sizing + // This represents either: + // * 'none': all three arrays are empty + // * A : mMinTrackSizingFunctions and mMaxTrackSizingFunctions + // are of identical non-zero size, + // and mLineNameLists is one element longer than that. + // (Delimiting N columns requires N+1 lines: + // one before each track, plus one at the very end.) + // + // An omitted is still represented in mLineNameLists, + // as an empty sub-array. + // + // A specified as a single is represented + // as identical min and max sizing functions. + // + // The units for nsStyleCoord are: + // * eStyleUnit_Percent represents a + // * eStyleUnit_FlexFraction represents a flexible fraction + // * eStyleUnit_Coord represents a + // * eStyleUnit_Enumerated represents min-content or max-content + nsTArray> mLineNameLists; + nsTArray mMinTrackSizingFunctions; + nsTArray mMaxTrackSizingFunctions; + + inline bool operator!=(const nsStyleGridTrackList& aOther) const { + return mLineNameLists != aOther.mLineNameLists || + mMinTrackSizingFunctions != aOther.mMinTrackSizingFunctions || + mMaxTrackSizingFunctions != aOther.mMaxTrackSizingFunctions; + } +}; + struct nsStylePosition { nsStylePosition(void); nsStylePosition(const nsStylePosition& aOther); @@ -1196,6 +1228,12 @@ struct nsStylePosition { float mFlexGrow; // [reset] float float mFlexShrink; // [reset] float nsStyleCoord mZIndex; // [reset] integer, auto + // NOTE: Fields so far can be memcpy()'ed, while following fields + // need to have their copy constructor called when we're being copied. + // See nsStylePosition::nsStylePosition(const nsStylePosition& aSource) + // in nsStyleStruct.cpp + nsStyleGridTrackList mGridTemplateColumns; + nsStyleGridTrackList mGridTemplateRows; bool WidthDependsOnContainer() const { return WidthCoordDependsOnContainer(mWidth); } diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index cdee88cf691..ae1d2ed0d39 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -4792,6 +4792,64 @@ if (SpecialPowers.getBoolPref("layout.css.filters.enabled")) { if (SpecialPowers.getBoolPref("layout.css.grid.enabled")) { gCSSProperties["display"].other_values.push("grid", "inline-grid"); + gCSSProperties["grid-template-columns"] = { + domProp: "gridTemplateColumns", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "none" ], + other_values: [ + "auto", + "40px", + "2.5fr", + "(normal) 40px () auto ( ) 12%", + "(foo) 40px min-content ( bar ) calc(20px + 10%) max-content", + "40px min-content calc(20px + 10%) max-content", + "m\\69nmax(20px, 4Fr)", + "40px MinMax(min-content, calc(20px + 10%)) max-content", + "40px 2em", + "() 40px (-foo) 2em (bar baz This\ is\ one\ ident)", + // TODO bug 978478: "(a) repeat(3, (b) 20px (c) 40px (d)) (e)", + + // See https://bugzilla.mozilla.org/show_bug.cgi?id=981300 + "(none auto subgrid min-content max-content foo) 40px", + ], + invalid_values: [ + "", + "normal", + "40ms", + "-40px", + "-12%", + "-2fr", + "(foo)", + "(inherit) 40px", + "(initial) 40px", + "(unset) 40px", + "(default) 40px", + "(6%) 40px", + "(5th) 40px", + "(foo() bar) 40px", + "(foo)) 40px", + "(foo] 40px", + "[foo] 40px", + "(foo) (bar) 40px", + "40px (foo) (bar)", + "minmax()", + "minmax(20px)", + "mİnmax(20px, 100px)", + "minmax(20px, 100px, 200px)", + "maxmin(100px, 20px)", + "minmax(min-content, auto)", + "minmax(min-content, minmax(30px, max-content))", + ] + }; + gCSSProperties["grid-template-rows"] = { + domProp: "gridTemplateRows", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: gCSSProperties["grid-template-columns"].initial_values, + other_values: gCSSProperties["grid-template-columns"].other_values, + invalid_values: gCSSProperties["grid-template-columns"].invalid_values + }; } if (SpecialPowers.getBoolPref("layout.css.image-orientation.enabled")) {