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 ¤t = eng->layoutData->items[item]; |
1834 const QScriptItem ¤t = 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(¤t); |
1844 lbh.glyphs = eng->shapedGlyphs(¤t); |
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 |