Changeset 561 for trunk/src/gui/text/qtextlayout.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/text/qtextlayout.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 62 62 63 63 #define ObjectSelectionBrush (QTextFormat::ForegroundBrush + 1) 64 65 64 66 65 67 static inline QFixed leadingSpaceWidth(QTextEngine *eng, const QScriptLine &line) … … 127 129 a QTextLayout. 128 130 129 \ingroup text131 \ingroup 130 132 131 133 This class is only used if the text layout is used to lay out … … 284 286 paragraph of text. 285 287 286 \ingroup text288 \ingroup 287 289 288 290 It offers most features expected from a modern text layout … … 366 368 if (paintdevice) 367 369 f = QFont(font, paintdevice); 368 d = new QTextEngine((text.isNull() ? (const QString&)QString::fromLatin1("") : text), f.d );370 d = new QTextEngine((text.isNull() ? (const QString&)QString::fromLatin1("") : text), f.d); 369 371 } 370 372 … … 859 861 xmax = qMax(xmax, si.x+qMax(si.width, si.textWidth)); 860 862 // ### shouldn't the ascent be used in ymin??? 861 ymax = qMax(ymax, si.y+si. ascent+si.descent+1);863 ymax = qMax(ymax, si.y+si.); 862 864 } 863 865 return QRectF(xmin.toReal(), ymin.toReal(), (xmax-xmin).toReal(), (ymax-ymin).toReal()); … … 1070 1072 QTextLineItemIterator iterator(eng, lineNumber, pos, selection); 1071 1073 1072 const QFixed y = QFixed::fromReal(pos.y()) + line.y + line.ascent; 1073 1074 1075 1076 const qreal selectionY = pos.y() + line.y.toReal(); 1074 1077 const qreal lineHeight = line.height().toReal(); 1075 const qreal selectionY = (y - line.ascent).toReal();1076 1078 1077 1079 QFixed lastSelectionX = iterator.x; … … 1144 1146 1145 1147 QPainterPath excludedRegion; 1148 1146 1149 for (int i = 0; i < selections.size(); ++i) { 1147 1150 FormatRange selection = selections.at(i); … … 1203 1206 1204 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1205 1225 p->save(); 1206 1226 p->setClipPath(region, Qt::IntersectClip); 1207 1208 selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));1209 // don't just clear the property, set an empty brush that overrides a potential1210 // background brush specified in the text1211 selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush());1212 selection.format.clearProperty(QTextFormat::OutlinePen);1213 1227 1214 1228 for (int line = firstLine; line < lastLine; ++line) { … … 1218 1232 p->restore(); 1219 1233 1220 if (selection.format.foreground().style() != Qt::NoBrush) // i.e. we have drawn text 1221 excludedRegion += region; 1234 if (hasText) { 1235 textDoneRegion += region; 1236 } else { 1237 if (hasBackground) 1238 textDoneRegion -= region; 1239 } 1240 1241 excludedRegion += region; 1242 } 1243 1244 QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion; 1245 if (!needsTextButNoBackground.isEmpty()){ 1246 p->save(); 1247 p->setClipPath(needsTextButNoBackground, Qt::IntersectClip); 1248 FormatRange selection; 1249 selection.start = 0; 1250 selection.length = INT_MAX; 1251 selection.format.setProperty(SuppressBackground, true); 1252 for (int line = firstLine; line < lastLine; ++line) { 1253 QTextLine l(line, d); 1254 l.draw(p, position, &selection); 1255 } 1256 p->restore(); 1222 1257 } 1223 1258 … … 1300 1335 1301 1336 int itm = d->findItem(cursorPosition - 1); 1302 QFixed ascent = sl.ascent;1337 QFixed ; 1303 1338 QFixed descent = sl.descent; 1304 1339 bool rightToLeft = (d->option.textDirection() == Qt::RightToLeft); … … 1306 1341 const QScriptItem &si = d->layoutData->items.at(itm); 1307 1342 if (si.ascent > 0) 1308 ascent= si.ascent;1343 = si.ascent; 1309 1344 if (si.descent > 0) 1310 1345 descent = si.descent; 1311 1346 rightToLeft = si.analysis.bidiLevel % 2; 1312 1347 } 1313 qreal y = position.y() + (sl.y + sl. ascent - ascent).toReal();1348 qreal y = position.y() + (sl.y + sl.).toReal(); 1314 1349 bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing) 1315 1350 && (p->transform().type() > QTransform::TxTranslate); 1316 1351 if (toggleAntialiasing) 1317 1352 p->setRenderHint(QPainter::Antialiasing); 1318 p->fillRect(QRectF(x, y, qreal(width), ( ascent + descent).toReal()), p->pen().brush());1353 p->fillRect(QRectF(x, y, qreal(width), ().toReal()), p->pen().brush()); 1319 1354 if (toggleAntialiasing) 1320 1355 p->setRenderHint(QPainter::Antialiasing, false); … … 1334 1369 \brief The QTextLine class represents a line of text inside a QTextLayout. 1335 1370 1336 \ingroup text1371 \ingroup 1337 1372 1338 1373 A text line is usually created by QTextLayout::createLine(). … … 1466 1501 1467 1502 /*! 1468 Returns the line's height. This is equal to ascent() + descent() + 1. 1469 1470 \sa ascent() descent() 1503 Returns the line's height. This is equal to ascent() + descent() + 1 1504 if leading is not included. If leading is included, this equals to 1505 ascent() + descent() + leading() + 1. 1506 1507 \sa ascent() descent() leading() setLeadingIncluded() 1471 1508 */ 1472 1509 qreal QTextLine::height() const … … 1474 1511 return eng->lines[i].height().toReal(); 1475 1512 } 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1476 1558 1477 1559 /*! … … 1555 1637 #endif 1556 1638 1557 static inline bool checkFullOtherwiseExtend(QScriptLine &line, QScriptLine &tmpData, QScriptLine &spaceData, 1558 int glyphCount, int maxGlyphs, QFixed &minw, bool manualWrap, 1559 QFixed softHyphenWidth = QFixed()) 1560 { 1639 namespace { 1640 1641 struct LineBreakHelper 1642 { 1643 LineBreakHelper() : glyphCount(0), maxGlyphs(0), manualWrap(false) {} 1644 1645 QScriptLine tmpData; 1646 QScriptLine spaceData; 1647 1648 int glyphCount; 1649 int maxGlyphs; 1650 1651 QFixed minw; 1652 QFixed softHyphenWidth; 1653 QFixed rightBearing; 1654 1655 bool manualWrap; 1656 1657 bool checkFullOtherwiseExtend(QScriptLine &line); 1658 }; 1659 1660 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) 1661 { 1561 1662 LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); 1562 if (line.length && !manualWrap && 1563 (line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth > line.width || glyphCount > maxGlyphs)) 1663 1664 QFixed newWidth = line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth + rightBearing; 1665 if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs)) 1564 1666 return true; 1667 1565 1668 minw = qMax(minw, tmpData.textWidth); 1566 1669 line += tmpData; 1567 1670 line.textWidth += spaceData.textWidth; 1671 1568 1672 line.length += spaceData.length; 1569 1673 tmpData.textWidth = 0; … … 1571 1675 spaceData.textWidth = 0; 1572 1676 spaceData.length = 0; 1677 1573 1678 return false; 1574 1679 } 1575 1680 1681 1682 1683 1576 1684 static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount, 1577 const QScriptItem ¤t, const unsigned short *logClusters, const QGlyphLayout &glyphs) 1685 const QScriptItem ¤t, const unsigned short *logClusters, 1686 const QGlyphLayout &glyphs) 1578 1687 { 1579 1688 int glyphPosition = logClusters[pos]; … … 1608 1717 Q_ASSERT(line.from < eng->layoutData->string.length()); 1609 1718 1719 1720 1721 1722 1610 1723 QTextOption::WrapMode wrapMode = eng->option.wrapMode(); 1611 1724 bool breakany = (wrapMode == QTextOption::WrapAnywhere); 1612 boolmanualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);1725 manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap); 1613 1726 1614 1727 // #### binary search! … … 1620 1733 } 1621 1734 1622 QFixed minw = 0;1623 int glyphCount = 0;1624 1625 1735 LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); 1626 QScriptLine tmpData;1627 QScriptLine spaceData;1628 1736 1629 1737 Qt::Alignment alignment = eng->option.alignment(); … … 1634 1742 QGlyphLayout glyphs; 1635 1743 const unsigned short *logClusters = eng->layoutData->logClustersPtr; 1744 1636 1745 while (newItem < eng->layoutData->items.size()) { 1746 1747 1637 1748 if (newItem != item) { 1638 1749 item = newItem; … … 1649 1760 const QScriptItem ¤t = eng->layoutData->items[item]; 1650 1761 1651 tmpData.ascent = qMax(tmpData.ascent, current.ascent); 1652 tmpData.descent = qMax(tmpData.descent, current.descent); 1762 lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent, 1763 current.leading + current.ascent) - qMax(lbh.tmpData.ascent, 1764 current.ascent); 1765 lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent); 1766 lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent); 1653 1767 1654 1768 if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) { 1655 if ( checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap))1769 if ()) 1656 1770 goto found; 1657 1771 1658 QFixed x = line.x + line.textWidth + tmpData.textWidth + spaceData.textWidth; 1659 spaceData.textWidth += eng->calculateTabWidth(item, x); 1660 spaceData.length++; 1772 QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth; 1773 QFixed tabWidth = eng->calculateTabWidth(item, x); 1774 1775 lbh.spaceData.textWidth += tabWidth; 1776 lbh.spaceData.length++; 1661 1777 newItem = item + 1; 1662 ++glyphCount; 1663 if (checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap)) 1778 1779 QFixed averageCharWidth = eng->fontEngine(current)->averageCharWidth(); 1780 lbh.glyphCount += qRound(tabWidth / averageCharWidth); 1781 1782 if (lbh.checkFullOtherwiseExtend(line)) 1664 1783 goto found; 1665 1784 } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) { 1666 1785 // if the line consists only of the line separator make sure 1667 1786 // we have a sane height 1668 if (!line.length && ! tmpData.length)1787 if (!line.length && !tmpData.length) 1669 1788 line.setDefaultHeight(eng); 1670 1789 if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators) { 1671 addNextCluster(pos, end, tmpData, glyphCount, current, logClusters, glyphs); 1790 addNextCluster(pos, end, lbh.tmpData, lbh.glyphCount, 1791 current, logClusters, glyphs); 1672 1792 } else { 1673 tmpData.length++;1793 tmpData.length++; 1674 1794 } 1675 line += tmpData;1795 line += tmpData; 1676 1796 goto found; 1677 1797 } else if (current.analysis.flags == QScriptAnalysis::Object) { 1678 tmpData.length++;1798 tmpData.length++; 1679 1799 1680 1800 QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item])); … … 1682 1802 eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format); 1683 1803 1684 tmpData.textWidth += current.width;1804 tmpData.textWidth += current.width; 1685 1805 1686 1806 newItem = item + 1; 1687 ++ glyphCount;1688 if ( checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap))1807 ++glyphCount; 1808 if ()) 1689 1809 goto found; 1690 1810 } else if (attributes[pos].whiteSpace) { 1691 1811 while (pos < end && attributes[pos].whiteSpace) 1692 addNextCluster(pos, end, spaceData, glyphCount, current, logClusters, glyphs); 1693 1694 if (!manualWrap && spaceData.textWidth > line.width) { 1695 spaceData.textWidth = line.width; // ignore spaces that fall out of the line. 1812 addNextCluster(pos, end, lbh.spaceData, lbh.glyphCount, 1813 current, logClusters, glyphs); 1814 1815 if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) { 1816 lbh.spaceData.textWidth = line.width; // ignore spaces that fall out of the line. 1696 1817 goto found; 1697 1818 } … … 1699 1820 bool sb_or_ws = false; 1700 1821 do { 1701 addNextCluster(pos, end, tmpData, glyphCount, current, logClusters, glyphs); 1822 addNextCluster(pos, end, lbh.tmpData, lbh.glyphCount, 1823 current, logClusters, glyphs); 1702 1824 1703 1825 if (attributes[pos].whiteSpace || attributes[pos-1].lineBreakType != HB_NoBreak) { … … 1708 1830 } 1709 1831 } while (pos < end); 1710 minw = qMax(tmpData.textWidth, minw); 1711 1712 QFixed softHyphenWidth; 1832 lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw); 1833 1713 1834 if (pos && attributes[pos - 1].lineBreakType == HB_SoftHyphen) { 1714 1835 // if we are splitting up a word because of … … 1729 1850 // 1730 1851 if (line.length) 1731 softHyphenWidth = glyphs.advances_x[logClusters[pos - 1]];1852 softHyphenWidth = glyphs.advances_x[logClusters[pos - 1]]; 1732 1853 else if (breakany) 1733 tmpData.textWidth += glyphs.advances_x[logClusters[pos - 1]];1854 tmpData.textWidth += glyphs.advances_x[logClusters[pos - 1]]; 1734 1855 } 1735 1856 1736 if ((sb_or_ws|breakany) 1737 && checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap, softHyphenWidth)) { 1857 // The actual width of the text needs to take the right bearing into account. The 1858 // right bearing is left-ward, which means that if the rightmost pixel is to the right 1859 // of the advance of the glyph, the bearing will be negative. We flip the sign 1860 // for the code to be more readable. Logic borrowed from qfontmetrics.cpp. 1861 if (pos) { 1862 QFontEngine *fontEngine = eng->fontEngine(current); 1863 glyph_t glyph = glyphs.glyphs[logClusters[pos - 1]]; 1864 glyph_metrics_t gi = fontEngine->boundingBox(glyph); 1865 if (gi.isValid()) 1866 lbh.rightBearing = qMax(QFixed(), -(gi.xoff - gi.x - gi.width)); 1867 } 1868 1869 if ((sb_or_ws|breakany) && lbh.checkFullOtherwiseExtend(line)) { 1738 1870 if (!breakany) { 1739 line.textWidth += softHyphenWidth;1871 line.textWidth += softHyphenWidth; 1740 1872 } 1873 1874 1875 1741 1876 goto found; 1742 1877 } … … 1746 1881 } 1747 1882 LB_DEBUG("reached end of line"); 1748 checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap); 1749 found: 1883 lbh.checkFullOtherwiseExtend(line); 1884 line.textWidth += lbh.rightBearing; 1885 1886 found: 1750 1887 if (line.length == 0) { 1751 1888 LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", 1752 tmpData.length, tmpData.textWidth.toReal(), spaceData.length, spaceData.textWidth.toReal()); 1753 line += tmpData; 1889 lbh.tmpData.length, lbh.tmpData.textWidth.toReal(), 1890 lbh.spaceData.length, lbh.spaceData.textWidth.toReal()); 1891 line += lbh.tmpData; 1754 1892 } 1755 1893 1756 1894 LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(), 1757 line.descent.toReal(), line.textWidth.toReal(), spaceData.width.toReal());1895 line.descent.toReal(), line.textWidth.toReal(), spaceData.width.toReal()); 1758 1896 LB_DEBUG(" : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data()); 1759 1897 1760 if ( manualWrap) {1898 if (manualWrap) { 1761 1899 eng->minWidth = qMax(eng->minWidth, line.textWidth); 1762 1900 eng->maxWidth = qMax(eng->maxWidth, line.textWidth); 1763 1901 } else { 1764 eng->minWidth = qMax(eng->minWidth, minw);1902 eng->minWidth = qMax(eng->minWidth, minw); 1765 1903 eng->maxWidth += line.textWidth; 1766 1904 } 1767 1905 1768 1906 if (line.textWidth > 0 && item < eng->layoutData->items.size()) 1769 eng->maxWidth += spaceData.textWidth;1907 eng->maxWidth += spaceData.textWidth; 1770 1908 if (eng->option.flags() & QTextOption::IncludeTrailingSpaces) 1771 line.textWidth += spaceData.textWidth;1772 line.length += spaceData.length;1773 if ( spaceData.length)1909 line.textWidth += spaceData.textWidth; 1910 line.length += spaceData.length; 1911 if (spaceData.length) 1774 1912 line.hasTrailingSpaces = true; 1775 1913 … … 1778 1916 1779 1917 if (eng->option.wrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere) { 1780 if (( maxGlyphs != INT_MAX && glyphCount >maxGlyphs)1781 || ( maxGlyphs == INT_MAX && line.textWidth > line.width)) {1918 if ((maxGlyphs) 1919 || (maxGlyphs == INT_MAX && line.textWidth > line.width)) { 1782 1920 1783 1921 eng->option.setWrapMode(QTextOption::WrapAnywhere); 1784 1922 line.length = 0; 1785 1923 line.textWidth = 0; 1786 layout_helper( maxGlyphs);1924 layout_helper(maxGlyphs); 1787 1925 eng->option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); 1788 1926 } … … 1913 2051 { 1914 2052 QBrush c = chf.foreground(); 1915 if (c.style() == Qt::NoBrush) 2053 if (c.style() == Qt::NoBrush) 1916 2054 p->setPen(defaultPen); 2055 1917 2056 1918 2057 QBrush bg = chf.background(); 1919 if (bg.style() != Qt::NoBrush )2058 if (bg.style() != Qt::NoBrush) 1920 2059 p->fillRect(r, bg); 1921 if (c.style() != Qt::NoBrush) 2060 if (c.style() != Qt::NoBrush) 1922 2061 p->setPen(QPen(c, 0)); 2062 2063 1923 2064 } 1924 2065 … … 1934 2075 QPen pen = p->pen(); 1935 2076 1936 bool noText = (selection && selection->format. foreground().style() == Qt::NoBrush);2077 bool noText = (selection && selection->format.); 1937 2078 1938 2079 if (!line.length) { … … 1952 2093 1953 2094 QTextLineItemIterator iterator(eng, i, pos, selection); 1954 const QFixed y = QFixed::fromReal(pos.y()) + line.y + line.ascent; 2095 QFixed lineBase = line.base(); 2096 2097 const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase; 1955 2098 1956 2099 bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors); … … 1975 2118 format.merge(selection->format); 1976 2119 1977 setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - line .ascent).toReal(),2120 setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - line).toReal(), 1978 2121 iterator.itemWidth.toReal(), line.height().toReal())); 1979 2122 … … 1996 2139 QFixed itemY = y - si.ascent; 1997 2140 if (format.verticalAlignment() == QTextCharFormat::AlignTop) { 1998 itemY = y - line .ascent;2141 itemY = y - line; 1999 2142 } 2000 2143
Note:
See TracChangeset
for help on using the changeset viewer.