Title: [179734] branches/safari-600.1.4.15-branch

Diff

Modified: branches/safari-600.1.4.15-branch/LayoutTests/ChangeLog (179733 => 179734)


--- branches/safari-600.1.4.15-branch/LayoutTests/ChangeLog	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/LayoutTests/ChangeLog	2015-02-06 01:40:21 UTC (rev 179734)
@@ -1,3 +1,16 @@
+2015-02-05  David Kilzer  <[email protected]>
+
+        Merge r176473.
+
+    2014-11-21  Glenn Adams  <[email protected]> and Myles C. Maxfield  <[email protected]>
+
+        CSS3: line-break property support
+        https://bugs.webkit.org/show_bug.cgi?id=89235
+
+        Reviewed by Eric Seidel and Dave Hyatt.
+
+        * platform/mac/TestExpectations: Mark css3/line-break tests as passing.
+
 2015-02-05  Lucas Forschler  <[email protected]>
 
     Rollout r179711

Modified: branches/safari-600.1.4.15-branch/LayoutTests/platform/mac/TestExpectations (179733 => 179734)


--- branches/safari-600.1.4.15-branch/LayoutTests/platform/mac/TestExpectations	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/LayoutTests/platform/mac/TestExpectations	2015-02-06 01:40:21 UTC (rev 179734)
@@ -1390,3 +1390,8 @@
 webkit.org/b/133686 media/track/w3c/interfaces/TextTrackCue/pauseOnExit.html [ Pass Failure ]
 webkit.org/b/133686 media/track/w3c/interfaces/TextTrackCue/startTime.html [ Pass Failure ]
 webkit.org/b/133686 media/track/w3c/interfaces/TextTrackCue/track.html [ Pass Failure ]
+
+# Verified passing, so override generic skip
+webkit.org/b/89235 css3/line-break [ Pass ]
+webkit.org/b/138115 css3/line-break/line-break-auto-hyphens.html [ ImageOnlyFailure ]
+webkit.org/b/138115 css3/line-break/line-break-auto-sound-marks.html [ ImageOnlyFailure ]

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/ChangeLog (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/ChangeLog	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/ChangeLog	2015-02-06 01:40:21 UTC (rev 179734)
@@ -1,3 +1,161 @@
+2015-02-05  David Kilzer  <[email protected]>
+
+        Merge r176473.
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::canUseFor): Change from
+        r176473 not listed in that ChangeLog.
+        (WebCore::SimpleLineLayout::createLineRuns): Call
+        nextBreakablePositionNonLoosely() in place of
+        nextBreakablePosition().
+
+    2014-11-21  Glenn Adams  <[email protected]> and Myles C. Maxfield  <[email protected]>
+
+        Add support to -webkit-line-break property for CSS3 Text line-break property values and semantics.
+        https://bugs.webkit.org/show_bug.cgi?id=89235
+
+        Reviewed by Eric Seidel and Dave Hyatt.
+
+        This patch adds semantic support for the CSS3 line-break property (qua -webkit-line-break),
+        and enables testing on (apple) mac ports. Follow on patches will enable these tests on
+        other ports as they are incrementally verified.
+
+        See also wiki documentation at:
+        [1] http://trac.webkit.org/wiki/LineBreaking
+        [2] http://trac.webkit.org/wiki/LineBreakingCSS3Mapping
+
+        Tests: css3/line-break/line-break-auto-centered.html
+               css3/line-break/line-break-auto-half-kana.html
+               css3/line-break/line-break-auto-hyphens.html
+               css3/line-break/line-break-auto-inseparables.html
+               css3/line-break/line-break-auto-iteration-marks.html
+               css3/line-break/line-break-auto-postfixes.html
+               css3/line-break/line-break-auto-prefixes.html
+               css3/line-break/line-break-auto-sound-marks.html
+               css3/line-break/line-break-loose-centered.html
+               css3/line-break/line-break-loose-half-kana.html
+               css3/line-break/line-break-loose-hyphens.html
+               css3/line-break/line-break-loose-inseparables.html
+               css3/line-break/line-break-loose-iteration-marks.html
+               css3/line-break/line-break-loose-postfixes.html
+               css3/line-break/line-break-loose-prefixes.html
+               css3/line-break/line-break-loose-sound-marks.html
+               css3/line-break/line-break-normal-centered.html
+               css3/line-break/line-break-normal-half-kana.html
+               css3/line-break/line-break-normal-hyphens.html
+               css3/line-break/line-break-normal-inseparables.html
+               css3/line-break/line-break-normal-iteration-marks.html
+               css3/line-break/line-break-normal-postfixes.html
+               css3/line-break/line-break-normal-prefixes.html
+               css3/line-break/line-break-normal-sound-marks.html
+               css3/line-break/line-break-strict-centered.html
+               css3/line-break/line-break-strict-half-kana.html
+               css3/line-break/line-break-strict-hyphens.html
+               css3/line-break/line-break-strict-inseparables.html
+               css3/line-break/line-break-strict-iteration-marks.html
+               css3/line-break/line-break-strict-postfixes.html
+               css3/line-break/line-break-strict-prefixes.html
+               css3/line-break/line-break-strict-sound-marks.html
+
+        These tests were previously added in http://trac.webkit.org/changeset/143378, but skipped
+        in generic TestExpectations. In this patch, they are marked as Pass for the (apple) mac ports.
+
+        * platform/text/LineBreakIteratorPoolICU.h:
+        (WebCore::LineBreakIteratorPool::makeLocaleWithBreakKeyword):
+        Add static function to construct ICU locale argument (also used as pool key) with additional
+        break keyword.
+        (LineBreakIteratorPool):
+        (WebCore::LineBreakIteratorPool::take):
+        (WebCore::LineBreakIteratorPool::put):
+        Remove direct dependency from ICU library (and types), moving that dependency into
+        new {open,close}LineBreakIterator() functions (defined in TextBreakIteratorICU.cpp).
+        Update to take line break mode into account.
+        Create (and cache) different break iterators depending on line break mode (in addition to locale),
+        which entails expanding pool entry key format to optionally append "@break=" +
+        "loose"|"normal"|"strict" keyword to locale string.
+
+        * platform/text/TextBreakIterator.h:
+        (WebCore::LazyLineBreakIterator::LazyLineBreakIterator):
+        (WebCore::LazyLineBreakIterator::isLooseCJKMode):
+        (WebCore::LazyLineBreakIterator::get):
+        (WebCore::LazyLineBreakIterator::reset):
+        (LazyLineBreakIterator):
+        Define LineBreakIteratorMode enumeration for use in TextBreakIterator et al.
+        Add state member to indicate line break mode.
+
+        * platform/text/TextBreakIteratorICU.cpp:
+        (WebCore::acquireLineBreakIterator):
+        Use new line break mode when making iterator from pool.
+        Handle change of return type of LineBreakIteratorPool::take() to non-ICU type,
+        i.e., TextBreakIterator* instead of ICU's UBreakIterator*.
+        (WebCore::releaseLineBreakIterator):
+        Handle change of parameter type of LineBreakIteratorPool::put() to non-ICU type,
+        i.e., TextBreakIterator* instead of ICU's UBreakIterator*.
+        (WebCore):
+        (WebCore::isCJKLocale):
+        New functions for determining if CJK rules apply.
+        (WebCore::openLineBreakIterator):
+        New function for abstracting opening of ICU style line break iterator. This is now
+        used in LineBreakIteratorPoolICU.h rather than having direct ICU API dependency there.
+        This function also takes into account the line break mode.
+
+        Note that this function only calls ubrk_openRules() when the author has opted-in via
+        using the -webkit-line-break CSS property. Eventually, we would like to be able to
+        customize the rules that ICU's line breaking algorithm uses (especially for CJK text);
+        however, ubrk_openRules() currently parses its input string to create a DFA and is
+        therefore very slow. In fact, it's so slow that increasing our cache size in
+        LineBreakIteratorPool doesn't actually help enough. Also note that the default value
+        for the line-break CSS property is 'auto'.
+        (WebCore::closeLineBreakIterator):
+        (WebCore::mapLineIteratorModeToRules):
+        New function for abstracting closing of ICU style line break iterator. This is now
+        used in LineBreakIteratorPoolICU.h rather than having direct ICU API dependency there.
+
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlock::LineBreaker::nextSegmentBreak):
+        Pass line break iterator mode flag when reseting LazyLineBreakIterator.
+        Add looseMode local variable to prevent need for computing under isBreakable().
+
+        * rendering/RenderText.cpp:
+        (WebCore::mapLineBreakToIteratorMode):
+        Add implementation for mapLineBreakToIteratorMode(), used by both RenderText::computePreferredLogicalWidths
+        and RenderBlock::LineBreaker::nextLineBreak.
+        (WebCore):
+        (WebCore::RenderText::computePreferredLogicalWidths):
+        Ensure (lazy line) breakIterator is initialized for line break mode.
+        Ensure isBreakable() is passed loose mode flag to match behavior in RenderBlock::LineBreaker::nextLineBreak.
+
+        * rendering/RenderText.h:
+        (WebCore):
+        Add declaration for mapLineBreakToIteratorMode(), used by both RenderText::computePreferredLogicalWidths
+        and RenderBlock::LineBreaker::nextLineBreak.
+
+        * rendering/break_lines.cpp:
+        (WebCore):
+        Introduce (local) enum NBSPBehavior for expanding template on nextBreakablePosition.
+        (WebCore::isBreakableSpace):
+        Add externally specified loose mode parameter to prevent need to invoke line break iterator
+        accessor method on each invocation. Use new loose mode flavors off NBP functions.
+        (WebCore::needsLineBreakIterator):
+        Use enum NBSP behavior template parameter rather than boolean.
+        (WebCore::nextBreakablePositionNonLoosely):
+        Extend name to distinguish from loose flavor of this function.
+        (WebCore::nextBreakablePositionLoosely):
+        Add loose flavor of NBP invoked only when loose mode applies, in which case ASCII shortcut
+        table cannot be used.
+        (WebCore::nextBreakablePosition):
+        (WebCore::nextBreakablePositionIgnoringNBSP):
+        Use (renamed) non-loose flavor of NBP.
+        (WebCore::nextBreakablePositionLoose):
+        (WebCore::nextBreakablePositionIgnoringNBSPLoose):
+        Introduce loose flavor of NBP template expansions.
+
+        * rendering/break_lines.h:
+        (WebCore):
+        (WebCore::isBreakable):
+        Add externally specified loose mode parameter to prevent need to invoke line break iterator
+        accessor method on each invocation.
+
 2015-02-05  Lucas Forschler  <[email protected]>
 
     Rollout r179711

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/WebCore.exp.in (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/WebCore.exp.in	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/WebCore.exp.in	2015-02-06 01:40:21 UTC (rev 179734)
@@ -2545,6 +2545,7 @@
 __ZN7WebCore11MathMLNames4initEv
 __ZN7WebCore11MemoryCache18pruneDeadResourcesEv
 __ZN7WebCore11MemoryCache18pruneLiveResourcesEb
+__ZN7WebCore11isCJKLocaleERKN3WTF12AtomicStringE
 __ZN7WebCore11isEndOfLineERKNS_15VisiblePositionE
 __ZN7WebCore11prefetchDNSERKN3WTF6StringE
 __ZN7WebCore12AudioSession11setCategoryENS0_12CategoryTypeE
@@ -2664,7 +2665,7 @@
 __ZN7WebCore24FloatingPointEnvironment21enableDenormalSupportEv
 __ZN7WebCore24FloatingPointEnvironment25saveMainThreadEnvironmentEv
 __ZN7WebCore24FloatingPointEnvironment6sharedEv
-__ZN7WebCore24acquireLineBreakIteratorEN3WTF10StringViewERKNS0_12AtomicStringEPKtj
+__ZN7WebCore24acquireLineBreakIteratorEN3WTF10StringViewERKNS0_12AtomicStringEPKtjNS_21LineBreakIteratorModeEb
 __ZN7WebCore24charactersAroundPositionERKNS_15VisiblePositionERiS3_S3_
 __ZN7WebCore24createTemporaryDirectoryEP8NSString
 __ZN7WebCore24distanceBetweenPositionsERKNS_15VisiblePositionES2_

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/LineBreakIteratorPoolICU.h (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/LineBreakIteratorPoolICU.h	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/LineBreakIteratorPoolICU.h	2015-02-06 01:40:21 UTC (rev 179734)
@@ -26,6 +26,7 @@
 #ifndef LineBreakIteratorPoolICU_h
 #define LineBreakIteratorPoolICU_h
 
+#include "TextBreakIterator.h"
 #include "TextBreakIteratorInternalICU.h"
 #include <unicode/ubrk.h>
 #include <wtf/Assertions.h>
@@ -34,6 +35,7 @@
 #include <wtf/ThreadSpecific.h>
 #include <wtf/text/AtomicString.h>
 #include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
@@ -48,11 +50,39 @@
 
     static PassOwnPtr<LineBreakIteratorPool> create() { return adoptPtr(new LineBreakIteratorPool); }
 
-    UBreakIterator* take(const AtomicString& locale)
+    static String makeLocaleWithBreakKeyword(const AtomicString& locale, LineBreakIteratorMode mode)
     {
-        UBreakIterator* iterator = 0;
+        StringBuilder localeWithKeyword;
+        localeWithKeyword.append(locale);
+        localeWithKeyword.appendLiteral("@break=");
+        switch (mode) {
+        case LineBreakIteratorModeUAX14:
+            ASSERT_NOT_REACHED();
+            break;
+        case LineBreakIteratorModeUAX14Loose:
+            localeWithKeyword.appendLiteral("loose");
+            break;
+        case LineBreakIteratorModeUAX14Normal:
+            localeWithKeyword.appendLiteral("normal");
+            break;
+        case LineBreakIteratorModeUAX14Strict:
+            localeWithKeyword.appendLiteral("strict");
+            break;
+        }
+        return localeWithKeyword.toString();
+    }
+
+    TextBreakIterator* take(const AtomicString& locale, LineBreakIteratorMode mode, bool isCJK)
+    {
+        AtomicString localeWithOptionalBreakKeyword;
+        if (mode == LineBreakIteratorModeUAX14)
+            localeWithOptionalBreakKeyword = locale;
+        else
+            localeWithOptionalBreakKeyword = makeLocaleWithBreakKeyword(locale, mode);
+
+        TextBreakIterator* iterator = 0;
         for (size_t i = 0; i < m_pool.size(); ++i) {
-            if (m_pool[i].first == locale) {
+            if (m_pool[i].first == localeWithOptionalBreakKeyword) {
                 iterator = m_pool[i].second;
                 m_pool.remove(i);
                 break;
@@ -60,33 +90,22 @@
         }
 
         if (!iterator) {
-            UErrorCode openStatus = U_ZERO_ERROR;
-            bool localeIsEmpty = locale.isEmpty();
-            iterator = ubrk_open(UBRK_LINE, localeIsEmpty ? currentTextBreakLocaleID() : locale.string().utf8().data(), 0, 0, &openStatus);
-            // locale comes from a web page and it can be invalid, leading ICU
-            // to fail, in which case we fall back to the default locale.
-            if (!localeIsEmpty && U_FAILURE(openStatus)) {
-                openStatus = U_ZERO_ERROR;
-                iterator = ubrk_open(UBRK_LINE, currentTextBreakLocaleID(), 0, 0, &openStatus);
-            }
-                
-            if (U_FAILURE(openStatus)) {
-                LOG_ERROR("ubrk_open failed with status %d", openStatus);
+            iterator = openLineBreakIterator(localeWithOptionalBreakKeyword, mode, isCJK);
+            if (!iterator)
                 return 0;
-            }
         }
 
         ASSERT(!m_vendedIterators.contains(iterator));
-        m_vendedIterators.set(iterator, locale);
+        m_vendedIterators.set(iterator, localeWithOptionalBreakKeyword);
         return iterator;
     }
 
-    void put(UBreakIterator* iterator)
+    void put(TextBreakIterator* iterator)
     {
         ASSERT_ARG(iterator, m_vendedIterators.contains(iterator));
 
         if (m_pool.size() == capacity) {
-            ubrk_close(m_pool[0].second);
+            closeLineBreakIterator(m_pool[0].second);
             m_pool.remove(0);
         }
 
@@ -98,10 +117,10 @@
 
     static const size_t capacity = 4;
 
-    typedef std::pair<AtomicString, UBreakIterator*> Entry;
+    typedef std::pair<AtomicString, TextBreakIterator*> Entry;
     typedef Vector<Entry, capacity> Pool;
     Pool m_pool;
-    HashMap<UBreakIterator*, AtomicString> m_vendedIterators;
+    HashMap<TextBreakIterator*, AtomicString> m_vendedIterators;
 
     friend WTF::ThreadSpecific<LineBreakIteratorPool>::operator LineBreakIteratorPool*();
 };

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.cpp (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.cpp	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.cpp	2015-02-06 01:40:21 UTC (rev 179734)
@@ -256,9 +256,9 @@
     return setTextForIterator(*staticCursorMovementIterator, string);
 }
 
-TextBreakIterator* acquireLineBreakIterator(StringView string, const AtomicString& locale, const UChar* priorContext, unsigned priorContextLength)
+TextBreakIterator* acquireLineBreakIterator(StringView string, const AtomicString& locale, const UChar* priorContext, unsigned priorContextLength, LineBreakIteratorMode mode, bool isCJK)
 {
-    TextBreakIterator* iterator = reinterpret_cast<TextBreakIterator*>(LineBreakIteratorPool::sharedPool().take(locale));
+    TextBreakIterator* iterator = LineBreakIteratorPool::sharedPool().take(locale, mode, isCJK);
     if (!iterator)
         return nullptr;
 
@@ -269,9 +269,475 @@
 {
     ASSERT_ARG(iterator, iterator);
 
-    LineBreakIteratorPool::sharedPool().put(reinterpret_cast<UBreakIterator*>(iterator));
+    LineBreakIteratorPool::sharedPool().put(iterator);
 }
 
+static const char* uax14Prologue =
+    "!!chain;"
+    "!!LBCMNoChain;"
+    "!!lookAheadHardBreak;";
+
+static const char* uax14AssignmentsBefore =
+    // explicitly enumerate $CJ since ICU versions prior to 49 don't support :LineBreak=Conditional_Japanese_Starter:
+    "$CJ = ["
+#if (U_ICU_VERSION_MAJOR_NUM >= 4) && (U_ICU_VERSION_MINOR_NUM >= 9)
+    ":LineBreak=Conditional_Japanese_Starter:"
+#else
+    "\\u3041\\u3043\\u3045\\u3047\\u3049\\u3063\\u3083\\u3085\\u3087\\u308E\\u3095\\u3096\\u30A1\\u30A3\\u30A5\\u30A7"
+    "\\u30A9\\u30C3\\u30E3\\u30E5\\u30E7\\u30EE\\u30F5\\u30F6\\u30FC"
+    "\\u31F0\\u31F1\\u31F2\\u31F3\\u31F4\\u31F5\\u31F6\\u31F7\\u31F8\\u31F9\\u31FA\\u31FB\\u31FC\\u31FD\\u31FE\\u31FF"
+    "\\uFF67\\uFF68\\uFF69\\uFF6A\\uFF6B\\uFF6C\\uFF6D\\uFF6E\\uFF6F\\uFF70"
+#endif
+    "];";
+
+static const char* uax14AssignmentsCustomLooseCJK =
+    "$BA_SUB = [\\u2010\\u2013];"
+    "$EX_SUB = [\\u0021\\u003F\\uFF01\\uFF1F];"
+    "$ID_SUB = '';"
+    "$IN_SUB = [\\u2025\\u2026];"
+    "$IS_SUB = [\\u003A\\u003B];"
+    "$NS_SUB = [\\u203C\\u2047\\u2048\\u2049\\u3005\\u301C\\u303B\\u309D\\u309E\\u30A0\\u30FB\\u30FD\\u30FE\\uFF1A\\uFF1B\\uFF65];"
+    "$PO_SUB = [\\u0025\\u00A2\\u00B0\\u2030\\u2032\\u2033\\u2103\\uFF05\\uFFE0];"
+    "$PR_SUB = [\\u0024\\u00A3\\u00A5\\u20AC\\u2116\\uFF04\\uFFE1\\uFFE5];"
+    "$ID_ADD = [$CJ $BA_SUB $EX_SUB $IN_SUB $IS_SUB $NS_SUB $PO_SUB $PR_SUB];"
+    "$NS_ADD = '';";
+
+static const char* uax14AssignmentsCustomLooseNonCJK =
+    "$BA_SUB = '';"
+    "$EX_SUB = '';"
+    "$ID_SUB = '';"
+    "$IN_SUB = [\\u2025\\u2026];"
+    "$IS_SUB = '';"
+    "$NS_SUB = [\\u3005\\u303B\\u309D\\u309E\\u30FD\\u30FE];"
+    "$PO_SUB = '';"
+    "$PR_SUB = '';"
+    "$ID_ADD = [$CJ $IN_SUB $NS_SUB];"
+    "$NS_ADD = '';";
+
+static const char* uax14AssignmentsCustomNormalCJK =
+    "$BA_SUB = [\\u2010\\u2013];"
+    "$EX_SUB = '';"
+    "$IN_SUB = '';"
+    "$ID_SUB = '';"
+    "$IS_SUB = '';"
+    "$NS_SUB = [\\u301C\\u30A0];"
+    "$PO_SUB = '';"
+    "$PR_SUB = '';"
+    "$ID_ADD = [$CJ $BA_SUB $NS_SUB];"
+    "$NS_ADD = '';";
+
+static const char* uax14AssignmentsCustomNormalNonCJK =
+    "$BA_SUB = '';"
+    "$EX_SUB = '';"
+    "$ID_SUB = '';"
+    "$IN_SUB = '';"
+    "$IS_SUB = '';"
+    "$NS_SUB = '';"
+    "$PO_SUB = '';"
+    "$PR_SUB = '';"
+    "$ID_ADD = [$CJ];"
+    "$NS_ADD = '';";
+
+static const char* uax14AssignmentsCustomStrictCJK =
+    "$BA_SUB = '';"
+    "$EX_SUB = '';"
+    "$ID_SUB = '';"
+    "$IN_SUB = '';"
+    "$IS_SUB = '';"
+    "$NS_SUB = '';"
+    "$PO_SUB = '';"
+    "$PR_SUB = '';"
+    "$ID_ADD = '';"
+    "$NS_ADD = [$CJ];";
+
+#define uax14AssignmentsCustomStrictNonCJK      uax14AssignmentsCustomStrictCJK
+#define uax14AssignmentsCustomDefaultCJK        uax14AssignmentsCustomNormalCJK
+#define uax14AssignmentsCustomDefaultNonCJK     uax14AssignmentsCustomStrictNonCJK
+
+static const char* uax14AssignmentsAfter =
+    "$AI = [:LineBreak = Ambiguous:];"
+    "$AL = [:LineBreak = Alphabetic:];"
+    "$BA = [[:LineBreak = Break_After:] - $BA_SUB];"
+    "$BB = [:LineBreak = Break_Before:];"
+    "$BK = [:LineBreak = Mandatory_Break:];"
+    "$B2 = [:LineBreak = Break_Both:];"
+    "$CB = [:LineBreak = Contingent_Break:];"
+    "$CL = [:LineBreak = Close_Punctuation:];"
+    "$CM = [:LineBreak = Combining_Mark:];"
+    "$CP = [:LineBreak = Close_Parenthesis:];"
+    "$CR = [:LineBreak = Carriage_Return:];"
+    "$EX = [[:LineBreak = Exclamation:] - $EX_SUB];"
+    "$GL = [:LineBreak = Glue:];"
+#if (U_ICU_VERSION_MAJOR_NUM >= 4) && (U_ICU_VERSION_MINOR_NUM >= 9)
+    "$HL = [:LineBreak = Hebrew_Letter:];"
+#else
+    "$HL = [[:Hebrew:] & [:Letter:]];"
+#endif
+    "$HY = [:LineBreak = Hyphen:];"
+    "$H2 = [:LineBreak = H2:];"
+    "$H3 = [:LineBreak = H3:];"
+    "$ID = [[[[:LineBreak = Ideographic:] - $CJ] $ID_ADD] - $ID_SUB];"
+    "$IN = [[:LineBreak = Inseparable:] - $IN_SUB];"
+    "$IS = [[:LineBreak = Infix_Numeric:] - $IS_SUB];"
+    "$JL = [:LineBreak = JL:];"
+    "$JV = [:LineBreak = JV:];"
+    "$JT = [:LineBreak = JT:];"
+    "$LF = [:LineBreak = Line_Feed:];"
+    "$NL = [:LineBreak = Next_Line:];"
+    "$NS = [[[[:LineBreak = Nonstarter:] - $CJ] $NS_ADD] - $NS_SUB];"
+    "$NU = [:LineBreak = Numeric:];"
+    "$OP = [:LineBreak = Open_Punctuation:];"
+    "$PO = [[:LineBreak = Postfix_Numeric:] - $PO_SUB];"
+    "$PR = [[:LineBreak = Prefix_Numeric:] - $PR_SUB];"
+    "$QU = [:LineBreak = Quotation:];"
+    "$SA = [:LineBreak = Complex_Context:];"
+    "$SG = [:LineBreak = Surrogate:];"
+    "$SP = [:LineBreak = Space:];"
+    "$SY = [:LineBreak = Break_Symbols:];"
+    "$WJ = [:LineBreak = Word_Joiner:];"
+    "$XX = [:LineBreak = Unknown:];"
+    "$ZW = [:LineBreak = ZWSpace:];"
+    "$dictionary = [:LineBreak = Complex_Context:];"
+    "$ALPlus = [$AL $AI $SA $SG $XX];"
+    "$ALcm = $ALPlus $CM*;"
+    "$BAcm = $BA $CM*;"
+    "$BBcm = $BB $CM*;"
+    "$B2cm = $B2 $CM*;"
+    "$CLcm = $CL $CM*;"
+    "$CPcm = $CP $CM*;"
+    "$EXcm = $EX $CM*;"
+    "$GLcm = $GL $CM*;"
+    "$HLcm = $HL $CM*;"
+    "$HYcm = $HY $CM*;"
+    "$H2cm = $H2 $CM*;"
+    "$H3cm = $H3 $CM*;"
+    "$IDcm = $ID $CM*;"
+    "$INcm = $IN $CM*;"
+    "$IScm = $IS $CM*;"
+    "$JLcm = $JL $CM*;"
+    "$JVcm = $JV $CM*;"
+    "$JTcm = $JT $CM*;"
+    "$NScm = $NS $CM*;"
+    "$NUcm = $NU $CM*;"
+    "$OPcm = $OP $CM*;"
+    "$POcm = $PO $CM*;"
+    "$PRcm = $PR $CM*;"
+    "$QUcm = $QU $CM*;"
+    "$SYcm = $SY $CM*;"
+    "$WJcm = $WJ $CM*;";
+
+static const char* uax14Forward =
+    "!!forward;"
+    "$CAN_CM = [^$SP $BK $CR $LF $NL $ZW $CM];"
+    "$CANT_CM = [$SP $BK $CR $LF $NL $ZW $CM];"
+    "$AL_FOLLOW_NOCM = [$BK $CR $LF $NL $ZW $SP];"
+    "$AL_FOLLOW_CM = [$CL $CP $EX $HL $IS $SY $WJ $GL $OP $QU $BA $HY $NS $IN $NU $ALPlus];"
+    "$AL_FOLLOW = [$AL_FOLLOW_NOCM $AL_FOLLOW_CM];"
+    "$LB4Breaks = [$BK $CR $LF $NL];"
+    "$LB4NonBreaks = [^$BK $CR $LF $NL];"
+    "$LB8Breaks = [$LB4Breaks $ZW];"
+    "$LB8NonBreaks = [[$LB4NonBreaks] - [$ZW]];"
+    "$LB18NonBreaks = [$LB8NonBreaks - [$SP]];"
+    "$LB18Breaks = [$LB8Breaks $SP];"
+    "$LB20NonBreaks = [$LB18NonBreaks - $CB];"
+    "$ALPlus $CM+;"
+    "$BA $CM+;"
+    "$BB $CM+;"
+    "$B2 $CM+;"
+    "$CL $CM+;"
+    "$CP $CM+;"
+    "$EX $CM+;"
+    "$GL $CM+;"
+    "$HL $CM+;"
+    "$HY $CM+;"
+    "$H2 $CM+;"
+    "$H3 $CM+;"
+    "$ID $CM+;"
+    "$IN $CM+;"
+    "$IS $CM+;"
+    "$JL $CM+;"
+    "$JV $CM+;"
+    "$JT $CM+;"
+    "$NS $CM+;"
+    "$NU $CM+;"
+    "$OP $CM+;"
+    "$PO $CM+;"
+    "$PR $CM+;"
+    "$QU $CM+;"
+    "$SY $CM+;"
+    "$WJ $CM+;"
+    "$CR $LF {100};"
+    "$LB4NonBreaks? $LB4Breaks {100};"
+    "$CAN_CM $CM* $LB4Breaks {100};"
+    "$CM+ $LB4Breaks {100};"
+    "$LB4NonBreaks [$SP $ZW];"
+    "$CAN_CM $CM* [$SP $ZW];"
+    "$CM+ [$SP $ZW];"
+    "$CAN_CM $CM+;"
+    "$CM+;"
+    "$CAN_CM $CM* $WJcm;"
+    "$LB8NonBreaks $WJcm;"
+    "$CM+ $WJcm;"
+    "$WJcm $CANT_CM;"
+    "$WJcm $CAN_CM $CM*;"
+    "$GLcm $CAN_CM $CM*;"
+    "$GLcm $CANT_CM;"
+    "[[$LB8NonBreaks] - [$SP $BA $HY]] $CM* $GLcm;"
+    "$CM+ GLcm;"
+    "$LB8NonBreaks $CL;"
+    "$CAN_CM $CM* $CL;"
+    "$CM+ $CL;"
+    "$LB8NonBreaks $CP;"
+    "$CAN_CM $CM* $CP;"
+    "$CM+ $CP;"
+    "$LB8NonBreaks $EX;"
+    "$CAN_CM $CM* $EX;"
+    "$CM+ $EX;"
+    "$LB8NonBreaks $IS;"
+    "$CAN_CM $CM* $IS;"
+    "$CM+ $IS;"
+    "$LB8NonBreaks $SY;"
+    "$CAN_CM $CM* $SY;"
+    "$CM+ $SY;"
+    "$OPcm $SP* $CAN_CM $CM*;"
+    "$OPcm $SP* $CANT_CM;"
+    "$OPcm $SP+ $CM+ $AL_FOLLOW?;"
+    "$QUcm $SP* $OPcm;"
+    "($CLcm | $CPcm) $SP* $NScm;"
+    "$B2cm $SP* $B2cm;"
+    "$LB18NonBreaks $CM* $QUcm;"
+    "$CM+ $QUcm;"
+    "$QUcm .?;"
+    "$QUcm $LB18NonBreaks $CM*;"
+    "$LB20NonBreaks $CM* ($BAcm | $HYcm | $NScm); "
+    "$BBcm [^$CB];"
+    "$BBcm $LB20NonBreaks $CM*;"
+    "$HLcm ($HYcm | $BAcm) [^$CB]?;"
+    "($ALcm | $HLcm) $INcm;"
+    "$CM+ $INcm;"
+    "$IDcm $INcm;"
+    "$INcm $INcm;"
+    "$NUcm $INcm;"
+    "$IDcm $POcm;"
+    "$ALcm $NUcm;"
+    "$HLcm $NUcm;"
+    "$CM+ $NUcm;"
+    "$NUcm $ALcm;"
+    "$NUcm $HLcm;"
+    "$PRcm $IDcm;"
+    "$PRcm ($ALcm | $HLcm);"
+    "$POcm ($ALcm | $HLcm);"
+    "($PRcm | $POcm)? ($OPcm | $HYcm)? $NUcm ($NUcm | $SYcm | $IScm)* ($CLcm | $CPcm)? ($PRcm | $POcm)?;"
+    "$JLcm ($JLcm | $JVcm | $H2cm | $H3cm);"
+    "($JVcm | $H2cm) ($JVcm | $JTcm);"
+    "($JTcm | $H3cm) $JTcm;"
+    "($JLcm | $JVcm | $JTcm | $H2cm | $H3cm) $INcm;"
+    "($JLcm | $JVcm | $JTcm | $H2cm | $H3cm) $POcm;"
+    "$PRcm ($JLcm | $JVcm | $JTcm | $H2cm | $H3cm);"
+    "($ALcm | $HLcm) ($ALcm | $HLcm);"
+    "$CM+ ($ALcm | $HLcm);"
+    "$IScm ($ALcm | $HLcm);"
+    "($ALcm | $HLcm | $NUcm) $OPcm;"
+    "$CM+ $OPcm;"
+    "$CPcm ($ALcm | $HLcm | $NUcm);";
+
+static const char* uax14Reverse =
+    "!!reverse;"
+    "$CM+ $ALPlus;"
+    "$CM+ $BA;"
+    "$CM+ $BB;"
+    "$CM+ $B2;"
+    "$CM+ $CL;"
+    "$CM+ $CP;"
+    "$CM+ $EX;"
+    "$CM+ $GL;"
+    "$CM+ $HL;"
+    "$CM+ $HY;"
+    "$CM+ $H2;"
+    "$CM+ $H3;"
+    "$CM+ $ID;"
+    "$CM+ $IN;"
+    "$CM+ $IS;"
+    "$CM+ $JL;"
+    "$CM+ $JV;"
+    "$CM+ $JT;"
+    "$CM+ $NS;"
+    "$CM+ $NU;"
+    "$CM+ $OP;"
+    "$CM+ $PO;"
+    "$CM+ $PR;"
+    "$CM+ $QU;"
+    "$CM+ $SY;"
+    "$CM+ $WJ;"
+    "$CM+;"
+    "$AL_FOLLOW $CM+ / ([$BK $CR $LF $NL $ZW {eof}] | $SP+ $CM+ $SP | $SP+ $CM* ([^$OP $CM $SP] | [$AL {eof}]));"
+    "[$PR] / $CM+ [$BK $CR $LF $NL $ZW $SP {eof}];"
+    "$LB4Breaks [$LB4NonBreaks-$CM];"
+    "$LB4Breaks $CM+ $CAN_CM;"
+    "$LF $CR;"
+    "[$SP $ZW] [$LB4NonBreaks-$CM];"
+    "[$SP $ZW] $CM+ $CAN_CM;"
+    "$CM+ $CAN_CM;"
+    "$CM* $WJ $CM* $CAN_CM;"
+    "$CM* $WJ [$LB8NonBreaks-$CM];"
+    "$CANT_CM $CM* $WJ;"
+    "$CM* $CAN_CM $CM* $WJ;"
+    "$CM* $GL $CM* [$LB8NonBreaks-[$CM $SP $BA $HY]];"
+    "$CANT_CM $CM* $GL;"
+    "$CM* $CAN_CM $CM* $GL;"
+    "$CL $CM+ $CAN_CM;"
+    "$CP $CM+ $CAN_CM;"
+    "$EX $CM+ $CAN_CM;"
+    "$IS $CM+ $CAN_CM;"
+    "$SY $CM+ $CAN_CM;"
+    "$CL [$LB8NonBreaks-$CM];"
+    "$CP [$LB8NonBreaks-$CM];"
+    "$EX [$LB8NonBreaks-$CM];"
+    "$IS [$LB8NonBreaks-$CM];"
+    "$SY [$LB8NonBreaks-$CM];"
+    "[$CL $CP $EX $IS $SY] $CM+ $SP+ $CM* $OP; "
+    "$CM* $CAN_CM $SP* $CM* $OP;"
+    "$CANT_CM $SP* $CM* $OP;"
+    "$AL_FOLLOW? $CM+ $SP $SP* $CM* $OP;"
+    "$AL_FOLLOW_NOCM $CM+ $SP+ $CM* $OP;"
+    "$CM* $AL_FOLLOW_CM $CM+ $SP+ $CM* $OP;"
+    "$SY $CM $SP+ $OP;"
+    "$CM* $OP $SP* $CM* $QU;"
+    "$CM* $NS $SP* $CM* ($CL | $CP);"
+    "$CM* $B2 $SP* $CM* $B2;"
+    "$CM* $QU $CM* $CAN_CM;"
+    "$CM* $QU $LB18NonBreaks;"
+    "$CM* $CAN_CM $CM* $QU;"
+    "$CANT_CM $CM* $QU;"
+    "$CM* ($BA | $HY | $NS) $CM* [$LB20NonBreaks-$CM];"
+    "$CM* [$LB20NonBreaks-$CM] $CM* $BB;"
+    "[^$CB] $CM* $BB;"
+    "[^$CB] $CM* ($HY | $BA) $CM* $HL;"
+    "$CM* $IN $CM* ($ALPlus | $HL);"
+    "$CM* $IN $CM* $ID;"
+    "$CM* $IN $CM* $IN;"
+    "$CM* $IN $CM* $NU;"
+    "$CM* $PO $CM* $ID;"
+    "$CM* $NU $CM* ($ALPlus | $HL);"
+    "$CM* ($ALPlus | $HL) $CM* $NU;"
+    "$CM* $ID $CM* $PR;"
+    "$CM* ($ALPlus | $HL) $CM* $PR;"
+    "$CM* ($ALPlus | $HL) $CM* $PO;"
+    "($CM* ($PR | $PO))? ($CM* ($CL | $CP))? ($CM* ($NU | $IS | $SY))* $CM* $NU ($CM* ($OP | $HY))? ($CM* ($PR | $PO))?;"
+    "$CM* ($H3 | $H2 | $JV | $JL) $CM* $JL;"
+    "$CM* ($JT | $JV) $CM* ($H2 | $JV);"
+    "$CM* $JT $CM* ($H3 | $JT);"
+    "$CM* $IN $CM* ($H3 | $H2 | $JT | $JV | $JL);"
+    "$CM* $PO $CM* ($H3 | $H2 | $JT | $JV | $JL);"
+    "$CM* ($H3 | $H2 | $JT | $JV | $JL) $CM* $PR;"
+    "$CM* ($ALPlus | $HL) $CM* ($ALPlus | $HL);"
+    "$CM* ($ALPlus | $HL) $CM* $IS;"
+    "$CM* $OP $CM* ($ALPlus | $HL | $NU);"
+    "$CM* ($ALPlus | $HL | $NU) $CM* $CP;";
+
+static const char* uax14SafeForward =
+    "!!safe_forward;"
+    "[$CM $OP $QU $CL $CP $B2 $PR $HY $BA $SP $dictionary]+ [^$CM $OP $QU $CL $CP $B2 $PR $HY $BA $dictionary];"
+    "$dictionary $dictionary;";
+
+static const char* uax14SafeReverse =
+    "!!safe_reverse;"
+    "$CM+ [^$CM $BK $CR $LF $NL $ZW $SP];"
+    "$CM+ $SP / .;"
+    "$SP+ $CM* $OP;"
+    "$SP+ $CM* $QU;"
+    "$SP+ $CM* ($CL | $CP);"
+    "$SP+ $CM* $B2;"
+    "$CM* ($HY | $BA) $CM* $HL;"
+    "($CM* ($IS | $SY))+ $CM* $NU;"
+    "($CL | $CP) $CM* ($NU | $IS | $SY);"
+    "$dictionary $dictionary;";
+
+static String mapLineIteratorModeToRules(LineBreakIteratorMode mode, bool isCJK)
+{
+    StringBuilder rulesBuilder;
+    rulesBuilder.append(uax14Prologue);
+    rulesBuilder.append(uax14AssignmentsBefore);
+    switch (mode) {
+    case LineBreakIteratorModeUAX14:
+        rulesBuilder.append(isCJK ? uax14AssignmentsCustomDefaultCJK : uax14AssignmentsCustomDefaultNonCJK);
+        break;
+    case LineBreakIteratorModeUAX14Loose:
+        rulesBuilder.append(isCJK ? uax14AssignmentsCustomLooseCJK : uax14AssignmentsCustomLooseNonCJK);
+        break;
+    case LineBreakIteratorModeUAX14Normal:
+        rulesBuilder.append(isCJK ? uax14AssignmentsCustomNormalCJK : uax14AssignmentsCustomNormalNonCJK);
+        break;
+    case LineBreakIteratorModeUAX14Strict:
+        rulesBuilder.append(isCJK ? uax14AssignmentsCustomStrictCJK : uax14AssignmentsCustomStrictNonCJK);
+        break;
+    }
+    rulesBuilder.append(uax14AssignmentsAfter);
+    rulesBuilder.append(uax14Forward);
+    rulesBuilder.append(uax14Reverse);
+    rulesBuilder.append(uax14SafeForward);
+    rulesBuilder.append(uax14SafeReverse);
+    return rulesBuilder.toString();
+}
+
+// Recognize BCP47 compliant primary language values of 'zh', 'ja', 'ko'
+// (in any combination of case), optionally followed by subtags. Don't
+// recognize 3-letter variants 'chi'/'zho', 'jpn', or 'kor' since BCP47
+// requires use of shortest language tag.
+bool isCJKLocale(const AtomicString& locale)
+{
+    size_t length = locale.length();
+    if (length < 2)
+        return false;
+    auto c1 = locale[0];
+    auto c2 = locale[1];
+    auto c3 = length == 2 ? 0 : locale[2];
+    if (!c3 || c3 == '-' || c3 == '_' || c3 == '@') {
+        if (c1 == 'z' || c1 == 'Z')
+            return c2 == 'h' || c2 == 'H';
+        if (c1 == 'j' || c1 == 'J')
+            return c2 == 'a' || c2 == 'A';
+        if (c1 == 'k' || c1 == 'K')
+            return c2 == 'o' || c2 == 'O';
+    }
+    return false;
+}
+
+TextBreakIterator* openLineBreakIterator(const AtomicString& locale, LineBreakIteratorMode mode, bool isCJK)
+{
+    UBreakIterator* ubrkIter;
+    UErrorCode openStatus = U_ZERO_ERROR;
+    bool localeIsEmpty = locale.isEmpty();
+    if (mode == LineBreakIteratorModeUAX14)
+        ubrkIter = ubrk_open(UBRK_LINE, localeIsEmpty ? currentTextBreakLocaleID() : locale.string().utf8().data(), 0, 0, &openStatus);
+    else {
+        UParseError parseStatus;
+        auto rules = mapLineIteratorModeToRules(mode, isCJK);
+        ubrkIter = ubrk_openRules(StringView(rules).upconvertedCharacters(), rules.length(), 0, 0, &parseStatus, &openStatus);
+    }
+    // locale comes from a web page and it can be invalid, leading ICU
+    // to fail, in which case we fall back to the default locale.
+    if (!localeIsEmpty && U_FAILURE(openStatus)) {
+        openStatus = U_ZERO_ERROR;
+        ubrkIter = ubrk_open(UBRK_LINE, currentTextBreakLocaleID(), 0, 0, &openStatus);
+    }
+
+    if (U_FAILURE(openStatus)) {
+        LOG_ERROR("ubrk_open failed with status %d", openStatus);
+        return nullptr;
+    }
+
+    return reinterpret_cast<TextBreakIterator*>(ubrkIter);
+}
+
+void closeLineBreakIterator(TextBreakIterator*& iterator)
+{
+    UBreakIterator* ubrkIter = reinterpret_cast<UBreakIterator*>(iterator);
+    ASSERT(ubrkIter);
+    ubrk_close(ubrkIter);
+    iterator = nullptr;
+}
+
 static TextBreakIterator* nonSharedCharacterBreakIterator;
 
 static inline bool compareAndSwapNonSharedCharacterBreakIterator(TextBreakIterator* expected, TextBreakIterator* newValue)

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.h (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.h	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/platform/text/TextBreakIterator.h	2015-02-06 01:40:21 UTC (rev 179734)
@@ -31,6 +31,13 @@
 
 // Note: The returned iterator is good only until you get another iterator, with the exception of acquireLineBreakIterator.
 
+enum LineBreakIteratorMode {
+    LineBreakIteratorModeUAX14,
+    LineBreakIteratorModeUAX14Loose,
+    LineBreakIteratorModeUAX14Normal,
+    LineBreakIteratorModeUAX14Strict,
+};
+
 // This is similar to character break iterator in most cases, but is subject to
 // platform UI conventions. One notable example where this can be different
 // from character break iterator is Thai prepend characters, see bug 24342.
@@ -40,8 +47,10 @@
 TextBreakIterator* wordBreakIterator(StringView);
 TextBreakIterator* sentenceBreakIterator(StringView);
 
-TextBreakIterator* acquireLineBreakIterator(StringView, const AtomicString& locale, const UChar* priorContext, unsigned priorContextLength);
+TextBreakIterator* acquireLineBreakIterator(StringView, const AtomicString& locale, const UChar* priorContext, unsigned priorContextLength, LineBreakIteratorMode, bool isCJK);
 void releaseLineBreakIterator(TextBreakIterator*);
+TextBreakIterator* openLineBreakIterator(const AtomicString& locale, LineBreakIteratorMode, bool isCJK);
+void closeLineBreakIterator(TextBreakIterator*&);
 
 int textBreakFirst(TextBreakIterator*);
 int textBreakLast(TextBreakIterator*);
@@ -55,24 +64,30 @@
 
 const int TextBreakDone = -1;
 
+bool isCJKLocale(const AtomicString&);
+
 class LazyLineBreakIterator {
 public:
     LazyLineBreakIterator()
-        : m_iterator(0)
-        , m_cachedPriorContext(0)
+        : m_iterator(nullptr)
+        , m_cachedPriorContext(nullptr)
+        , m_mode(LineBreakIteratorModeUAX14)
         , m_cachedPriorContextLength(0)
+        , m_isCJK(false)
     {
         resetPriorContext();
     }
 
-    LazyLineBreakIterator(String string, const AtomicString& locale = AtomicString())
+    LazyLineBreakIterator(String string, const AtomicString& locale = AtomicString(), LineBreakIteratorMode mode = LineBreakIteratorModeUAX14)
         : m_string(string)
         , m_locale(locale)
-        , m_iterator(0)
-        , m_cachedPriorContext(0)
+        , m_iterator(nullptr)
+        , m_cachedPriorContext(nullptr)
+        , m_mode(mode)
         , m_cachedPriorContextLength(0)
     {
         resetPriorContext();
+        m_isCJK = isCJKLocale(locale);
     }
 
     ~LazyLineBreakIterator()
@@ -82,35 +97,41 @@
     }
 
     String string() const { return m_string; }
+    bool isLooseCJKMode() const { return m_isCJK && m_mode == LineBreakIteratorModeUAX14Loose; }
 
     UChar lastCharacter() const
     {
         COMPILE_ASSERT(WTF_ARRAY_LENGTH(m_priorContext) == 2, TextBreakIterator_unexpected_prior_context_length);
         return m_priorContext[1];
     }
+
     UChar secondToLastCharacter() const
     {
         COMPILE_ASSERT(WTF_ARRAY_LENGTH(m_priorContext) == 2, TextBreakIterator_unexpected_prior_context_length);
         return m_priorContext[0];
     }
+
     void setPriorContext(UChar last, UChar secondToLast)
     {
         COMPILE_ASSERT(WTF_ARRAY_LENGTH(m_priorContext) == 2, TextBreakIterator_unexpected_prior_context_length);
         m_priorContext[0] = secondToLast;
         m_priorContext[1] = last;
     }
+
     void updatePriorContext(UChar last)
     {
         COMPILE_ASSERT(WTF_ARRAY_LENGTH(m_priorContext) == 2, TextBreakIterator_unexpected_prior_context_length);
         m_priorContext[0] = m_priorContext[1];
         m_priorContext[1] = last;
     }
+
     void resetPriorContext()
     {
         COMPILE_ASSERT(WTF_ARRAY_LENGTH(m_priorContext) == 2, TextBreakIterator_unexpected_prior_context_length);
         m_priorContext[0] = 0;
         m_priorContext[1] = 0;
     }
+
     unsigned priorContextLength() const
     {
         unsigned priorContextLength = 0;
@@ -122,6 +143,7 @@
         }
         return priorContextLength;
     }
+
     // Obtain text break iterator, possibly previously cached, where this iterator is (or has been)
     // initialized to use the previously stored string as the primary breaking context and using
     // previously stored prior context if non-empty.
@@ -130,23 +152,26 @@
         ASSERT(priorContextLength <= priorContextCapacity);
         const UChar* priorContext = priorContextLength ? &m_priorContext[priorContextCapacity - priorContextLength] : 0;
         if (!m_iterator) {
-            m_iterator = acquireLineBreakIterator(m_string, m_locale, priorContext, priorContextLength);
+            m_iterator = acquireLineBreakIterator(m_string, m_locale, priorContext, priorContextLength, m_mode, m_isCJK);
             m_cachedPriorContext = priorContext;
             m_cachedPriorContextLength = priorContextLength;
         } else if (priorContext != m_cachedPriorContext || priorContextLength != m_cachedPriorContextLength) {
-            this->resetStringAndReleaseIterator(m_string, m_locale);
+            resetStringAndReleaseIterator(m_string, m_locale, m_mode);
             return this->get(priorContextLength);
         }
         return m_iterator;
     }
-    void resetStringAndReleaseIterator(String string, const AtomicString& locale)
+
+    void resetStringAndReleaseIterator(String string, const AtomicString& locale, LineBreakIteratorMode mode)
     {
         if (m_iterator)
             releaseLineBreakIterator(m_iterator);
         m_string = string;
         m_locale = locale;
-        m_iterator = 0;
-        m_cachedPriorContext = 0;
+        m_iterator = nullptr;
+        m_cachedPriorContext = nullptr;
+        m_mode = mode;
+        m_isCJK = isCJKLocale(locale);
         m_cachedPriorContextLength = 0;
     }
 
@@ -155,9 +180,11 @@
     String m_string;
     AtomicString m_locale;
     TextBreakIterator* m_iterator;
-    UChar m_priorContext[priorContextCapacity];
     const UChar* m_cachedPriorContext;
+    LineBreakIteratorMode m_mode;
     unsigned m_cachedPriorContextLength;
+    UChar m_priorContext[priorContextCapacity];
+    bool m_isCJK;
 };
 
 // Iterates over "extended grapheme clusters", as defined in UAX #29.

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.cpp (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.cpp	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.cpp	2015-02-06 01:40:21 UTC (rev 179734)
@@ -597,6 +597,22 @@
     return m_maxWidth;
 }
 
+LineBreakIteratorMode mapLineBreakToIteratorMode(LineBreak lineBreak)
+{
+    switch (lineBreak) {
+    case LineBreakAuto:
+    case LineBreakAfterWhiteSpace:
+        return LineBreakIteratorModeUAX14;
+    case LineBreakLoose:
+        return LineBreakIteratorModeUAX14Loose;
+    case LineBreakNormal:
+        return LineBreakIteratorModeUAX14Normal;
+    case LineBreakStrict:
+        return LineBreakIteratorModeUAX14Strict;
+    }
+    return LineBreakIteratorModeUAX14;
+}
+
 void RenderText::computePreferredLogicalWidths(float leadWidth)
 {
     HashSet<const SimpleFontData*> fallbackFonts;
@@ -673,7 +689,7 @@
     const Font& font = style.font(); // FIXME: This ignores first-line.
     float wordSpacing = font.wordSpacing();
     int len = textLength();
-    LazyLineBreakIterator breakIterator(m_text, style.locale());
+    LazyLineBreakIterator breakIterator(m_text, style.locale(), mapLineBreakToIteratorMode(style.lineBreak()));
     bool needsWordSpacing = false;
     bool ignoringSpaces = false;
     bool isSpace = false;
@@ -708,6 +724,7 @@
 
     bool breakNBSP = style.autoWrap() && style.nbspMode() == SPACE;
     bool breakAll = (style.wordBreak() == BreakAllWordBreak || style.wordBreak() == BreakWordBreak) && style.autoWrap();
+    bool isLooseCJKMode = breakIterator.isLooseCJKMode();
 
     for (int i = 0; i < len; i++) {
         UChar c = uncheckedCharacterAt(i);
@@ -755,7 +772,7 @@
             continue;
         }
 
-        bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP);
+        bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP, isLooseCJKMode);
         bool betweenWords = true;
         int j = i;
         while (c != '\n' && !isSpaceAccordingToStyle(c, style) && c != '\t' && (c != softHyphen || style.hyphens() == HyphensNone)) {
@@ -763,7 +780,7 @@
             if (j == len)
                 break;
             c = uncheckedCharacterAt(j);
-            if (isBreakable(breakIterator, j, nextBreakable, breakNBSP) && characterAt(j - 1) != softHyphen)
+            if (isBreakable(breakIterator, j, nextBreakable, breakNBSP, isLooseCJKMode) && characterAt(j - 1) != softHyphen)
                 break;
             if (breakAll) {
                 betweenWords = false;

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.h (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.h	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/rendering/RenderText.h	2015-02-06 01:40:21 UTC (rev 179734)
@@ -27,6 +27,7 @@
 #include "RenderTextLineBoxes.h"
 #include "SimpleLineLayout.h"
 #include "Text.h"
+#include "TextBreakIterator.h"
 #include <wtf/Forward.h>
 
 namespace WebCore {
@@ -257,6 +258,7 @@
 
 void applyTextTransform(const RenderStyle&, String&, UChar);
 void makeCapitalized(String*, UChar previous);
+LineBreakIteratorMode mapLineBreakToIteratorMode(LineBreak);
     
 inline RenderText* Text::renderer() const
 {

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/rendering/SimpleLineLayout.cpp (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/rendering/SimpleLineLayout.cpp	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/rendering/SimpleLineLayout.cpp	2015-02-06 01:40:21 UTC (rev 179734)
@@ -162,6 +162,8 @@
         return false;
     if (style.borderFit() == BorderFitLines)
         return false;
+    if (style.lineBreak() != LineBreakAuto)
+        return false;
     const RenderText& textRenderer = toRenderText(*flow.firstChild());
     if (flow.containsFloats()) {
         // We can't use the code path if any lines would need to be shifted below floats. This is because we don't keep per-line y coordinates.
@@ -283,7 +285,7 @@
         if (!style.collapseWhitespace && isWhitespace(text[wordStart], style.preserveNewline))
             wordEnd = wordStart + 1;
         else
-            wordEnd = nextBreakablePosition<CharacterType, false>(lineBreakIterator, text, textLength, wordStart + 1);
+            wordEnd = nextBreakablePositionNonLoosely<CharacterType, NBSPBehavior::IgnoreNBSP>(lineBreakIterator, text, textLength, wordStart + 1);
 
         bool wordIsPrecededByWhitespace = style.collapseWhitespace && wordStart > lineStart && isWhitespace(text[wordStart - 1], style.preserveNewline);
         if (wordIsPrecededByWhitespace)

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/rendering/break_lines.h (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/rendering/break_lines.h	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/rendering/break_lines.h	2015-02-06 01:40:21 UTC (rev 179734)
@@ -35,10 +35,12 @@
 
 extern const unsigned char asciiLineBreakTable[][asciiLineBreakTableColumnCount];
 
-int nextBreakablePositionIgnoringNBSP(LazyLineBreakIterator&, int pos);
-int nextBreakablePosition(LazyLineBreakIterator&, int pos);
+enum class NBSPBehavior {
+    IgnoreNBSP,
+    TreatNBSPAsBreak,
+};
 
-template<bool treatNoBreakSpaceAsBreak>
+template<NBSPBehavior nbspBehavior>
 static inline bool isBreakableSpace(UChar ch)
 {
     switch (ch) {
@@ -47,7 +49,7 @@
     case '\t':
         return true;
     case noBreakSpace:
-        return treatNoBreakSpaceAsBreak;
+        return nbspBehavior == NBSPBehavior::TreatNBSPAsBreak;
     default:
         return false;
     }
@@ -71,16 +73,17 @@
     return false;
 }
 
-template<bool treatNoBreakSpaceAsBreak>
+template<NBSPBehavior nbspBehavior>
 inline bool needsLineBreakIterator(UChar ch)
 {
-    if (treatNoBreakSpaceAsBreak)
+    if (nbspBehavior == NBSPBehavior::TreatNBSPAsBreak)
         return ch > asciiLineBreakTableLastChar;
     return ch > asciiLineBreakTableLastChar && ch != noBreakSpace;
 }
 
-template<typename CharacterType, bool treatNoBreakSpaceAsBreak>
-inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, const CharacterType* str, unsigned length, int pos)
+// When in non-loose mode, we can use the ASCII shortcut table.
+template<typename CharacterType, NBSPBehavior nbspBehavior>
+inline int nextBreakablePositionNonLoosely(LazyLineBreakIterator& lazyBreakIterator, const CharacterType* str, unsigned length, int pos)
 {
     int len = static_cast<int>(length);
     int nextBreak = -1;
@@ -91,10 +94,12 @@
     for (int i = pos; i < len; i++) {
         CharacterType ch = str[i];
 
-        if (isBreakableSpace<treatNoBreakSpaceAsBreak>(ch) || shouldBreakAfter(lastLastCh, lastCh, ch))
+        // Non-loose mode, so use ASCII shortcut (shouldBreakAfter) if not breakable space.
+        if (isBreakableSpace<nbspBehavior>(ch) || shouldBreakAfter(lastLastCh, lastCh, ch))
             return i;
 
-        if (needsLineBreakIterator<treatNoBreakSpaceAsBreak>(ch) || needsLineBreakIterator<treatNoBreakSpaceAsBreak>(lastCh)) {
+        // Non-loose mode, so conditionally use break iterator.
+        if (needsLineBreakIterator<nbspBehavior>(ch) || needsLineBreakIterator<nbspBehavior>(lastCh)) {
             if (nextBreak < i) {
                 // Don't break if positioned at start of primary context and there is no prior context.
                 if (i || priorContextLength) {
@@ -106,7 +111,7 @@
                     }
                 }
             }
-            if (i == nextBreak && !isBreakableSpace<treatNoBreakSpaceAsBreak>(lastCh))
+            if (i == nextBreak && !isBreakableSpace<nbspBehavior>(lastCh))
                 return i;
         }
 
@@ -117,26 +122,89 @@
     return len;
 }
 
+// When in loose mode, we can't use the ASCII shortcut table since loose mode allows "$100" to break after '$' in content marked as CJK.
+// N.B. It should be possible to combine the following with the non-loose version above by adding a LooseBehavior template parameter;
+// however, when doing this, a 10% performance regression appeared on chromium-win (https://bugs.webkit.org/show_bug.cgi?id=89235#c112).
+template<typename CharacterType, NBSPBehavior nbspBehavior>
+static inline int nextBreakablePositionLoosely(LazyLineBreakIterator& lazyBreakIterator, const CharacterType* str, unsigned length, int pos)
+{
+    int len = static_cast<int>(length);
+    int nextBreak = -1;
+
+    CharacterType lastCh = pos > 0 ? str[pos - 1] : static_cast<CharacterType>(lazyBreakIterator.lastCharacter());
+    unsigned priorContextLength = lazyBreakIterator.priorContextLength();
+    for (int i = pos; i < len; i++) {
+        CharacterType ch = str[i];
+
+        // Always loose mode, so don't use ASCII shortcut (shouldBreakAfter).
+        if (isBreakableSpace<nbspBehavior>(ch))
+            return i;
+
+        // Always use line break iterator in loose mode.
+        if (nextBreak < i) {
+            // Don't break if positioned at start of primary context and there is no prior context.
+            if (i || priorContextLength) {
+                TextBreakIterator* breakIterator = lazyBreakIterator.get(priorContextLength);
+                if (breakIterator) {
+                    nextBreak = textBreakFollowing(breakIterator, i - 1 + priorContextLength);
+                    if (nextBreak >= 0)
+                        nextBreak -= priorContextLength;
+                }
+            }
+        }
+        if (i == nextBreak && !isBreakableSpace<nbspBehavior>(lastCh))
+            return i;
+
+        lastCh = ch;
+    }
+
+    return len;
+}
+
+inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos)
+{
+    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);
+}
+
 inline int nextBreakablePositionIgnoringNBSP(LazyLineBreakIterator& lazyBreakIterator, int pos)
 {
     String string = lazyBreakIterator.string();
     if (string.is8Bit())
-        return nextBreakablePosition<LChar, false>(lazyBreakIterator, string.characters8(), string.length(), pos);
-    return nextBreakablePosition<UChar, false>(lazyBreakIterator, string.characters16(), string.length(), pos);
+        return nextBreakablePositionNonLoosely<LChar, NBSPBehavior::IgnoreNBSP>(lazyBreakIterator, string.characters8(), string.length(), pos);
+    return nextBreakablePositionNonLoosely<UChar, NBSPBehavior::IgnoreNBSP>(lazyBreakIterator, string.characters16(), string.length(), pos);
 }
 
-inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos)
+inline int nextBreakablePositionLoose(LazyLineBreakIterator& lazyBreakIterator, int pos)
 {
     String string = lazyBreakIterator.string();
     if (string.is8Bit())
-        return nextBreakablePosition<LChar, true>(lazyBreakIterator, string.characters8(), string.length(), pos);
-    return nextBreakablePosition<UChar, true>(lazyBreakIterator, string.characters16(), string.length(), pos);
+        return nextBreakablePositionLoosely<LChar, NBSPBehavior::TreatNBSPAsBreak>(lazyBreakIterator, string.characters8(), string.length(), pos);
+    return nextBreakablePositionLoosely<UChar, NBSPBehavior::TreatNBSPAsBreak>(lazyBreakIterator, string.characters16(), string.length(), pos);
 }
 
-inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP)
+inline int nextBreakablePositionIgnoringNBSPLoose(LazyLineBreakIterator& lazyBreakIterator, int pos)
 {
-    if (pos > nextBreakable) {
+    String string = lazyBreakIterator.string();
+    if (string.is8Bit())
+        return nextBreakablePositionLoosely<LChar, NBSPBehavior::IgnoreNBSP>(lazyBreakIterator, string.characters8(), string.length(), pos);
+    return nextBreakablePositionLoosely<UChar, NBSPBehavior::IgnoreNBSP>(lazyBreakIterator, string.characters16(), string.length(), pos);
+}
+
+inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP, bool isLooseMode)
+{
+    if (pos <= nextBreakable)
+        return pos == nextBreakable;
+
+    if (isLooseMode) {
         if (breakNBSP)
+            nextBreakable = nextBreakablePositionLoose(lazyBreakIterator, pos);
+        else
+            nextBreakable = nextBreakablePositionIgnoringNBSPLoose(lazyBreakIterator, pos);
+    } else {
+        if (breakNBSP)
             nextBreakable = nextBreakablePosition(lazyBreakIterator, pos);
         else
             nextBreakable = nextBreakablePositionIgnoringNBSP(lazyBreakIterator, pos);

Modified: branches/safari-600.1.4.15-branch/Source/WebCore/rendering/line/BreakingContextInlineHeaders.h (179733 => 179734)


--- branches/safari-600.1.4.15-branch/Source/WebCore/rendering/line/BreakingContextInlineHeaders.h	2015-02-06 01:34:07 UTC (rev 179733)
+++ branches/safari-600.1.4.15-branch/Source/WebCore/rendering/line/BreakingContextInlineHeaders.h	2015-02-06 01:40:21 UTC (rev 179734)
@@ -628,6 +628,7 @@
     bool midWordBreak = false;
     bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap;
     float hyphenWidth = 0;
+    bool isLooseCJKMode = false;
 
     if (isSVGText) {
         breakWords = false;
@@ -639,7 +640,8 @@
         m_renderTextInfo.m_text = renderText;
         m_renderTextInfo.m_font = &font;
         m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
-        m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(renderText->text(), style.locale());
+        m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(renderText->text(), style.locale(), mapLineBreakToIteratorMode(m_blockStyle.lineBreak()));
+        isLooseCJKMode = m_renderTextInfo.m_lineBreakIterator.isLooseCJKMode();
     } else if (m_renderTextInfo.m_layout && m_renderTextInfo.m_font != &font) {
         m_renderTextInfo.m_font = &font;
         m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
@@ -680,7 +682,7 @@
         }
 
         int nextBreakablePosition = m_current.nextBreakablePosition();
-        bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP)
+        bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP, isLooseCJKMode)
             && (style.hyphens() != HyphensNone || (m_current.previousInSameNode() != softHyphen)));
         m_current.setNextBreakablePosition(nextBreakablePosition);
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to