src/gui/text/qtextlayout.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
--- a/src/gui/text/qtextlayout.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/gui/text/qtextlayout.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -69,7 +69,7 @@
     if (!line.hasTrailingSpaces
         || (eng->option.flags() & QTextOption::IncludeTrailingSpaces)
         || !(eng->option.alignment() & Qt::AlignRight)
-        || (eng->option.textDirection() != Qt::RightToLeft))
+        || !eng->isRightToLeft())
         return QFixed();
 
     int pos = line.length;
@@ -86,12 +86,12 @@
     // if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned.
     if (!line.justified && line.width != QFIXED_MAX) {
         int align = eng->option.alignment();
-        if (align & Qt::AlignJustify && eng->option.textDirection() == Qt::RightToLeft)
+        if (align & Qt::AlignJustify && eng->isRightToLeft())
             align = Qt::AlignRight;
         if (align & Qt::AlignRight)
-            x = line.width - (line.textWidth + leadingSpaceWidth(eng, line));
+            x = line.width - (line.textAdvance + leadingSpaceWidth(eng, line));
         else if (align & Qt::AlignHCenter)
-            x = (line.width - line.textWidth)/2;
+            x = (line.width - line.textAdvance)/2;
     }
     return x;
 }
@@ -282,12 +282,11 @@
     \class QTextLayout
     \reentrant
 
-    \brief The QTextLayout class is used to lay out and paint a single
-    paragraph of text.
+    \brief The QTextLayout class is used to lay out and render text.
 
     \ingroup richtext-processing
 
-    It offers most features expected from a modern text layout
+    It offers many features expected from a modern text layout
     engine, including Unicode compliant rendering, line breaking and
     handling of cursor positioning. It can also produce and render
     device independent layout, something that is important for WYSIWYG
@@ -297,29 +296,33 @@
     implement your own text rendering for some specialized widget, you
     probably won't need to use it directly.
 
-    QTextLayout can currently deal with plain text and rich text
-    paragraphs that are part of a QTextDocument.
-
-    QTextLayout can be used to create a sequence of QTextLine's with
-    given widths and can position them independently on the screen.
-    Once the layout is done, these lines can be drawn on a paint
-    device.
-
-    Here's some code snippet that presents the layout phase:
+    QTextLayout can be used with both plain and rich text.
+
+    QTextLayout can be used to create a sequence of QTextLine
+    instances with given widths and can position them independently
+    on the screen. Once the layout is done, these lines can be drawn
+    on a paint device.
+
+    The text to be laid out can be provided in the constructor or set with
+    setText().
+
+    The layout can be seen as a sequence of QTextLine objects; use createLine()
+    to create a QTextLine instance, and lineAt() or lineForTextPosition() to retrieve
+    created lines.
+
+    Here is a code snippet that demonstrates the layout phase:
     \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 0
 
-    The text can be drawn by calling the layout's draw() function:
+    The text can then be rendered by calling the layout's draw() function:
     \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 1
 
-    The text layout's text is set in the constructor or with
-    setText(). The layout can be seen as a sequence of QTextLine
-    objects; use lineAt() or lineForTextPosition() to get a QTextLine,
-    createLine() to create one. For a given position in the text you
-    can find a valid cursor position with isValidCursorPosition(),
-    nextCursorPosition(), and previousCursorPosition(). The layout
-    itself can be positioned with setPosition(); it has a
-    boundingRect(), and a minimumWidth() and a maximumWidth(). A text
-    layout can be drawn on a painter device using draw().
+    For a given position in the text you can find a valid cursor position with
+    isValidCursorPosition(), nextCursorPosition(), and previousCursorPosition().
+
+    The QTextLayout itself can be positioned with setPosition(); it has a
+    boundingRect(), and a minimumWidth() and a maximumWidth().
+
+    \sa QStaticText
 
 */
 
@@ -858,7 +861,8 @@
         const QScriptLine &si = d->lines[i];
         xmin = qMin(xmin, si.x);
         ymin = qMin(ymin, si.y);
-        xmax = qMax(xmax, si.x+qMax(si.width, si.textWidth));
+        QFixed lineWidth = si.width < QFIXED_MAX ? qMax(si.width, si.textWidth) : si.textWidth;
+        xmax = qMax(xmax, si.x+lineWidth);
         // ### shouldn't the ascent be used in ymin???
         ymax = qMax(ymax, si.y+si.height());
     }
@@ -1336,7 +1340,7 @@
     int itm = d->findItem(cursorPosition - 1);
     QFixed base = sl.base();
     QFixed descent = sl.descent;
-    bool rightToLeft = (d->option.textDirection() == Qt::RightToLeft);
+    bool rightToLeft = d->isRightToLeft();
     if (itm >= 0) {
         const QScriptItem &si = d->layoutData->items.at(itm);
         if (si.ascent > 0)
@@ -1660,7 +1664,7 @@
     {
         LineBreakHelper()
             : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
-              manualWrap(false)
+              manualWrap(false), whiteSpaceOrObject(true)
         {
         }
 
@@ -1683,6 +1687,7 @@
         const unsigned short *logClusters;
 
         bool manualWrap;
+        bool whiteSpaceOrObject;
 
         bool checkFullOtherwiseExtend(QScriptLine &line);
 
@@ -1692,8 +1697,10 @@
         }
 
         inline glyph_t currentGlyph() const
-        {
+        {            
             Q_ASSERT(currentPosition > 0);
+            Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
+
             return glyphs.glyphs[logClusters[currentPosition - 1]];
         }
 
@@ -1828,6 +1835,7 @@
         lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
 
         if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) {
+            lbh.whiteSpaceOrObject = true;
             if (lbh.checkFullOtherwiseExtend(line))
                 goto found;
 
@@ -1844,6 +1852,7 @@
             if (lbh.checkFullOtherwiseExtend(line))
                 goto found;
         } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) {
+            lbh.whiteSpaceOrObject = true;
             // if the line consists only of the line separator make sure
             // we have a sane height
             if (!line.length && !lbh.tmpData.length)
@@ -1857,6 +1866,7 @@
             line += lbh.tmpData;
             goto found;
         } else if (current.analysis.flags == QScriptAnalysis::Object) {
+            lbh.whiteSpaceOrObject = true;
             lbh.tmpData.length++;
 
             QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item]));
@@ -1870,6 +1880,7 @@
             if (lbh.checkFullOtherwiseExtend(line))
                 goto found;
         } else if (attributes[lbh.currentPosition].whiteSpace) {
+            lbh.whiteSpaceOrObject = true;
             while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
                 addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
                                current, lbh.logClusters, lbh.glyphs);
@@ -1879,6 +1890,7 @@
                 goto found;
             }
         } else {
+            lbh.whiteSpaceOrObject = false;
             bool sb_or_ws = false;
             do {
                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
@@ -1923,7 +1935,7 @@
             // We ignore the right bearing if the minimum negative bearing is too little to
             // expand the text beyond the edge.
             if (sb_or_ws|breakany) {
-                if (lbh.calculateNewWidth(line) + lbh.minimumRightBearing > line.width)
+                if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
                     lbh.adjustRightBearing();
                 if (lbh.checkFullOtherwiseExtend(line)) {
                     if (!breakany) {
@@ -1940,7 +1952,7 @@
     LB_DEBUG("reached end of line");
     lbh.checkFullOtherwiseExtend(line);
 found:       
-    if (lbh.rightBearing > 0) // If right bearing has not yet been adjusted
+    if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
         lbh.adjustRightBearing();
     line.textAdvance = line.textWidth;
     line.textWidth -= qMin(QFixed(), lbh.rightBearing);