Implement hanging-punctuation property parsing.
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Feb 2016 20:54:30 +0000 (20:54 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Feb 2016 20:54:30 +0000 (20:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=18109.

Reviewed by Zalan Bujtas.

Source/WebCore:

Added parsing test in fast/css.

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::renderEmphasisPositionFlagsToCSSValue):
(WebCore::hangingPunctuationToCSSValue):
(WebCore::fillRepeatToCSSValue):
(WebCore::ComputedStyleExtractor::propertyValue):
* css/CSSParser.cpp:
(WebCore::CSSParser::parseValue):
(WebCore::CSSParser::parseTextIndent):
(WebCore::CSSParser::parseHangingPunctuation):
(WebCore::CSSParser::parseLineBoxContain):
* css/CSSParser.h:
* css/CSSPrimitiveValueMappings.h:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore::CSSPrimitiveValue::operator HangingPunctuation):
(WebCore::CSSPrimitiveValue::operator LineBreak):
* css/CSSPropertyNames.in:
* css/CSSValueKeywords.in:
* css/StyleBuilderConverter.h:
(WebCore::StyleBuilderConverter::convertRegionBreakInside):
(WebCore::StyleBuilderConverter::convertHangingPunctuation):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::changeRequiresLayout):
* rendering/style/RenderStyle.h:
* rendering/style/RenderStyleConstants.h:
(WebCore::operator| ):
(WebCore::operator|= ):
* rendering/style/StyleRareInheritedData.cpp:
(WebCore::StyleRareInheritedData::StyleRareInheritedData):
(WebCore::StyleRareInheritedData::operator==):
* rendering/style/StyleRareInheritedData.h:

LayoutTests:

* fast/css/parsing-hanging-punctuation-expected.txt: Added.
* fast/css/parsing-hanging-punctuation.html: Added.
* fast/css/resources/parsing-hanging-punctuation.js: Added.
(test):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@196075 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/parsing-hanging-punctuation-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/parsing-hanging-punctuation.html [new file with mode: 0644]
LayoutTests/fast/css/resources/parsing-hanging-punctuation.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSParser.h
Source/WebCore/css/CSSPrimitiveValueMappings.h
Source/WebCore/css/CSSPropertyNames.in
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/css/StyleBuilderConverter.h
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/RenderStyleConstants.h
Source/WebCore/rendering/style/StyleRareInheritedData.cpp
Source/WebCore/rendering/style/StyleRareInheritedData.h

index ed94c6b..73f6e05 100644 (file)
@@ -1,3 +1,15 @@
+2016-02-03  Dave Hyatt  <hyatt@apple.com>
+
+        Implement hanging-punctuation property parsing.
+        https://bugs.webkit.org/show_bug.cgi?id=18109.
+
+        Reviewed by Zalan Bujtas.
+
+        * fast/css/parsing-hanging-punctuation-expected.txt: Added.
+        * fast/css/parsing-hanging-punctuation.html: Added.
+        * fast/css/resources/parsing-hanging-punctuation.js: Added.
+        (test):
+
 2016-02-03  Ryan Haddad  <ryanhaddad@apple.com>
 
         Skip fast/forms/input-user-input-sanitization.html on ios-simulator
diff --git a/LayoutTests/fast/css/parsing-hanging-punctuation-expected.txt b/LayoutTests/fast/css/parsing-hanging-punctuation-expected.txt
new file mode 100644 (file)
index 0000000..61328e6
--- /dev/null
@@ -0,0 +1,27 @@
+This tests checks that all of the input values for hanging-punctuation parse correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS test("hanging-punctuation: none;") is "none"
+PASS test("hanging-punctuation: first;") is "first"
+PASS test("hanging-punctuation: last;") is "last"
+PASS test("hanging-punctuation: allow-end;") is "allow-end"
+PASS test("hanging-punctuation: force-end;") is "force-end"
+PASS test("hanging-punctuation: first last;") is "first last"
+PASS test("hanging-punctuation: last first;") is "last first"
+PASS test("hanging-punctuation: first allow-end;") is "first allow-end"
+PASS test("hanging-punctuation: first force-end;") is "first force-end"
+PASS test("hanging-punctuation: first allow-end last;") is "first allow-end last"
+PASS test("hanging-punctuation: last allow-end;") is "last allow-end"
+PASS test("hanging-punctuation: first first;") is ""
+PASS test("hanging-punctuation: nonsense;") is ""
+PASS test("hanging-punctuation: allow-end force-end;") is ""
+PASS test("hanging-punctuation: force-end allow-end;") is ""
+PASS test("hanging-punctuation: last last;") is ""
+PASS test("hanging-punctuation: 20px;") is ""
+PASS test("hanging-punctuation: first allow-end force-end last;") is ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/css/parsing-hanging-punctuation.html b/LayoutTests/fast/css/parsing-hanging-punctuation.html
new file mode 100644 (file)
index 0000000..a2ea51d
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/parsing-hanging-punctuation.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/css/resources/parsing-hanging-punctuation.js b/LayoutTests/fast/css/resources/parsing-hanging-punctuation.js
new file mode 100644 (file)
index 0000000..a0f3097
--- /dev/null
@@ -0,0 +1,32 @@
+description("This tests checks that all of the input values for hanging-punctuation parse correctly.");
+
+function test(value)
+{
+    var div = document.createElement("div");
+    div.setAttribute("style", value);
+    document.body.appendChild(div);
+    
+    var result = div.style.getPropertyValue("hanging-punctuation");
+    document.body.removeChild(div);
+    return result;
+}
+
+shouldBe('test("hanging-punctuation: none;")', '"none"');
+shouldBe('test("hanging-punctuation: first;")', '"first"');
+shouldBe('test("hanging-punctuation: last;")', '"last"');
+shouldBe('test("hanging-punctuation: allow-end;")', '"allow-end"');
+shouldBe('test("hanging-punctuation: force-end;")', '"force-end"');
+shouldBe('test("hanging-punctuation: first last;")', '"first last"');
+shouldBe('test("hanging-punctuation: last first;")', '"last first"');
+shouldBe('test("hanging-punctuation: first allow-end;")', '"first allow-end"');
+shouldBe('test("hanging-punctuation: first force-end;")', '"first force-end"');
+shouldBe('test("hanging-punctuation: first allow-end last;")', '"first allow-end last"');
+shouldBe('test("hanging-punctuation: last allow-end;")', '"last allow-end"');
+
+shouldBeEqualToString('test("hanging-punctuation: first first;")', '');
+shouldBeEqualToString('test("hanging-punctuation: nonsense;")', '');
+shouldBeEqualToString('test("hanging-punctuation: allow-end force-end;")', '');
+shouldBeEqualToString('test("hanging-punctuation: force-end allow-end;")', '');
+shouldBeEqualToString('test("hanging-punctuation: last last;")', '');
+shouldBeEqualToString('test("hanging-punctuation: 20px;")', '');
+shouldBeEqualToString('test("hanging-punctuation: first allow-end force-end last;")', '');
index 15315ca..d3d9863 100644 (file)
@@ -1,3 +1,43 @@
+2016-02-03  Dave Hyatt  <hyatt@apple.com>
+
+        Implement hanging-punctuation property parsing.
+        https://bugs.webkit.org/show_bug.cgi?id=18109.
+
+        Reviewed by Zalan Bujtas.
+
+        Added parsing test in fast/css.
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::renderEmphasisPositionFlagsToCSSValue):
+        (WebCore::hangingPunctuationToCSSValue):
+        (WebCore::fillRepeatToCSSValue):
+        (WebCore::ComputedStyleExtractor::propertyValue):
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseValue):
+        (WebCore::CSSParser::parseTextIndent):
+        (WebCore::CSSParser::parseHangingPunctuation):
+        (WebCore::CSSParser::parseLineBoxContain):
+        * css/CSSParser.h:
+        * css/CSSPrimitiveValueMappings.h:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+        (WebCore::CSSPrimitiveValue::operator HangingPunctuation):
+        (WebCore::CSSPrimitiveValue::operator LineBreak):
+        * css/CSSPropertyNames.in:
+        * css/CSSValueKeywords.in:
+        * css/StyleBuilderConverter.h:
+        (WebCore::StyleBuilderConverter::convertRegionBreakInside):
+        (WebCore::StyleBuilderConverter::convertHangingPunctuation):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::changeRequiresLayout):
+        * rendering/style/RenderStyle.h:
+        * rendering/style/RenderStyleConstants.h:
+        (WebCore::operator| ):
+        (WebCore::operator|= ):
+        * rendering/style/StyleRareInheritedData.cpp:
+        (WebCore::StyleRareInheritedData::StyleRareInheritedData):
+        (WebCore::StyleRareInheritedData::operator==):
+        * rendering/style/StyleRareInheritedData.h:
+
 2016-02-03  Jessie Berlin  <jberlin@webkit.org>
 
         Build fix.
index 111b147..7aea6af 100644 (file)
@@ -1695,6 +1695,23 @@ static Ref<CSSValue> renderEmphasisPositionFlagsToCSSValue(TextEmphasisPosition
     return list.releaseNonNull();
 }
 
+static Ref<CSSValue> hangingPunctuationToCSSValue(HangingPunctuation hangingPunctuation)
+{
+    auto& cssValuePool = CSSValuePool::singleton();
+    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+    if (hangingPunctuation & FirstHangingPunctuation)
+        list->append(cssValuePool.createIdentifierValue(CSSValueFirst));
+    if (hangingPunctuation & AllowEndHangingPunctuation)
+        list->append(cssValuePool.createIdentifierValue(CSSValueAllowEnd));
+    if (hangingPunctuation & ForceEndHangingPunctuation)
+        list->append(cssValuePool.createIdentifierValue(CSSValueForceEnd));
+    if (hangingPunctuation & LastHangingPunctuation)
+        list->append(cssValuePool.createIdentifierValue(CSSValueLast));
+    if (!list->length())
+        return cssValuePool.createIdentifierValue(CSSValueNone);
+    return list.releaseNonNull();
+}
+    
 static Ref<CSSValue> fillRepeatToCSSValue(EFillRepeat xRepeat, EFillRepeat yRepeat)
 {
     // For backwards compatibility, if both values are equal, just return one of them. And
@@ -3018,6 +3035,8 @@ RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID,
             return cssValuePool.createValue(style->breakBefore());
         case CSSPropertyBreakInside:
             return cssValuePool.createValue(style->breakInside());
+        case CSSPropertyHangingPunctuation:
+            return hangingPunctuationToCSSValue(style->hangingPunctuation());
         case CSSPropertyPosition:
             return cssValuePool.createValue(style->position());
         case CSSPropertyRight:
index 1bf3197..624a5b4 100644 (file)
@@ -3087,6 +3087,8 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important)
             validPrimitive = true;
         break;
 
+    case CSSPropertyHangingPunctuation:
+        return parseHangingPunctuation(important);
     case CSSPropertyWebkitLineBoxContain:
         if (id == CSSValueNone)
             validPrimitive = true;
@@ -10511,6 +10513,50 @@ RefPtr<CSSValue> CSSParser::parseTextIndent()
     return list.release();
 }
 
+bool CSSParser::parseHangingPunctuation(bool important)
+{
+    CSSParserValue* value = m_valueList->current();
+    if (value && value->id == CSSValueNone) {
+        addProperty(CSSPropertyHangingPunctuation, CSSValuePool::singleton().createIdentifierValue(CSSValueNone), important);
+        m_valueList->next();
+        return true;
+    }
+    
+    RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+    bool isValid = true;
+    std::bitset<numCSSValueKeywords> seenValues;
+    while (isValid && value) {
+        if (seenValues[value->id]
+            || (value->id == CSSValueAllowEnd && seenValues[CSSValueForceEnd])
+            || (value->id == CSSValueForceEnd && seenValues[CSSValueAllowEnd])) {
+            isValid = false;
+            break;
+        }
+        switch (value->id) {
+        case CSSValueAllowEnd:
+        case CSSValueFirst:
+        case CSSValueForceEnd:
+        case CSSValueLast:
+            list->append(CSSValuePool::singleton().createIdentifierValue(value->id));
+            seenValues.set(value->id);
+            break;
+        default:
+            isValid = false;
+            break;
+        }
+        if (isValid)
+            value = m_valueList->next();
+    }
+    
+    // Values are either valid or in shorthand scope.
+    if (list->length() && isValid) {
+        addProperty(CSSPropertyHangingPunctuation, list.release(), important);
+        return true;
+    }
+    
+    return false;
+}
+
 bool CSSParser::parseLineBoxContain(bool important)
 {
     LineBoxContain lineBoxContain = LineBoxContainNone;
index fd0409d..244733f 100644 (file)
@@ -337,6 +337,8 @@ public:
 
     RefPtr<CSSValue> parseTextIndent();
     
+    bool parseHangingPunctuation(bool important);
+
     bool parseLineBoxContain(bool important);
     RefPtr<CSSCalcValue> parseCalculation(CSSParserValue&, CalculationPermittedValueRange);
 
index b4d43ae..a9aaa94 100644 (file)
@@ -1626,6 +1626,29 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(LineBreak e)
     }
 }
 
+template<> inline CSSPrimitiveValue::operator HangingPunctuation() const
+{
+    ASSERT(isValueID());
+    
+    switch (m_value.valueID) {
+    case CSSValueNone:
+        return NoHangingPunctuation;
+    case CSSValueFirst:
+        return FirstHangingPunctuation;
+    case CSSValueLast:
+        return LastHangingPunctuation;
+    case CSSValueAllowEnd:
+        return AllowEndHangingPunctuation;
+    case CSSValueForceEnd:
+        return ForceEndHangingPunctuation;
+    default:
+        break;
+    }
+    
+    ASSERT_NOT_REACHED();
+    return NoHangingPunctuation;
+}
+
 template<> inline CSSPrimitiveValue::operator LineBreak() const
 {
     ASSERT(isValueID());
index 1f6a704..271940b 100644 (file)
@@ -236,6 +236,7 @@ font-variant [Inherited, Longhands=font-variant-ligatures|font-variant-position|
 font-stretch [SkipBuilder]
 glyph-orientation-horizontal [Inherited, SVG, Converter=GlyphOrientation]
 glyph-orientation-vertical [Inherited, SVG, Converter=GlyphOrientationOrAuto]
+hanging-punctuation [Inherited, Converter=HangingPunctuation]
 height [Initial=initialSize, Converter=LengthSizing]
 #if defined(ENABLE_CSS_IMAGE_ORIENTATION) && ENABLE_CSS_IMAGE_ORIENTATION
 image-orientation [Inherited]
index 4f4e84d..8ef4691 100644 (file)
@@ -1191,3 +1191,9 @@ contents
 // touch-action
 manipulation
 #endif
+
+// hanging-punctuation
+allow-end
+first
+force-end
+last
index 20cb520..cb81b4d 100644 (file)
@@ -135,6 +135,8 @@ public:
     static BreakBetween convertRegionBreakBetween(StyleResolver&, CSSValue&);
     static BreakInside convertRegionBreakInside(StyleResolver&, CSSValue&);
 #endif
+    
+    static HangingPunctuation convertHangingPunctuation(StyleResolver&, CSSValue&);
 
 private:
     friend class StyleBuilderCustom;
@@ -1279,6 +1281,16 @@ inline BreakInside StyleBuilderConverter::convertRegionBreakInside(StyleResolver
 }
 #endif
 
+inline HangingPunctuation StyleBuilderConverter::convertHangingPunctuation(StyleResolver&, CSSValue& value)
+{
+    HangingPunctuation result = RenderStyle::initialHangingPunctuation();
+    if (is<CSSValueList>(value)) {
+        for (auto& currentValue : downcast<CSSValueList>(value))
+            result |= downcast<CSSPrimitiveValue>(currentValue.get());
+    }
+    return result;
+}
+
 } // namespace WebCore
 
 #endif // StyleBuilderConverter_h
index 57f922e..11860f6 100644 (file)
@@ -613,6 +613,7 @@ bool RenderStyle::changeRequiresLayout(const RenderStyle& other, unsigned& chang
 #endif
             || rareInheritedData->m_lineSnap != other.rareInheritedData->m_lineSnap
             || rareInheritedData->m_lineAlign != other.rareInheritedData->m_lineAlign
+            || rareInheritedData->m_hangingPunctuation != other.rareInheritedData->m_hangingPunctuation
 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
             || rareInheritedData->useTouchOverflowScrolling != other.rareInheritedData->useTouchOverflowScrolling
 #endif
index fff3409..75bc079 100644 (file)
@@ -879,6 +879,8 @@ public:
     BreakInside breakInside() const { return static_cast<BreakInside>(rareNonInheritedData->m_breakInside); }
     BreakBetween breakBefore() const { return static_cast<BreakBetween>(rareNonInheritedData->m_breakBefore); }
     BreakBetween breakAfter() const { return static_cast<BreakBetween>(rareNonInheritedData->m_breakAfter); }
+    
+    HangingPunctuation hangingPunctuation() const { return static_cast<HangingPunctuation>(rareInheritedData->m_hangingPunctuation); }
 
     float outlineOffset() const
     {
@@ -1622,6 +1624,8 @@ public:
     void setBreakBefore(BreakBetween breakBehavior) { SET_VAR(rareNonInheritedData, m_breakBefore, breakBehavior); }
     void setBreakAfter(BreakBetween breakBehavior) { SET_VAR(rareNonInheritedData, m_breakAfter, breakBehavior); }
     void setBreakInside(BreakInside breakBehavior) { SET_VAR(rareNonInheritedData, m_breakInside, breakBehavior); }
+    
+    void setHangingPunctuation(HangingPunctuation punctuation) { SET_VAR(rareInheritedData, m_hangingPunctuation, punctuation); }
 
     // End CSS3 Setters
 
@@ -1881,6 +1885,7 @@ public:
     static EFloat initialFloating() { return NoFloat; }
     static BreakBetween initialBreakBetween() { return AutoBreakBetween; }
     static BreakInside initialBreakInside() { return AutoBreakInside; }
+    static HangingPunctuation initialHangingPunctuation() { return NoHangingPunctuation; }
     static ETableLayout initialTableLayout() { return TAUTO; }
     static EBorderCollapse initialBorderCollapse() { return BSEPARATE; }
     static EBorderStyle initialBorderStyle() { return BNONE; }
index 187140e..fe6f630 100644 (file)
@@ -483,7 +483,17 @@ bool alwaysPageBreak(BreakBetween);
 enum BreakInside {
     AutoBreakInside, AvoidBreakInside, AvoidColumnBreakInside, AvoidPageBreakInside, AvoidRegionBreakInside
 };
-    
+
+enum HangingPunctuation {
+    NoHangingPunctuation = 0,
+    FirstHangingPunctuation = 1 << 0,
+    LastHangingPunctuation = 1 << 1,
+    AllowEndHangingPunctuation = 1 << 2,
+    ForceEndHangingPunctuation = 1 << 3
+};
+inline HangingPunctuation operator| (HangingPunctuation a, HangingPunctuation b) { return HangingPunctuation(int(a) | int(b)); }
+inline HangingPunctuation& operator|= (HangingPunctuation& a, HangingPunctuation b) { return a = a | b; }
+
 enum EEmptyCell {
     SHOW, HIDE
 };
index d16b91f..a517d7d 100644 (file)
@@ -125,6 +125,7 @@ StyleRareInheritedData::StyleRareInheritedData()
 #if ENABLE(CSS_TRAILING_WORD)
     , trailingWord(static_cast<unsigned>(RenderStyle::initialTrailingWord()))
 #endif
+    , m_hangingPunctuation(RenderStyle::initialHangingPunctuation())
     , hyphenationLimitBefore(-1)
     , hyphenationLimitAfter(-1)
     , hyphenationLimitLines(-1)
@@ -207,6 +208,7 @@ inline StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedDa
 #if ENABLE(CSS_TRAILING_WORD)
     , trailingWord(o.trailingWord)
 #endif
+    , m_hangingPunctuation(o.m_hangingPunctuation)
     , hyphenationString(o.hyphenationString)
     , hyphenationLimitBefore(o.hyphenationLimitBefore)
     , hyphenationLimitAfter(o.hyphenationLimitAfter)
@@ -313,6 +315,7 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
 #if ENABLE(CSS_TRAILING_WORD)
         && trailingWord == o.trailingWord
 #endif
+        && m_hangingPunctuation == o.m_hangingPunctuation
         && m_customProperties == o.m_customProperties
         && arePointingToEqualData(listStyleImage, o.listStyleImage);
 }
index a52e718..e740297 100644 (file)
@@ -137,6 +137,8 @@ public:
     unsigned trailingWord : 1;
 #endif
 
+    unsigned m_hangingPunctuation : 4;
+
     AtomicString hyphenationString;
     short hyphenationLimitBefore;
     short hyphenationLimitAfter;