Changeset 846 for trunk/src/gui/text/qtextlayout.cpp
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/gui/text/qtextlayout.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 70 70 || (eng->option.flags() & QTextOption::IncludeTrailingSpaces) 71 71 || !(eng->option.alignment() & Qt::AlignRight) 72 || (eng->option.textDirection() != Qt::RightToLeft))72 || !eng->isRightToLeft()) 73 73 return QFixed(); 74 74 75 75 int pos = line.length; 76 76 const HB_CharAttributes *attributes = eng->attributes(); 77 if (!attributes) 78 return QFixed(); 77 79 while (pos > 0 && attributes[line.from + pos - 1].whiteSpace) 78 80 --pos; … … 87 89 if (!line.justified && line.width != QFIXED_MAX) { 88 90 int align = eng->option.alignment(); 89 if (align & Qt::AlignJustify && eng-> option.textDirection() == Qt::RightToLeft)91 if (align & Qt::AlignJustify && eng->isRightToLeft()) 90 92 align = Qt::AlignRight; 91 93 if (align & Qt::AlignRight) … … 283 285 \reentrant 284 286 285 \brief The QTextLayout class is used to lay out and paint a single 286 paragraph of text. 287 \brief The QTextLayout class is used to lay out and render text. 287 288 288 289 \ingroup richtext-processing 289 290 290 It offers m ostfeatures expected from a modern text layout291 It offers many features expected from a modern text layout 291 292 engine, including Unicode compliant rendering, line breaking and 292 293 handling of cursor positioning. It can also produce and render … … 298 299 probably won't need to use it directly. 299 300 300 QTextLayout can currently deal with plain text and rich text 301 paragraphs that are part of a QTextDocument. 302 303 QTextLayout can be used to create a sequence of QTextLine's with 304 given widths and can position them independently on the screen. 305 Once the layout is done, these lines can be drawn on a paint 306 device. 307 308 Here's some pseudo code that presents the layout phase: 301 QTextLayout can be used with both plain and rich text. 302 303 QTextLayout can be used to create a sequence of QTextLine 304 instances with given widths and can position them independently 305 on the screen. Once the layout is done, these lines can be drawn 306 on a paint device. 307 308 The text to be laid out can be provided in the constructor or set with 309 setText(). 310 311 The layout can be seen as a sequence of QTextLine objects; use createLine() 312 to create a QTextLine instance, and lineAt() or lineForTextPosition() to retrieve 313 created lines. 314 315 Here is a code snippet that demonstrates the layout phase: 309 316 \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 0 310 317 311 The text can be drawnby calling the layout's draw() function:318 The text can then be rendered by calling the layout's draw() function: 312 319 \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 1 313 320 314 The text layout's text is set in the constructor or with 315 setText(). The layout can be seen as a sequence of QTextLine 316 objects; use lineAt() or lineForTextPosition() to get a QTextLine, 317 createLine() to create one. For a given position in the text you 318 can find a valid cursor position with isValidCursorPosition(), 319 nextCursorPosition(), and previousCursorPosition(). The layout 320 itself can be positioned with setPosition(); it has a 321 boundingRect(), and a minimumWidth() and a maximumWidth(). A text 322 layout can be drawn on a painter device using draw(). 321 For a given position in the text you can find a valid cursor position with 322 isValidCursorPosition(), nextCursorPosition(), and previousCursorPosition(). 323 324 The QTextLayout itself can be positioned with setPosition(); it has a 325 boundingRect(), and a minimumWidth() and a maximumWidth(). 326 327 \sa QStaticText 323 328 324 329 */ … … 599 604 { 600 605 #ifndef QT_NO_DEBUG 601 if (d->layoutData && d->layoutData-> inLayout) {606 if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) { 602 607 qWarning("QTextLayout::beginLayout: Called while already doing layout"); 603 608 return; … … 607 612 d->clearLineData(); 608 613 d->itemize(); 609 d->layoutData-> inLayout = true;614 d->layoutData->layoutState = QTextEngine::InLayout; 610 615 } 611 616 … … 616 621 { 617 622 #ifndef QT_NO_DEBUG 618 if (!d->layoutData || !d->layoutData->inLayout) {623 if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) { 619 624 qWarning("QTextLayout::endLayout: Called without beginLayout()"); 620 625 return; … … 625 630 QTextLine(l-1, d).setNumColumns(INT_MAX); 626 631 } 627 d->layoutData-> inLayout = false;632 d->layoutData->layoutState = QTextEngine::LayoutEmpty; 628 633 if (!d->cacheGlyphs) 629 634 d->freeMemory(); … … 755 760 { 756 761 #ifndef QT_NO_DEBUG 757 if (!d->layoutData || !d->layoutData->inLayout) {762 if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) { 758 763 qWarning("QTextLayout::createLine: Called without layouting"); 759 764 return QTextLine(); 760 765 } 761 766 #endif 767 if (d->layoutData->layoutState == QTextEngine::LayoutFailed) 768 return QTextLine(); 769 762 770 int l = d->lines.size(); 763 771 if (l && d->lines.at(l-1).length < 0) { … … 859 867 xmin = qMin(xmin, si.x); 860 868 ymin = qMin(ymin, si.y); 861 xmax = qMax(xmax, si.x+qMax(si.width, si.textWidth)); 869 QFixed lineWidth = si.width < QFIXED_MAX ? qMax(si.width, si.textWidth) : si.textWidth; 870 xmax = qMax(xmax, si.x+lineWidth); 862 871 // ### shouldn't the ascent be used in ymin??? 863 872 ymax = qMax(ymax, si.y+si.height()); … … 1209 1218 bool hasText = (selection.format.foreground().style() != Qt::NoBrush); 1210 1219 bool hasBackground= (selection.format.background().style() != Qt::NoBrush); 1211 1220 1212 1221 if (hasBackground) { 1213 1222 selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush)); … … 1337 1346 QFixed base = sl.base(); 1338 1347 QFixed descent = sl.descent; 1339 bool rightToLeft = (d->option.textDirection() == Qt::RightToLeft);1348 bool rightToLeft = d->isRightToLeft(); 1340 1349 if (itm >= 0) { 1341 1350 const QScriptItem &si = d->layoutData->items.at(itm); … … 1571 1580 } 1572 1581 1582 /*! \since 4.7 1583 Returns the horizontal advance of the text. The advance of the text 1584 is the distance from its position to the next position at which 1585 text would naturally be drawn. 1586 1587 By adding the advance to the position of the text line and using this 1588 as the position of a second text line, you will be able to position 1589 the two lines side-by-side without gaps in-between. 1590 */ 1591 qreal QTextLine::horizontalAdvance() const 1592 { 1593 return eng->lines[i].textAdvance.toReal(); 1594 } 1595 1573 1596 /*! 1574 1597 Lays out the line with the given \a width. The line is filled from … … 1593 1616 && line.textWidth <= line.width 1594 1617 && line.from + line.length == eng->layoutData->string.length()) 1595 // no need to do anything if the line is already layouted and the last one. This optimi sation helps1618 // no need to do anything if the line is already layouted and the last one. This optimization helps 1596 1619 // when using things in a single line layout. 1597 1620 return; … … 1647 1670 LineBreakHelper() 1648 1671 : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0), 1649 manualWrap(false) 1672 manualWrap(false), whiteSpaceOrObject(true) 1650 1673 { 1651 1674 } … … 1670 1693 1671 1694 bool manualWrap; 1695 bool whiteSpaceOrObject; 1672 1696 1673 1697 bool checkFullOtherwiseExtend(QScriptLine &line); … … 1679 1703 1680 1704 inline glyph_t currentGlyph() const 1705 { 1706 Q_ASSERT(currentPosition > 0); 1707 Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs); 1708 1709 return glyphs.glyphs[logClusters[currentPosition - 1]]; 1710 } 1711 1712 inline void adjustRightBearing(glyph_t glyph) 1681 1713 { 1682 Q_ASSERT(currentPosition > 0); 1683 return glyphs.glyphs[logClusters[currentPosition - 1]]; 1714 qreal rb; 1715 fontEngine->getGlyphBearings(glyph, 0, &rb); 1716 rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); 1684 1717 } 1685 1718 … … 1688 1721 if (currentPosition <= 0) 1689 1722 return; 1690 1691 qreal rb; 1692 fontEngine->getGlyphBearings(currentGlyph(), 0, &rb); 1693 rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); 1723 adjustRightBearing(currentGlyph()); 1694 1724 } 1695 1725 … … 1702 1732 1703 1733 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) 1704 { 1734 { 1705 1735 LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); 1706 1736 … … 1768 1798 lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap); 1769 1799 1770 // #### binary search!1771 1800 int item = -1; 1772 int newItem; 1773 for (newItem = eng->layoutData->items.size()-1; newItem > 0; --newItem) { 1774 if (eng->layoutData->items[newItem].position <= line.from) 1801 int newItem = -1; 1802 int left = 0; 1803 int right = eng->layoutData->items.size()-1; 1804 while(left <= right) { 1805 int middle = ((right-left)/2)+left; 1806 if (line.from > eng->layoutData->items[middle].position) 1807 left = middle+1; 1808 else if(line.from < eng->layoutData->items[middle].position) 1809 right = middle-1; 1810 else { 1811 newItem = middle; 1775 1812 break; 1776 } 1813 } 1814 } 1815 if (newItem == -1) 1816 newItem = right; 1777 1817 1778 1818 LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); … … 1781 1821 1782 1822 const HB_CharAttributes *attributes = eng->attributes(); 1823 if (!attributes) 1824 return; 1783 1825 lbh.currentPosition = line.from; 1784 1826 int end = 0; … … 1794 1836 eng->shape(item); 1795 1837 attributes = eng->attributes(); 1838 if (!attributes) 1839 return; 1796 1840 lbh.logClusters = eng->layoutData->logClustersPtr; 1797 1841 } … … 1815 1859 1816 1860 if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) { 1861 lbh.whiteSpaceOrObject = true; 1817 1862 if (lbh.checkFullOtherwiseExtend(line)) 1818 1863 goto found; … … 1831 1876 goto found; 1832 1877 } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) { 1878 lbh.whiteSpaceOrObject = true; 1833 1879 // if the line consists only of the line separator make sure 1834 1880 // we have a sane height … … 1844 1890 goto found; 1845 1891 } else if (current.analysis.flags == QScriptAnalysis::Object) { 1892 lbh.whiteSpaceOrObject = true; 1846 1893 lbh.tmpData.length++; 1847 1894 … … 1857 1904 goto found; 1858 1905 } else if (attributes[lbh.currentPosition].whiteSpace) { 1906 lbh.whiteSpaceOrObject = true; 1859 1907 while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace) 1860 1908 addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount, … … 1866 1914 } 1867 1915 } else { 1916 lbh.whiteSpaceOrObject = false; 1868 1917 bool sb_or_ws = false; 1918 glyph_t previousGlyph = 0; 1919 if (lbh.currentPosition > 0 && lbh.logClusters[lbh.currentPosition - 1] <lbh.glyphs.numGlyphs) 1920 previousGlyph = lbh.currentGlyph(); // needed to calculate right bearing later 1869 1921 do { 1870 1922 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount, … … 1910 1962 // expand the text beyond the edge. 1911 1963 if (sb_or_ws|breakany) { 1912 if (lbh.calculateNewWidth(line) + lbh.minimumRightBearing > line.width) 1964 QFixed rightBearing = lbh.rightBearing; // store previous right bearing 1965 #if !defined(Q_WS_MAC) 1966 if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width) 1967 #endif 1913 1968 lbh.adjustRightBearing(); 1914 1969 if (lbh.checkFullOtherwiseExtend(line)) { 1970 // we are too wide, fix right bearing 1971 if (rightBearing <= 0) 1972 lbh.rightBearing = rightBearing; // take from cache 1973 else if (previousGlyph > 0) 1974 lbh.adjustRightBearing(previousGlyph); 1915 1975 if (!breakany) { 1916 1976 line.textWidth += lbh.softHyphenWidth; … … 1926 1986 LB_DEBUG("reached end of line"); 1927 1987 lbh.checkFullOtherwiseExtend(line); 1928 found: 1929 if (lbh.rightBearing > 0 ) // If right bearing has not yet been adjusted1988 found: 1989 if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted 1930 1990 lbh.adjustRightBearing(); 1931 1991 line.textAdvance = line.textWidth;
Note:
See TracChangeset
for help on using the changeset viewer.