src/gui/text/qtextlayout.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
equal deleted inserted replaced
36:ef0373b55136 37:758a864f9613
    72         || !eng->isRightToLeft())
    72         || !eng->isRightToLeft())
    73         return QFixed();
    73         return QFixed();
    74 
    74 
    75     int pos = line.length;
    75     int pos = line.length;
    76     const HB_CharAttributes *attributes = eng->attributes();
    76     const HB_CharAttributes *attributes = eng->attributes();
       
    77     if (!attributes)
       
    78         return QFixed();
    77     while (pos > 0 && attributes[line.from + pos - 1].whiteSpace)
    79     while (pos > 0 && attributes[line.from + pos - 1].whiteSpace)
    78         --pos;
    80         --pos;
    79     return eng->width(line.from + pos, line.length - pos);
    81     return eng->width(line.from + pos, line.length - pos);
    80 }
    82 }
    81 
    83 
   599     Begins the layout process.
   601     Begins the layout process.
   600 */
   602 */
   601 void QTextLayout::beginLayout()
   603 void QTextLayout::beginLayout()
   602 {
   604 {
   603 #ifndef QT_NO_DEBUG
   605 #ifndef QT_NO_DEBUG
   604     if (d->layoutData && d->layoutData->inLayout) {
   606     if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) {
   605         qWarning("QTextLayout::beginLayout: Called while already doing layout");
   607         qWarning("QTextLayout::beginLayout: Called while already doing layout");
   606         return;
   608         return;
   607     }
   609     }
   608 #endif
   610 #endif
   609     d->invalidate();
   611     d->invalidate();
   610     d->clearLineData();
   612     d->clearLineData();
   611     d->itemize();
   613     d->itemize();
   612     d->layoutData->inLayout = true;
   614     d->layoutData->layoutState = QTextEngine::InLayout;
   613 }
   615 }
   614 
   616 
   615 /*!
   617 /*!
   616     Ends the layout process.
   618     Ends the layout process.
   617 */
   619 */
   618 void QTextLayout::endLayout()
   620 void QTextLayout::endLayout()
   619 {
   621 {
   620 #ifndef QT_NO_DEBUG
   622 #ifndef QT_NO_DEBUG
   621     if (!d->layoutData || !d->layoutData->inLayout) {
   623     if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
   622         qWarning("QTextLayout::endLayout: Called without beginLayout()");
   624         qWarning("QTextLayout::endLayout: Called without beginLayout()");
   623         return;
   625         return;
   624     }
   626     }
   625 #endif
   627 #endif
   626     int l = d->lines.size();
   628     int l = d->lines.size();
   627     if (l && d->lines.at(l-1).length < 0) {
   629     if (l && d->lines.at(l-1).length < 0) {
   628         QTextLine(l-1, d).setNumColumns(INT_MAX);
   630         QTextLine(l-1, d).setNumColumns(INT_MAX);
   629     }
   631     }
   630     d->layoutData->inLayout = false;
   632     d->layoutData->layoutState = QTextEngine::LayoutEmpty;
   631     if (!d->cacheGlyphs)
   633     if (!d->cacheGlyphs)
   632         d->freeMemory();
   634         d->freeMemory();
   633 }
   635 }
   634 
   636 
   635 /*!  \since 4.4
   637 /*!  \since 4.4
   755     (isValid() will return false).
   757     (isValid() will return false).
   756 */
   758 */
   757 QTextLine QTextLayout::createLine()
   759 QTextLine QTextLayout::createLine()
   758 {
   760 {
   759 #ifndef QT_NO_DEBUG
   761 #ifndef QT_NO_DEBUG
   760     if (!d->layoutData || !d->layoutData->inLayout) {
   762     if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
   761         qWarning("QTextLayout::createLine: Called without layouting");
   763         qWarning("QTextLayout::createLine: Called without layouting");
   762         return QTextLine();
   764         return QTextLine();
   763     }
   765     }
   764 #endif
   766 #endif
       
   767     if (d->layoutData->layoutState == QTextEngine::LayoutFailed)
       
   768         return QTextLine();
       
   769 
   765     int l = d->lines.size();
   770     int l = d->lines.size();
   766     if (l && d->lines.at(l-1).length < 0) {
   771     if (l && d->lines.at(l-1).length < 0) {
   767         QTextLine(l-1, d).setNumColumns(INT_MAX);
   772         QTextLine(l-1, d).setNumColumns(INT_MAX);
   768     }
   773     }
   769     int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length : 0;
   774     int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length : 0;
  1210 
  1215 
  1211 
  1216 
  1212 
  1217 
  1213         bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
  1218         bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
  1214         bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
  1219         bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
  1215         
  1220 
  1216         if (hasBackground) {
  1221         if (hasBackground) {
  1217             selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));
  1222             selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));
  1218             // don't just clear the property, set an empty brush that overrides a potential
  1223             // don't just clear the property, set an empty brush that overrides a potential
  1219             // background brush specified in the text
  1224             // background brush specified in the text
  1220             selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush());
  1225             selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush());
  1702             Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
  1707             Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
  1703 
  1708 
  1704             return glyphs.glyphs[logClusters[currentPosition - 1]];
  1709             return glyphs.glyphs[logClusters[currentPosition - 1]];
  1705         }
  1710         }
  1706 
  1711 
       
  1712         inline void adjustRightBearing(glyph_t glyph)
       
  1713         {
       
  1714             qreal rb;
       
  1715             fontEngine->getGlyphBearings(glyph, 0, &rb);
       
  1716             rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
       
  1717         }
       
  1718 
  1707         inline void adjustRightBearing()
  1719         inline void adjustRightBearing()
  1708         {
  1720         {
  1709             if (currentPosition <= 0)
  1721             if (currentPosition <= 0)
  1710                 return;
  1722                 return;
  1711 
  1723             adjustRightBearing(currentGlyph());
  1712             qreal rb;
       
  1713             fontEngine->getGlyphBearings(currentGlyph(), 0, &rb);
       
  1714             rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
       
  1715         }
  1724         }
  1716 
  1725 
  1717         inline void resetRightBearing()
  1726         inline void resetRightBearing()
  1718         {
  1727         {
  1719             rightBearing = QFixed(1); // Any positive number is defined as invalid since only
  1728             rightBearing = QFixed(1); // Any positive number is defined as invalid since only
  1720                                       // negative right bearings are interesting to us.
  1729                                       // negative right bearings are interesting to us.
  1721         }
  1730         }
  1722     };
  1731     };
  1723 
  1732 
  1724 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
  1733 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
  1725 {        
  1734 {
  1726     LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
  1735     LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
  1727 
  1736 
  1728     QFixed newWidth = calculateNewWidth(line);
  1737     QFixed newWidth = calculateNewWidth(line);
  1729     if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
  1738     if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
  1730         return true;
  1739         return true;
  1786 
  1795 
  1787     QTextOption::WrapMode wrapMode = eng->option.wrapMode();
  1796     QTextOption::WrapMode wrapMode = eng->option.wrapMode();
  1788     bool breakany = (wrapMode == QTextOption::WrapAnywhere);
  1797     bool breakany = (wrapMode == QTextOption::WrapAnywhere);
  1789     lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
  1798     lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
  1790 
  1799 
  1791     // #### binary search!
       
  1792     int item = -1;
  1800     int item = -1;
  1793     int newItem;
  1801     int newItem = -1;
  1794     for (newItem = eng->layoutData->items.size()-1; newItem > 0; --newItem) {
  1802     int left = 0;
  1795         if (eng->layoutData->items[newItem].position <= line.from)
  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;
  1796             break;
  1812             break;
  1797     }
  1813         }
       
  1814     }
       
  1815     if (newItem == -1)
       
  1816         newItem = right;
  1798 
  1817 
  1799     LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
  1818     LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
  1800 
  1819 
  1801     Qt::Alignment alignment = eng->option.alignment();
  1820     Qt::Alignment alignment = eng->option.alignment();
  1802 
  1821 
  1803     const HB_CharAttributes *attributes = eng->attributes();
  1822     const HB_CharAttributes *attributes = eng->attributes();
       
  1823     if (!attributes)
       
  1824         return;
  1804     lbh.currentPosition = line.from;
  1825     lbh.currentPosition = line.from;
  1805     int end = 0;
  1826     int end = 0;
  1806     lbh.logClusters = eng->layoutData->logClustersPtr;
  1827     lbh.logClusters = eng->layoutData->logClustersPtr;
  1807 
  1828 
  1808     while (newItem < eng->layoutData->items.size()) {
  1829     while (newItem < eng->layoutData->items.size()) {
  1812             item = newItem;
  1833             item = newItem;
  1813             const QScriptItem &current = eng->layoutData->items[item];
  1834             const QScriptItem &current = eng->layoutData->items[item];
  1814             if (!current.num_glyphs) {
  1835             if (!current.num_glyphs) {
  1815                 eng->shape(item);
  1836                 eng->shape(item);
  1816                 attributes = eng->attributes();
  1837                 attributes = eng->attributes();
       
  1838                 if (!attributes)
       
  1839                     return;
  1817                 lbh.logClusters = eng->layoutData->logClustersPtr;
  1840                 lbh.logClusters = eng->layoutData->logClustersPtr;
  1818             }
  1841             }
  1819             lbh.currentPosition = qMax(line.from, current.position);
  1842             lbh.currentPosition = qMax(line.from, current.position);
  1820             end = current.position + eng->length(item);
  1843             end = current.position + eng->length(item);
  1821             lbh.glyphs = eng->shapedGlyphs(&current);
  1844             lbh.glyphs = eng->shapedGlyphs(&current);
  1890                 goto found;
  1913                 goto found;
  1891             }
  1914             }
  1892         } else {
  1915         } else {
  1893             lbh.whiteSpaceOrObject = false;
  1916             lbh.whiteSpaceOrObject = false;
  1894             bool sb_or_ws = false;
  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
  1895             do {
  1921             do {
  1896                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
  1922                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
  1897                                current, lbh.logClusters, lbh.glyphs);
  1923                                current, lbh.logClusters, lbh.glyphs);
  1898 
  1924 
  1899                 if (attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition-1].lineBreakType != HB_NoBreak) {
  1925                 if (attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition-1].lineBreakType != HB_NoBreak) {
  1933             // of the advance of the glyph, the bearing will be negative. We flip the sign
  1959             // of the advance of the glyph, the bearing will be negative. We flip the sign
  1934             // for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
  1960             // for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
  1935             // We ignore the right bearing if the minimum negative bearing is too little to
  1961             // We ignore the right bearing if the minimum negative bearing is too little to
  1936             // expand the text beyond the edge.
  1962             // expand the text beyond the edge.
  1937             if (sb_or_ws|breakany) {
  1963             if (sb_or_ws|breakany) {
       
  1964                 QFixed rightBearing = lbh.rightBearing; // store previous right bearing
       
  1965 #if !defined(Q_WS_MAC)
  1938                 if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
  1966                 if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
       
  1967 #endif
  1939                     lbh.adjustRightBearing();
  1968                     lbh.adjustRightBearing();
  1940                 if (lbh.checkFullOtherwiseExtend(line)) {
  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);
  1941                     if (!breakany) {
  1975                     if (!breakany) {
  1942                         line.textWidth += lbh.softHyphenWidth;
  1976                         line.textWidth += lbh.softHyphenWidth;
  1943                     }
  1977                     }
  1944 
  1978 
  1945                     goto found;
  1979                     goto found;
  1949         if (lbh.currentPosition == end)
  1983         if (lbh.currentPosition == end)
  1950             newItem = item + 1;
  1984             newItem = item + 1;
  1951     }
  1985     }
  1952     LB_DEBUG("reached end of line");
  1986     LB_DEBUG("reached end of line");
  1953     lbh.checkFullOtherwiseExtend(line);
  1987     lbh.checkFullOtherwiseExtend(line);
  1954 found:       
  1988 found:
  1955     if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
  1989     if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
  1956         lbh.adjustRightBearing();
  1990         lbh.adjustRightBearing();
  1957     line.textAdvance = line.textWidth;
  1991     line.textAdvance = line.textWidth;
  1958     line.textWidth -= qMin(QFixed(), lbh.rightBearing);
  1992     line.textWidth -= qMin(QFixed(), lbh.rightBearing);
  1959 
  1993