QTextBoundaryFinder: Introduce BoundaryReason::MandatoryBreak flag
authorKonstantin Ritt <ritt.ks@gmail.com>
Thu, 4 Oct 2012 03:52:13 +0000 (06:52 +0300)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 10 Oct 2012 11:26:13 +0000 (13:26 +0200)
that will be returned by boundaryReasons() when the boundary finder
is at the line end position (CR, LF, NewLine Function, End of Text, etc.).
The MandatoryBreak flag, if set, means the text should be wrapped at a given position.

Change-Id: I32d4f570935d2e015bfc5f18915396a15f009fde
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/3rdparty/harfbuzz/src/harfbuzz-shaper.h
src/corelib/tools/qtextboundaryfinder.cpp
src/corelib/tools/qtextboundaryfinder.h
src/corelib/tools/qunicodetools.cpp
src/corelib/tools/qunicodetools_p.h
tests/auto/corelib/tools/qtextboundaryfinder/tst_qtextboundaryfinder.cpp

index 5a3329d..e2891d0 100644 (file)
@@ -135,7 +135,7 @@ typedef struct {
     hb_bitfield whiteSpace       : 1;     /* A unicode whitespace character */
     hb_bitfield wordStart        : 1;
     hb_bitfield wordEnd          : 1;
-    hb_bitfield unused           : 1;
+    hb_bitfield mandatoryBreak   : 1;
 } HB_CharAttributes;
 
 void HB_GetTailoredCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength,
index 7f12032..416a14a 100644 (file)
@@ -162,6 +162,8 @@ static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int
   \value NotAtBoundary  The boundary finder is not at a boundary position.
   \value StartWord  The boundary finder is at the start of a word.
   \value EndWord  The boundary finder is at the end of a word.
+  \value MandatoryBreak  Since 5.0. The boundary finder is at the end of line
+                         (can occur for a Line boundary type only).
   \value SoftHyphen  The boundary finder is at the soft hyphen
                      (can occur for a Line boundary type only).
 */
@@ -477,7 +479,10 @@ QTextBoundaryFinder::BoundaryReasons QTextBoundaryFinder::boundaryReasons() cons
             reasons |= EndWord;
         break;
     case Line:
-        if (pos > 0 && chars[pos - 1].unicode() == QChar::SoftHyphen)
+        // ### TR#14 LB2 prohibits break at sot
+        if (d->attributes[pos].mandatoryBreak || pos == 0)
+            reasons |= MandatoryBreak;
+        else if (pos > 0 && chars[pos - 1].unicode() == QChar::SoftHyphen)
             reasons |= SoftHyphen;
         // fall through
     case Grapheme:
index 57c2fda..c752623 100644 (file)
@@ -69,9 +69,10 @@ public:
 
     enum BoundaryReason {
         NotAtBoundary = 0,
-        StartWord = 1,
-        EndWord = 2,
-        SoftHyphen = 4
+        StartWord = 0x10,
+        EndWord = 0x20,
+        MandatoryBreak = 0x40,
+        SoftHyphen = 0x80
     };
     Q_DECLARE_FLAGS( BoundaryReasons, BoundaryReason )
 
index 1f45575..3d58f16 100644 (file)
@@ -497,7 +497,7 @@ static void getLineBreaks(const ushort *string, quint32 len, QCharAttributes *at
         if (Q_UNLIKELY(lcls >= QUnicodeTables::LineBreak_CR)) {
             // LB4: BK!, LB5: (CRxLF|CR|LF|NL)!
             if (lcls > QUnicodeTables::LineBreak_CR || ncls != QUnicodeTables::LineBreak_LF)
-                attributes[pos].lineBreak = true;
+                attributes[pos].lineBreak = attributes[pos].mandatoryBreak = true;
             goto next;
         }
 
@@ -547,8 +547,8 @@ static void getLineBreaks(const ushort *string, quint32 len, QCharAttributes *at
             attributes[j].lineBreak = false;
     }
 
-    attributes[0].lineBreak = false; // LB2
-    attributes[len].lineBreak = true; // LB3
+    attributes[0].lineBreak = attributes[0].mandatoryBreak = false; // LB2
+    attributes[len].lineBreak = attributes[len].mandatoryBreak = true; // LB3
 }
 
 
index b1e9127..143a4fd 100644 (file)
@@ -66,7 +66,7 @@ struct Q_PACKED QCharAttributes
     uchar whiteSpace       : 1;
     uchar wordStart        : 1;
     uchar wordEnd          : 1;
-    uchar unused           : 1;
+    uchar mandatoryBreak   : 1;
 };
 Q_DECLARE_TYPEINFO(QCharAttributes, Q_PRIMITIVE_TYPE);
 
index 22d3465..a0aab34 100644 (file)
@@ -76,6 +76,8 @@ private slots:
     void wordBoundaries_qtbug6498();
     void isAtSoftHyphen_data();
     void isAtSoftHyphen();
+    void isAtMandatoryBreak_data();
+    void isAtMandatoryBreak();
     void thaiLineBreak();
 };
 
@@ -659,6 +661,41 @@ void tst_QTextBoundaryFinder::isAtSoftHyphen()
     }
 }
 
+void tst_QTextBoundaryFinder::isAtMandatoryBreak_data()
+{
+    QTest::addColumn<QString>("testString");
+    QTest::addColumn<QList<int> >("expectedBreakPositions");
+
+    {
+        QChar s[] = { 0x000D, 0x0308, 0x000A, 0x000A };
+        QString testString(s, sizeof(s)/sizeof(s[0]));
+        QList<int> expectedBreakPositions;
+        expectedBreakPositions << 0 << 1 << 3 << 4;
+
+        QTest::newRow("+CR+FExLF+LF+") << testString << expectedBreakPositions;
+    }
+    {
+        QString testString(QString::fromUtf8("Aaa bbb ccc.\r\nDdd eee fff."));
+        QList<int> expectedBreakPositions;
+        expectedBreakPositions << 0 << 14 << 26;
+
+        QTest::newRow("data1") << testString << expectedBreakPositions;
+    }
+}
+
+void tst_QTextBoundaryFinder::isAtMandatoryBreak()
+{
+    QFETCH(QString, testString);
+    QFETCH(QList<int>, expectedBreakPositions);
+
+    QTextBoundaryFinder boundaryFinder(QTextBoundaryFinder::Line, testString);
+    for (int i = 0; i <= testString.size(); ++i) {
+        boundaryFinder.setPosition(i);
+        if (boundaryFinder.boundaryReasons() & QTextBoundaryFinder::MandatoryBreak)
+            QVERIFY(expectedBreakPositions.contains(i));
+    }
+}
+
 #include <qlibrary.h>
 
 #define LIBTHAI_MAJOR   0