[CSS3] Add support for the word-break:keep-all CSS property
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Jun 2015 23:59:19 +0000 (23:59 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Jun 2015 23:59:19 +0000 (23:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123782

Reviewed by Darin Adler.

Source/WebCore:

Add support for word-break:keep-all CSS property by CSS3 spec:
http://www.w3.org/TR/2013/WD-css-text-3-20131010/#word-break-property

Test: fast/text/word-break-keep-all.html

* css/CSSParser.cpp:
(WebCore::isValidKeywordPropertyAndValue):
* css/CSSPrimitiveValueMappings.h:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore::CSSPrimitiveValue::operator EWordBreak):
* css/CSSValueKeywords.in:
* rendering/RenderText.cpp:
(WebCore::RenderText::computePreferredLogicalWidths):
* rendering/break_lines.h:
(WebCore::nextBreakablePositionKeepingAllWords):
(WebCore::nextBreakablePositionKeepingAllWordsIgnoringNBSP):
(WebCore::isBreakable):
* rendering/line/BreakingContext.h:
(WebCore::BreakingContext::handleText):
(WebCore::BreakingContext::optimalLineBreakLocationForTrailingWord):
* rendering/style/RenderStyleConstants.h:

LayoutTests:

* fast/text/word-break-keep-all.html: Added.
* platform/mac/fast/text/word-break-keep-all-expected.png: Added.
* platform/mac/fast/text/word-break-keep-all-expected.txt: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/text/word-break-keep-all-expected.html [new file with mode: 0644]
LayoutTests/fast/text/word-break-keep-all.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSPrimitiveValueMappings.h
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/rendering/RenderText.cpp
Source/WebCore/rendering/break_lines.h
Source/WebCore/rendering/line/BreakingContext.h
Source/WebCore/rendering/style/RenderStyleConstants.h

index 627efb3..497238a 100644 (file)
@@ -1,3 +1,14 @@
+2015-06-18  KyungTae Kim  <ktf.kim@samsung.com> and Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [CSS3] Add support for the word-break:keep-all CSS property
+        https://bugs.webkit.org/show_bug.cgi?id=123782
+
+        Reviewed by Darin Adler.
+
+        * fast/text/word-break-keep-all.html: Added.
+        * platform/mac/fast/text/word-break-keep-all-expected.png: Added.
+        * platform/mac/fast/text/word-break-keep-all-expected.txt: Added.
+
 2015-06-18  Conrad Shultz  <conrad_shultz@apple.com>
 
         REGRESSION: js/dom/navigator-plugins-crash.html asserts a lot
diff --git a/LayoutTests/fast/text/word-break-keep-all-expected.html b/LayoutTests/fast/text/word-break-keep-all-expected.html
new file mode 100644 (file)
index 0000000..6fe0a09
--- /dev/null
@@ -0,0 +1,15 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style>
+div{width:150px;border:2px solid black;}
+</style>
+</head>
+<body>
+This test checks whether word-break:keep-all keeps the words
+
+<p>On the next line, lines should break between any two Korean syllables (word-break: normal)</p>
+<div style="word-break: normal;">각 줄의 마지막에 한글이 올 때 줄 나눔 기준을 글자 또는 어절 단위로 한다.</div>
+
+<p>On the next line, lines should break only at spaces like English (word-break: keep-all)<p> 
+<div style="word-break: keep-all;">각 줄의 마지막에<br>한글이 올 때 줄 나눔<br>기준을 글자 또는<br>어절 단위로 한다.</div>
diff --git a/LayoutTests/fast/text/word-break-keep-all.html b/LayoutTests/fast/text/word-break-keep-all.html
new file mode 100644 (file)
index 0000000..39813aa
--- /dev/null
@@ -0,0 +1,15 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style>
+div{width:150px;border:2px solid black;}
+</style>
+</head>
+<body>
+This test checks whether word-break:keep-all keeps the words
+
+<p>On the next line, lines should break between any two Korean syllables (word-break: normal)</p>
+<div style="word-break: normal;">각 줄의 마지막에 한글이 올 때 줄 나눔 기준을 글자 또는 어절 단위로 한다.</div>
+
+<p>On the next line, lines should break only at spaces like English (word-break: keep-all)<p> 
+<div style="word-break: keep-all;">각 줄의 마지막에 한글이 올 때 줄 나눔 기준을 글자 또는 어절 단위로 한다.</div>
index aa98692..31856ad 100644 (file)
@@ -1,3 +1,32 @@
+2015-06-18  KyungTae Kim  <ktf.kim@samsung.com> and Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [CSS3] Add support for the word-break:keep-all CSS property
+        https://bugs.webkit.org/show_bug.cgi?id=123782
+
+        Reviewed by Darin Adler.
+
+        Add support for word-break:keep-all CSS property by CSS3 spec:
+        http://www.w3.org/TR/2013/WD-css-text-3-20131010/#word-break-property
+
+        Test: fast/text/word-break-keep-all.html
+
+        * css/CSSParser.cpp:
+        (WebCore::isValidKeywordPropertyAndValue):
+        * css/CSSPrimitiveValueMappings.h:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+        (WebCore::CSSPrimitiveValue::operator EWordBreak):
+        * css/CSSValueKeywords.in:
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::computePreferredLogicalWidths):
+        * rendering/break_lines.h:
+        (WebCore::nextBreakablePositionKeepingAllWords):
+        (WebCore::nextBreakablePositionKeepingAllWordsIgnoringNBSP):
+        (WebCore::isBreakable):
+        * rendering/line/BreakingContext.h:
+        (WebCore::BreakingContext::handleText):
+        (WebCore::BreakingContext::optimalLineBreakLocationForTrailingWord):
+        * rendering/style/RenderStyleConstants.h:
+
 2015-06-18  Jon Lee  <jonlee@apple.com>
 
         Update AVKit usage of pip
index 166bee4..8ecf66d 100644 (file)
@@ -1029,8 +1029,8 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int
         if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
             return true;
         break;
-    case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
-        if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
+    case CSSPropertyWordBreak: // normal | break-all | keep-all | break-word (this is a custom extension)
+        if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueKeepAll || valueID == CSSValueBreakWord)
             return true;
         break;
 #if ENABLE(CSS_TRAILING_WORD)
index 3348aac..9a99758 100644 (file)
@@ -3010,6 +3010,9 @@ template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EWordBreak e)
     case BreakAllWordBreak:
         m_value.valueID = CSSValueBreakAll;
         break;
+    case KeepAllWordBreak:
+        m_value.valueID = CSSValueKeepAll;
+        break;
     case BreakWordBreak:
         m_value.valueID = CSSValueBreakWord;
         break;
@@ -3023,6 +3026,8 @@ template<> inline CSSPrimitiveValue::operator EWordBreak() const
     switch (m_value.valueID) {
     case CSSValueBreakAll:
         return BreakAllWordBreak;
+    case CSSValueKeepAll:
+        return KeepAllWordBreak;
     case CSSValueBreakWord:
         return BreakWordBreak;
     case CSSValueNormal:
index 1beb134..931aabd 100644 (file)
@@ -680,6 +680,7 @@ skip-white-space
 // CSS_PROP_WORD_BREAK
 //
 break-all
+keep-all
 
 //
 // CSS_PROP_WORD_WRAP
index d016b19..595d931 100644 (file)
@@ -738,6 +738,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Fo
 
     bool breakNBSP = style.autoWrap() && style.nbspMode() == SPACE;
     bool breakAll = (style.wordBreak() == BreakAllWordBreak || style.wordBreak() == BreakWordBreak) && style.autoWrap();
+    bool keepAllWords = style.wordBreak() == KeepAllWordBreak;
     bool isLooseCJKMode = breakIterator.isLooseCJKMode();
 
     for (int i = 0; i < len; i++) {
@@ -783,7 +784,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Fo
             continue;
         }
 
-        bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP, isLooseCJKMode);
+        bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP, isLooseCJKMode, keepAllWords);
         bool betweenWords = true;
         int j = i;
         while (c != '\n' && !isSpaceAccordingToStyle(c, style) && c != '\t' && (c != softHyphen || style.hyphens() == HyphensNone)) {
@@ -791,7 +792,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Fo
             if (j == len)
                 break;
             c = uncheckedCharacterAt(j);
-            if (isBreakable(breakIterator, j, nextBreakable, breakNBSP, isLooseCJKMode) && characterAt(j - 1) != softHyphen)
+            if (isBreakable(breakIterator, j, nextBreakable, breakNBSP, isLooseCJKMode, keepAllWords) && characterAt(j - 1) != softHyphen)
                 break;
             if (breakAll) {
                 betweenWords = false;
index dc9a31b..9e04d1e 100644 (file)
@@ -161,12 +161,38 @@ static inline int nextBreakablePositionLoosely(LazyLineBreakIterator& lazyBreakI
     return len;
 }
 
-inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos)
+template<typename CharacterType, NBSPBehavior nbspBehavior>
+inline unsigned nextBreakablePositionKeepingAllWords(const CharacterType* string, unsigned length, unsigned startPosition)
+{
+    for (unsigned i = startPosition; i < length; i++) {
+        if (isBreakableSpace<nbspBehavior>(string[i]))
+            return i;
+    }
+    return length;
+}
+
+inline unsigned nextBreakablePositionKeepingAllWords(LazyLineBreakIterator& lazyBreakIterator, int startPosition)
 {
     String string = lazyBreakIterator.string();
     if (string.is8Bit())
-        return nextBreakablePositionNonLoosely<LChar, NBSPBehavior::TreatNBSPAsBreak>(lazyBreakIterator, string.characters8(), string.length(), pos);
-    return nextBreakablePositionNonLoosely<UChar, NBSPBehavior::TreatNBSPAsBreak>(lazyBreakIterator, string.characters16(), string.length(), pos);
+        return nextBreakablePositionKeepingAllWords<LChar, NBSPBehavior::TreatNBSPAsBreak>(string.characters8(), string.length(), startPosition);
+    return nextBreakablePositionKeepingAllWords<UChar, NBSPBehavior::TreatNBSPAsBreak>(string.characters16(), string.length(), startPosition);
+}
+
+inline unsigned nextBreakablePositionKeepingAllWordsIgnoringNBSP(LazyLineBreakIterator& iterator, int startPosition)
+{
+    String string = iterator.string();
+    if (string.is8Bit())
+        return nextBreakablePositionKeepingAllWords<LChar, NBSPBehavior::IgnoreNBSP>(string.characters8(), string.length(), startPosition);
+    return nextBreakablePositionKeepingAllWords<UChar, NBSPBehavior::IgnoreNBSP>(string.characters16(), string.length(), startPosition);
+}
+
+inline int nextBreakablePosition(LazyLineBreakIterator& iterator, int pos)
+{
+    String string = iterator.string();
+    if (string.is8Bit())
+        return nextBreakablePositionNonLoosely<LChar, NBSPBehavior::TreatNBSPAsBreak>(iterator, string.characters8(), string.length(), pos);
+    return nextBreakablePositionNonLoosely<UChar, NBSPBehavior::TreatNBSPAsBreak>(iterator, string.characters16(), string.length(), pos);
 }
 
 inline int nextBreakablePositionIgnoringNBSP(LazyLineBreakIterator& lazyBreakIterator, int pos)
@@ -193,12 +219,17 @@ inline int nextBreakablePositionIgnoringNBSPLoose(LazyLineBreakIterator& lazyBre
     return nextBreakablePositionLoosely<UChar, NBSPBehavior::IgnoreNBSP>(lazyBreakIterator, string.characters16(), string.length(), pos);
 }
 
-inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP, bool isLooseMode)
+inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP, bool isLooseMode, bool keepAllWords)
 {
     if (pos <= nextBreakable)
         return pos == nextBreakable;
 
-    if (isLooseMode) {
+    if (keepAllWords) {
+        if (breakNBSP)
+            nextBreakable = static_cast<int>(nextBreakablePositionKeepingAllWords(lazyBreakIterator, pos));
+        else
+            nextBreakable = static_cast<int>(nextBreakablePositionKeepingAllWordsIgnoringNBSP(lazyBreakIterator, pos));
+    } else if (isLooseMode) {
         if (breakNBSP)
             nextBreakable = nextBreakablePositionLoose(lazyBreakIterator, pos);
         else
index de03b21..e55133c 100644 (file)
@@ -744,6 +744,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
     bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.committedWidth()) || m_currWS == PRE);
     bool midWordBreak = false;
     bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap;
+    bool keepAllWords = m_currentStyle->wordBreak() == KeepAllWordBreak;
     float hyphenWidth = 0;
     bool isLooseCJKMode = false;
 
@@ -798,7 +799,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
         }
 
         int nextBreakablePosition = m_current.nextBreakablePosition();
-        bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP, isLooseCJKMode)
+        bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP, isLooseCJKMode, keepAllWords)
             && (style.hyphens() != HyphensNone || (m_current.previousInSameNode() != softHyphen)));
         m_current.setNextBreakablePosition(nextBreakablePosition);
 
@@ -1219,7 +1220,7 @@ inline InlineIterator BreakingContext::optimalLineBreakLocationForTrailingWord()
     bool isLooseCJKMode = m_renderTextInfo.text != &renderText && m_renderTextInfo.lineBreakIterator.isLooseCJKMode();
     bool breakNBSP = m_autoWrap && m_currentStyle->nbspMode() == SPACE;
     int nextBreakablePosition = lineBreak.nextBreakablePosition();
-    isBreakable(m_renderTextInfo.lineBreakIterator, lineBreak.offset() + 1, nextBreakablePosition, breakNBSP, isLooseCJKMode);
+    isBreakable(m_renderTextInfo.lineBreakIterator, lineBreak.offset() + 1, nextBreakablePosition, breakNBSP, isLooseCJKMode, m_currentStyle->wordBreak() == KeepAllWordBreak);
     if (nextBreakablePosition < 0 || static_cast<unsigned>(nextBreakablePosition) != renderText.textLength())
         return lineBreak;
     const RenderStyle& style = lineStyle(renderText, m_lineInfo);
index 1adf583..f131805 100644 (file)
@@ -285,10 +285,8 @@ enum AspectRatioType {
     AspectRatioAuto, AspectRatioFromIntrinsic, AspectRatioFromDimensions, AspectRatioSpecified
 };
 
-// Word Break Values. Matches WinIE, rather than CSS3
-
 enum EWordBreak {
-    NormalWordBreak, BreakAllWordBreak, BreakWordBreak
+    NormalWordBreak, BreakAllWordBreak, KeepAllWordBreak, BreakWordBreak
 };
 
 enum EOverflowWrap {