Bug 1289007 - part1: parse and compute initial-letter property.
MozReview-Commit-ID: E0eXolZ93oJ
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -839,16 +839,17 @@ PropertySupportsVariant(nsCSSProperty aP
supported = VARIANT_URL;
break;
case eCSSProperty_grid_column_start:
case eCSSProperty_grid_column_end:
case eCSSProperty_grid_row_start:
case eCSSProperty_grid_row_end:
case eCSSProperty_font_weight:
+ case eCSSProperty_initial_letter:
supported = VARIANT_NUMBER;
break;
default:
supported = 0;
break;
}
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -999,16 +999,18 @@ protected:
bool ParseGridShorthandAutoProps();
bool ParseGridLine(nsCSSValue& aValue);
bool ParseGridColumnRowStartEnd(nsCSSProperty aPropID);
bool ParseGridColumnRow(nsCSSProperty aStartPropID,
nsCSSProperty aEndPropID);
bool ParseGridArea();
bool ParseGridGap();
+ bool ParseInitialLetter();
+
// parsing 'align/justify-items/self' from the css-align spec
bool ParseAlignJustifyPosition(nsCSSValue& aResult,
const KTableEntry aTable[]);
bool ParseJustifyItems();
bool ParseAlignItems();
bool ParseAlignJustifySelf(nsCSSProperty aPropID);
// parsing 'align/justify-content' from the css-align spec
bool ParseAlignJustifyContent(nsCSSProperty aPropID);
@@ -1240,16 +1242,26 @@ protected:
{
return ParseSingleTokenNonNegativeVariant(aValue, VARIANT_INTEGER, nullptr);
}
bool ParseNonNegativeNumber(nsCSSValue& aValue)
{
return ParseSingleTokenNonNegativeVariant(aValue, VARIANT_NUMBER, nullptr);
}
+ // Helpers for some common ParseSingleTokenOneOrLargerVariant calls.
+ bool ParseOneOrLargerInteger(nsCSSValue& aValue)
+ {
+ return ParseSingleTokenOneOrLargerVariant(aValue, VARIANT_INTEGER, nullptr);
+ }
+ bool ParseOneOrLargerNumber(nsCSSValue& aValue)
+ {
+ return ParseSingleTokenOneOrLargerVariant(aValue, VARIANT_NUMBER, nullptr);
+ }
+
// 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
@@ -9774,16 +9786,43 @@ CSSParserImpl::ParseGridGap()
return false;
}
AppendValue(eCSSProperty_grid_row_gap, first);
AppendValue(eCSSProperty_grid_column_gap,
result == CSSParseResult::NotFound ? first : second);
return true;
}
+// normal | [<number> <integer>?]
+bool
+CSSParserImpl::ParseInitialLetter()
+{
+ nsCSSValue value;
+ // 'inherit', 'initial', 'unset', 'none', and 'normal' must be alone
+ if (!ParseSingleTokenVariant(value, VARIANT_INHERIT | VARIANT_NORMAL,
+ nullptr)) {
+ nsCSSValue first, second;
+ if (!ParseOneOrLargerNumber(first)) {
+ return false;
+ }
+
+ if (!ParseOneOrLargerInteger(second)) {
+ AppendValue(eCSSProperty_initial_letter, first);
+ return true;
+ } else {
+ RefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(2);
+ val->Item(0) = first;
+ val->Item(1) = second;
+ value.SetArrayValue(val, eCSSUnit_Array);
+ }
+ }
+ AppendValue(eCSSProperty_initial_letter, value);
+ return true;
+}
+
// [ $aTable && <overflow-position>? ] ?
// $aTable is for <content-position> or <self-position>
bool
CSSParserImpl::ParseAlignJustifyPosition(nsCSSValue& aResult,
const KTableEntry aTable[])
{
nsCSSValue pos, overflowPos;
int32_t value = 0;
@@ -11565,16 +11604,18 @@ CSSParserImpl::ParsePropertyByFunction(n
case eCSSProperty_align_content:
case eCSSProperty_justify_content:
return ParseAlignJustifyContent(aPropID);
case eCSSProperty_align_items:
return ParseAlignItems();
case eCSSProperty_align_self:
case eCSSProperty_justify_self:
return ParseAlignJustifySelf(aPropID);
+ case eCSSProperty_initial_letter:
+ return ParseInitialLetter();
case eCSSProperty_justify_items:
return ParseJustifyItems();
case eCSSProperty_list_style:
return ParseListStyle();
case eCSSProperty_margin:
return ParseMargin();
case eCSSProperty_object_position:
return ParseObjectPosition();
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2263,16 +2263,27 @@ CSS_PROP_TEXT(
hyphens,
Hyphens,
CSS_PROPERTY_PARSE_VALUE,
"",
VARIANT_HK,
kHyphensKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
+CSS_PROP_TEXTRESET(
+ initial-letter,
+ initial_letter,
+ InitialLetter,
+ CSS_PROPERTY_PARSE_FUNCTION |
+ CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
+ "layout.css.initial-letter.enabled",
+ 0,
+ nullptr,
+ CSS_PROP_NO_OFFSET,
+ eStyleAnimType_None)
CSS_PROP_VISIBILITY(
image-orientation,
image_orientation,
ImageOrientation,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_VALUE_PARSER_FUNCTION,
"layout.css.image-orientation.enabled",
0,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3539,16 +3539,35 @@ nsComputedDOMStyle::DoGetImageRegion()
leftVal->SetAppUnits(list->mImageRegion.x);
val->SetRect(domRect);
}
return val.forget();
}
already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetInitialLetter()
+{
+ const nsStyleTextReset* textReset = StyleTextReset();
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ if (textReset->mInitialLetterSink == 0) {
+ val->SetIdent(eCSSKeyword_normal);
+ return val.forget();
+ } else {
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ val->SetNumber(textReset->mInitialLetterSize);
+ valueList->AppendCSSValue(val.forget());
+ RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
+ second->SetNumber(textReset->mInitialLetterSink);
+ valueList->AppendCSSValue(second.forget());
+ return valueList.forget();
+ }
+}
+
+already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetLineHeight()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
nscoord lineHeight;
if (GetLineHeightCoord(lineHeight)) {
val->SetAppUnits(lineHeight);
} else {
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -399,16 +399,17 @@ private:
/* List properties */
already_AddRefed<CSSValue> DoGetListStyleImage();
already_AddRefed<CSSValue> DoGetListStylePosition();
already_AddRefed<CSSValue> DoGetListStyleType();
already_AddRefed<CSSValue> DoGetImageRegion();
/* Text Properties */
+ already_AddRefed<CSSValue> DoGetInitialLetter();
already_AddRefed<CSSValue> DoGetLineHeight();
already_AddRefed<CSSValue> DoGetRubyAlign();
already_AddRefed<CSSValue> DoGetRubyPosition();
already_AddRefed<CSSValue> DoGetTextAlign();
already_AddRefed<CSSValue> DoGetTextAlignLast();
already_AddRefed<CSSValue> DoGetTextCombineUpright();
already_AddRefed<CSSValue> DoGetTextDecoration();
already_AddRefed<CSSValue> DoGetTextDecorationColor();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -148,16 +148,17 @@ COMPUTED_STYLE_PROP(grid_row_gap,
COMPUTED_STYLE_PROP(grid_row_start, GridRowStart)
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)
COMPUTED_STYLE_PROP(hyphens, Hyphens)
COMPUTED_STYLE_PROP(image_orientation, ImageOrientation)
COMPUTED_STYLE_PROP(ime_mode, IMEMode)
+COMPUTED_STYLE_PROP(initial_letter, InitialLetter)
COMPUTED_STYLE_PROP(isolation, Isolation)
COMPUTED_STYLE_PROP(justify_content, JustifyContent)
COMPUTED_STYLE_PROP(justify_items, JustifyItems)
COMPUTED_STYLE_PROP(justify_self, JustifySelf)
COMPUTED_STYLE_PROP(left, Left)
COMPUTED_STYLE_PROP(letter_spacing, LetterSpacing)
COMPUTED_STYLE_PROP(line_height, LineHeight)
//// COMPUTED_STYLE_PROP(list_style, ListStyle)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -4972,16 +4972,46 @@ nsRuleNode::ComputeTextResetData(void* a
}
// unicode-bidi: enum, inherit, initial
SetValue(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, conditions,
SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
parentText->mUnicodeBidi,
NS_STYLE_UNICODE_BIDI_NORMAL);
+ // initial-letter: normal, number, array(number, integer?), initial
+ const nsCSSValue* initialLetterValue = aRuleData->ValueForInitialLetter();
+ if (initialLetterValue->GetUnit() == eCSSUnit_Null) {
+ // We don't want to change anything in this case.
+ } else if (initialLetterValue->GetUnit() == eCSSUnit_Inherit) {
+ conditions.SetUncacheable();
+ text->mInitialLetterSink = parentText->mInitialLetterSink;
+ text->mInitialLetterSize = parentText->mInitialLetterSize;
+ } else if (initialLetterValue->GetUnit() == eCSSUnit_Initial ||
+ initialLetterValue->GetUnit() == eCSSUnit_Unset ||
+ initialLetterValue->GetUnit() == eCSSUnit_Normal) {
+ // Use invalid values in initial-letter property to mean normal. So we can
+ // determine whether it is normal by checking mInitialLetterSink == 0.
+ text->mInitialLetterSink = 0;
+ text->mInitialLetterSize = 0.0f;
+ } else if (initialLetterValue->GetUnit() == eCSSUnit_Array) {
+ const nsCSSValue& firstValue = initialLetterValue->GetArrayValue()->Item(0);
+ const nsCSSValue& secondValue = initialLetterValue->GetArrayValue()->Item(1);
+ MOZ_ASSERT(firstValue.GetUnit() == eCSSUnit_Number &&
+ secondValue.GetUnit() == eCSSUnit_Integer,
+ "unexpected value unit");
+ text->mInitialLetterSize = firstValue.GetFloatValue();
+ text->mInitialLetterSink = secondValue.GetIntValue();
+ } else if (initialLetterValue->GetUnit() == eCSSUnit_Number) {
+ text->mInitialLetterSize = initialLetterValue->GetFloatValue();
+ text->mInitialLetterSink = NSToCoordFloorClamped(text->mInitialLetterSize);
+ } else {
+ MOZ_ASSERT_UNREACHABLE("unknown unit for initial-letter");
+ }
+
COMPUTE_END_RESET(TextReset, text)
}
const void*
nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
const nsRuleData* aRuleData,
nsStyleContext* aContext,
nsRuleNode* aHighestNode,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3571,16 +3571,18 @@ nsStyleContent::AllocateContents(uint32_
// --------------------
// nsStyleTextReset
//
nsStyleTextReset::nsStyleTextReset(StyleStructContext aContext)
: mTextDecorationLine(NS_STYLE_TEXT_DECORATION_LINE_NONE)
, mUnicodeBidi(NS_STYLE_UNICODE_BIDI_NORMAL)
+ , mInitialLetterSink(0)
+ , mInitialLetterSize(0.0f)
, mTextDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND)
, mTextDecorationColor(NS_RGB(0, 0, 0))
{
MOZ_COUNT_CTOR(nsStyleTextReset);
}
nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
{
@@ -3591,17 +3593,19 @@ nsStyleTextReset::nsStyleTextReset(const
nsStyleTextReset::~nsStyleTextReset()
{
MOZ_COUNT_DTOR(nsStyleTextReset);
}
nsChangeHint
nsStyleTextReset::CalcDifference(const nsStyleTextReset& aNewData) const
{
- if (mUnicodeBidi != aNewData.mUnicodeBidi) {
+ if (mUnicodeBidi != aNewData.mUnicodeBidi ||
+ mInitialLetterSink != aNewData.mInitialLetterSink ||
+ mInitialLetterSize != aNewData.mInitialLetterSize) {
return NS_STYLE_HINT_REFLOW;
}
uint8_t lineStyle = GetDecorationStyle();
uint8_t otherLineStyle = aNewData.GetDecorationStyle();
if (mTextDecorationLine != aNewData.mTextDecorationLine ||
lineStyle != otherLineStyle) {
// Changes to our text-decoration line can impact our overflow area &
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1972,16 +1972,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
nsChangeHint_ReflowChangesSizeOrPosition |
nsChangeHint_ClearAncestorIntrinsics;
}
nsStyleTextOverflow mTextOverflow; // [reset] enum, string
uint8_t mTextDecorationLine; // [reset] see nsStyleConsts.h
uint8_t mUnicodeBidi; // [reset] see nsStyleConsts.h
+ nscoord mInitialLetterSink; // [reset] 0 means normal
+ float mInitialLetterSize; // [reset] 0.0f means normal
protected:
uint8_t mTextDecorationStyle; // [reset] see nsStyleConsts.h
nscolor mTextDecorationColor; // [reset] the colors to use for a decoration lines, not used at currentColor
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
{
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -6656,16 +6656,27 @@ if (IsCSSPropertyPrefEnabled("layout.css
"0deg from-image",
"from-image 0deg",
"flip from-image",
"from-image flip",
]
};
}
+if (IsCSSPropertyPrefEnabled("layout.css.initial-letter.enabled")) {
+ gCSSProperties["initial-letter"] = {
+ domProp: "initialLetter",
+ inherited: false,
+ type: CSS_TYPE_LONGHAND,
+ initial_values: [ "normal" ],
+ other_values: [ "2", "2.5", "3.7 2", "4 3" ],
+ invalid_values: [ "-3", "3.7 -2", "25%", "16px", "1 0", "0", "0 1" ]
+ };
+}
+
if (IsCSSPropertyPrefEnabled("layout.css.osx-font-smoothing.enabled")) {
gCSSProperties["-moz-osx-font-smoothing"] = {
domProp: "MozOsxFontSmoothing",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "auto" ],
other_values: [ "grayscale" ],
invalid_values: [ "none", "subpixel-antialiased", "antialiased" ]
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2408,16 +2408,19 @@ pref("layout.css.visited_links_enabled",
pref("layout.css.dpi", -1);
// Set the number of device pixels per CSS pixel. A value <= 0 means choose
// automatically based on user settings for the platform (e.g., "UI scale factor"
// on Mac). A positive value is used as-is. This effectively controls the size
// of a CSS "px". This is only used for windows on the screen, not for printing.
pref("layout.css.devPixelsPerPx", "-1.0");
+// Is support for CSS initial-letter property enabled?
+pref("layout.css.initial-letter.enabled", false);
+
// Is support for CSS Masking features enabled?
pref("layout.css.masking.enabled", true);
// Is support for mix-blend-mode enabled?
pref("layout.css.mix-blend-mode.enabled", true);
// Is support for isolation enabled?
pref("layout.css.isolation.enabled", true);
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -158,16 +158,19 @@ user_pref("layout.css.report_errors", tr
// Enable CSS Grid for testing
user_pref("layout.css.grid.enabled", true);
user_pref("layout.css.grid-template-subgrid-value.enabled", true);
// Enable CSS 'contain' for testing
user_pref("layout.css.contain.enabled", true);
+// Enable CSS initial-letter for testing
+user_pref("layout.css.initial-letter.enabled", true);
+
// Enable CSS object-fit & object-position for testing
user_pref("layout.css.object-fit-and-position.enabled", true);
// Enable webkit prefixed CSS features for testing
user_pref("layout.css.prefixes.webkit", true);
// Enable -webkit-{min|max}-device-pixel-ratio media queries for testing
user_pref("layout.css.prefixes.device-pixel-ratio-webkit", true);