Bug 677582 - Implement CSS3 text-overflow: <left> <right> in the style system. r=dbaron
authorMats Palmgren <matspal@gmail.com>
Sat, 20 Aug 2011 22:41:39 +0200
changeset 75606 f700f4ef73b9ea8d2480c87934bc825dea6a5395
parent 75605 be2eb19328c43951d371e6761dcc8b043d5bb437
child 75607 0f6660f35a46c304de105d504453273354665b7e
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersdbaron
bugs677582
milestone9.0a1
Bug 677582 - Implement CSS3 text-overflow: <left> <right> in the style system. r=dbaron
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -508,16 +508,17 @@ protected:
   PRBool ParseMozTransform();
   PRBool ParseOutline();
   PRBool ParseOverflow();
   PRBool ParsePadding();
   PRBool ParseQuotes();
   PRBool ParseSize();
   PRBool ParseTextDecoration();
   PRBool ParseTextDecorationLine(nsCSSValue& aValue);
+  PRBool ParseTextOverflow(nsCSSValue& aValue);
 
   PRBool ParseShadowItem(nsCSSValue& aValue, PRBool aIsBoxShadow);
   PRBool ParseShadowList(nsCSSProperty aProperty);
   PRBool ParseTransitionProperty();
   PRBool ParseTransitionTimingFunctionValues(nsCSSValue& aValue);
   PRBool ParseTransitionTimingFunctionValueComponent(float& aComponent,
                                                      char aStop,
                                                      PRBool aCheckRange);
@@ -5596,16 +5597,18 @@ CSSParserImpl::ParseSingleValueProperty(
       case eCSSProperty_font_family:
         return ParseFamily(aValue);
       case eCSSProperty_font_weight:
         return ParseFontWeight(aValue);
       case eCSSProperty_marks:
         return ParseMarks(aValue);
       case eCSSProperty_text_decoration_line:
         return ParseTextDecorationLine(aValue);
+      case eCSSProperty_text_overflow:
+        return ParseTextOverflow(aValue);
       default:
         NS_ABORT_IF_FALSE(PR_FALSE, "should not reach here");
         return PR_FALSE;
     }
   }
 
   PRUint32 variant = nsCSSProps::ParserVariant(aPropID);
   if (variant == 0) {
@@ -8113,16 +8116,37 @@ CSSParserImpl::ParseTextDecorationLine(n
         aValue.SetIntValue(intValue, eCSSUnit_Enumerated);
       }
     }
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
+PRBool
+CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue)
+{
+  if (ParseVariant(aValue, VARIANT_INHERIT, nsnull)) {
+    // 'inherit' and 'initial' must be alone
+    return PR_TRUE;
+  }
+
+  nsCSSValue left;
+  if (!ParseVariant(left, VARIANT_KEYWORD | VARIANT_STRING,
+                    nsCSSProps::kTextOverflowKTable))
+    return PR_FALSE;
+
+  nsCSSValue right;
+  if (ParseVariant(right, VARIANT_KEYWORD | VARIANT_STRING,
+                    nsCSSProps::kTextOverflowKTable))
+    aValue.SetPairValue(left, right);
+  else
+    aValue.SetPairValue(left, left);
+  return PR_TRUE;
+}
 
 PRBool
 CSSParserImpl::ParseTransitionProperty()
 {
   nsCSSValue value;
   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE | VARIANT_ALL,
                    nsnull)) {
     // 'inherit', 'initial', 'none', and 'all' must be alone
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2206,18 +2206,19 @@ CSS_PROP_TEXT(
     VARIANT_HLP | VARIANT_CALC,
     nsnull,
     offsetof(nsStyleText, mTextIndent),
     eStyleAnimType_Coord)
 CSS_PROP_TEXTRESET(
     text-overflow,
     text_overflow,
     TextOverflow,
-    CSS_PROPERTY_PARSE_VALUE,
-    VARIANT_HK | VARIANT_STRING,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_VALUE_PARSER_FUNCTION,
+    0,
     kTextOverflowKTable,
     offsetof(nsStyleTextReset, mTextOverflow),
     eStyleAnimType_None)
 CSS_PROP_TEXT(
     text-shadow,
     text_shadow,
     TextShadow,
     CSS_PROPERTY_PARSE_FUNCTION |
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2444,29 +2444,45 @@ nsComputedDOMStyle::DoGetTextIndent()
   SetValueToCoord(val, GetStyleText()->mTextIndent, PR_FALSE,
                   &nsComputedDOMStyle::GetCBContentWidth);
   return val;
 }
 
 nsIDOMCSSValue*
 nsComputedDOMStyle::DoGetTextOverflow()
 {
-  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
   const nsStyleTextReset *style = GetStyleTextReset();
-
-  if (style->mTextOverflow.mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
+  nsROCSSPrimitiveValue *left = GetROCSSPrimitiveValue();
+  if (style->mTextOverflow.mLeft.mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
     nsString str;
-    nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mString, str);
-    val->SetString(str);
+    nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mLeft.mString, str);
+    left->SetString(str);
   } else {
-    val->SetIdent(
-      nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mType,
+    left->SetIdent(
+      nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mLeft.mType,
                                      nsCSSProps::kTextOverflowKTable));
   }
-  return val;
+  if (style->mTextOverflow.mLeft == style->mTextOverflow.mRight) {
+    return left;
+  }
+  nsROCSSPrimitiveValue *right = GetROCSSPrimitiveValue();
+  if (style->mTextOverflow.mRight.mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
+    nsString str;
+    nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mRight.mString, str);
+    right->SetString(str);
+  } else {
+    right->SetIdent(
+      nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mRight.mType,
+                                     nsCSSProps::kTextOverflowKTable));
+  }
+
+  nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
+  valueList->AppendCSSValue(left);
+  valueList->AppendCSSValue(right);
+  return valueList;
 }
 
 nsIDOMCSSValue*
 nsComputedDOMStyle::DoGetTextShadow()
 {
   return GetCSSShadowArray(GetStyleText()->mTextShadow,
                            GetStyleColor()->mColor,
                            PR_FALSE);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -3490,32 +3490,51 @@ nsRuleNode::ComputeTextResetData(void* a
     text->SetDecorationStyle(decorationStyleValue->GetIntValue());
   } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
     text->SetDecorationStyle(parentText->GetDecorationStyle());
     canStoreInRuleTree = PR_FALSE;
   } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit()) {
     text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
   }
 
-  // text-overflow: enum, string, inherit, initial
+  // text-overflow: pair(enum|string), inherit, initial
   const nsCSSValue* textOverflowValue =
     aRuleData->ValueForTextOverflow();
-  if (eCSSUnit_Enumerated == textOverflowValue->GetUnit() ||
-      eCSSUnit_Initial    == textOverflowValue->GetUnit()) {
-    SetDiscrete(*textOverflowValue, text->mTextOverflow.mType,
-                canStoreInRuleTree,
-                SETDSC_ENUMERATED, parentText->mTextOverflow.mType,
-                NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
-    text->mTextOverflow.mString.Truncate();
+  if (eCSSUnit_Initial == textOverflowValue->GetUnit()) {
+    text->mTextOverflow = nsStyleTextOverflow();
   } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
     canStoreInRuleTree = PR_FALSE;
     text->mTextOverflow = parentText->mTextOverflow;
-  } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
-    textOverflowValue->GetStringValue(text->mTextOverflow.mString);
-    text->mTextOverflow.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
+  } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
+    const nsCSSValuePair& textOverflowValue =
+      aRuleData->ValueForTextOverflow()->GetPairValue();
+
+    const nsCSSValue *textOverflowLeftValue = &textOverflowValue.mXValue;
+    if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
+      SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
+                  canStoreInRuleTree,
+                  SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
+                  NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
+      text->mTextOverflow.mLeft.mString.Truncate();
+    } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
+      textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
+      text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
+    }
+
+    const nsCSSValue *textOverflowRightValue = &textOverflowValue.mYValue;
+    if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
+      SetDiscrete(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
+                  canStoreInRuleTree,
+                  SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
+                  NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
+      text->mTextOverflow.mRight.mString.Truncate();
+    } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
+      textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
+      text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
+    }
   }
 
   // unicode-bidi: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
               SETDSC_ENUMERATED, parentText->mUnicodeBidi,
               NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
 
   COMPUTE_END_RESET(TextReset, text)
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1126,30 +1126,42 @@ private:
   static PRBool WidthCoordDependsOnContainer(const nsStyleCoord &aCoord);
   static PRBool HeightCoordDependsOnContainer(const nsStyleCoord &aCoord)
   {
     return aCoord.GetUnit() == eStyleUnit_Auto || // CSS 2.1, 10.6.4, item (5)
            aCoord.HasPercent();
   }
 };
 
-struct nsStyleTextOverflow {
-  nsStyleTextOverflow() : mType(NS_STYLE_TEXT_OVERFLOW_CLIP) {}
+struct nsStyleTextOverflowSide {
+  nsStyleTextOverflowSide() : mType(NS_STYLE_TEXT_OVERFLOW_CLIP) {}
 
-  bool operator==(const nsStyleTextOverflow& aOther) const {
+  bool operator==(const nsStyleTextOverflowSide& aOther) const {
     return mType == aOther.mType &&
            (mType != NS_STYLE_TEXT_OVERFLOW_STRING ||
             mString == aOther.mString);
   }
+  bool operator!=(const nsStyleTextOverflowSide& aOther) const {
+    return !(*this == aOther);
+  }
+
+  nsString mString;
+  PRUint8  mType;
+};
+
+struct nsStyleTextOverflow {
+  bool operator==(const nsStyleTextOverflow& aOther) const {
+    return mLeft == aOther.mLeft && mRight == aOther.mRight;
+  }
   bool operator!=(const nsStyleTextOverflow& aOther) const {
     return !(*this == aOther);
   }
 
-  nsString mString;
-  PRUint8  mType;
+  nsStyleTextOverflowSide mLeft;
+  nsStyleTextOverflowSide mRight;
 };
 
 struct nsStyleTextReset {
   nsStyleTextReset(void);
   nsStyleTextReset(const nsStyleTextReset& aOther);
   ~nsStyleTextReset(void);
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -2541,19 +2541,19 @@ var gCSSProperties = {
 			"-moz-calc(3*25px + 50%)",
 		],
 		invalid_values: []
 	},
 	"text-overflow": {
 		domProp: "textOverflow",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "clip" ],
-		other_values: [ "ellipsis", '""', "''", '"hello"' ],
-		invalid_values: [ "none", "auto" ]
+		initial_values: [ "clip", "clip clip" ],
+		other_values: [ "ellipsis", '""', "''", '"hello"', 'clip ellipsis', 'clip ""', '"hello" ""', '"" ellipsis' ],
+		invalid_values: [ "none", "auto", '"hello" inherit', 'inherit "hello"', 'clip initial', 'initial clip', 'initial inherit', 'inherit initial', 'inherit none']
 	},
 	"text-shadow": {
 		domProp: "textShadow",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		prerequisites: { "color": "blue" },
 		initial_values: [ "none" ],
 		other_values: [ "2px 2px", "2px 2px 1px", "2px 2px green", "2px 2px 1px green", "green 2px 2px", "green 2px 2px 1px", "green 2px 2px, blue 1px 3px 4px", "currentColor 3px 3px", "blue 2px 2px, currentColor 1px 2px",