Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/text/qtextlayout.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7070        || (eng->option.flags() & QTextOption::IncludeTrailingSpaces)
    7171        || !(eng->option.alignment() & Qt::AlignRight)
    72         || (eng->option.textDirection() != Qt::RightToLeft))
     72        || !eng->isRightToLeft())
    7373        return QFixed();
    7474
    7575    int pos = line.length;
    7676    const HB_CharAttributes *attributes = eng->attributes();
     77    if (!attributes)
     78        return QFixed();
    7779    while (pos > 0 && attributes[line.from + pos - 1].whiteSpace)
    7880        --pos;
     
    8789    if (!line.justified && line.width != QFIXED_MAX) {
    8890        int align = eng->option.alignment();
    89         if (align & Qt::AlignJustify && eng->option.textDirection() == Qt::RightToLeft)
     91        if (align & Qt::AlignJustify && eng->isRightToLeft())
    9092            align = Qt::AlignRight;
    9193        if (align & Qt::AlignRight)
     
    283285    \reentrant
    284286
    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.
    287288
    288289    \ingroup richtext-processing
    289290
    290     It offers most features expected from a modern text layout
     291    It offers many features expected from a modern text layout
    291292    engine, including Unicode compliant rendering, line breaking and
    292293    handling of cursor positioning. It can also produce and render
     
    298299    probably won't need to use it directly.
    299300
    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:
    309316    \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 0
    310317
    311     The text can be drawn by calling the layout's draw() function:
     318    The text can then be rendered by calling the layout's draw() function:
    312319    \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 1
    313320
    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
    323328
    324329*/
     
    599604{
    600605#ifndef QT_NO_DEBUG
    601     if (d->layoutData && d->layoutData->inLayout) {
     606    if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) {
    602607        qWarning("QTextLayout::beginLayout: Called while already doing layout");
    603608        return;
     
    607612    d->clearLineData();
    608613    d->itemize();
    609     d->layoutData->inLayout = true;
     614    d->layoutData->layoutState = QTextEngine::InLayout;
    610615}
    611616
     
    616621{
    617622#ifndef QT_NO_DEBUG
    618     if (!d->layoutData || !d->layoutData->inLayout) {
     623    if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
    619624        qWarning("QTextLayout::endLayout: Called without beginLayout()");
    620625        return;
     
    625630        QTextLine(l-1, d).setNumColumns(INT_MAX);
    626631    }
    627     d->layoutData->inLayout = false;
     632    d->layoutData->layoutState = QTextEngine::LayoutEmpty;
    628633    if (!d->cacheGlyphs)
    629634        d->freeMemory();
     
    755760{
    756761#ifndef QT_NO_DEBUG
    757     if (!d->layoutData || !d->layoutData->inLayout) {
     762    if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
    758763        qWarning("QTextLayout::createLine: Called without layouting");
    759764        return QTextLine();
    760765    }
    761766#endif
     767    if (d->layoutData->layoutState == QTextEngine::LayoutFailed)
     768        return QTextLine();
     769
    762770    int l = d->lines.size();
    763771    if (l && d->lines.at(l-1).length < 0) {
     
    859867        xmin = qMin(xmin, si.x);
    860868        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);
    862871        // ### shouldn't the ascent be used in ymin???
    863872        ymax = qMax(ymax, si.y+si.height());
     
    12091218        bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
    12101219        bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
    1211        
     1220
    12121221        if (hasBackground) {
    12131222            selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));
     
    13371346    QFixed base = sl.base();
    13381347    QFixed descent = sl.descent;
    1339     bool rightToLeft = (d->option.textDirection() == Qt::RightToLeft);
     1348    bool rightToLeft = d->isRightToLeft();
    13401349    if (itm >= 0) {
    13411350        const QScriptItem &si = d->layoutData->items.at(itm);
     
    15711580}
    15721581
     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*/
     1591qreal QTextLine::horizontalAdvance() const
     1592{
     1593    return eng->lines[i].textAdvance.toReal();
     1594}
     1595
    15731596/*!
    15741597    Lays out the line with the given \a width. The line is filled from
     
    15931616        && line.textWidth <= line.width
    15941617        && 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 optimisation helps
     1618        // no need to do anything if the line is already layouted and the last one. This optimization helps
    15961619        // when using things in a single line layout.
    15971620        return;
     
    16471670        LineBreakHelper()
    16481671            : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
    1649               manualWrap(false)
     1672              manualWrap(false), whiteSpaceOrObject(true)
    16501673        {
    16511674        }
     
    16701693
    16711694        bool manualWrap;
     1695        bool whiteSpaceOrObject;
    16721696
    16731697        bool checkFullOtherwiseExtend(QScriptLine &line);
     
    16791703
    16801704        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)
    16811713        {
    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));
    16841717        }
    16851718
     
    16881721            if (currentPosition <= 0)
    16891722                return;
    1690 
    1691             qreal rb;
    1692             fontEngine->getGlyphBearings(currentGlyph(), 0, &rb);
    1693             rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
     1723            adjustRightBearing(currentGlyph());
    16941724        }
    16951725
     
    17021732
    17031733inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
    1704 {       
     1734{
    17051735    LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
    17061736
     
    17681798    lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
    17691799
    1770     // #### binary search!
    17711800    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;
    17751812            break;
    1776     }
     1813        }
     1814    }
     1815    if (newItem == -1)
     1816        newItem = right;
    17771817
    17781818    LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
     
    17811821
    17821822    const HB_CharAttributes *attributes = eng->attributes();
     1823    if (!attributes)
     1824        return;
    17831825    lbh.currentPosition = line.from;
    17841826    int end = 0;
     
    17941836                eng->shape(item);
    17951837                attributes = eng->attributes();
     1838                if (!attributes)
     1839                    return;
    17961840                lbh.logClusters = eng->layoutData->logClustersPtr;
    17971841            }
     
    18151859
    18161860        if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) {
     1861            lbh.whiteSpaceOrObject = true;
    18171862            if (lbh.checkFullOtherwiseExtend(line))
    18181863                goto found;
     
    18311876                goto found;
    18321877        } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) {
     1878            lbh.whiteSpaceOrObject = true;
    18331879            // if the line consists only of the line separator make sure
    18341880            // we have a sane height
     
    18441890            goto found;
    18451891        } else if (current.analysis.flags == QScriptAnalysis::Object) {
     1892            lbh.whiteSpaceOrObject = true;
    18461893            lbh.tmpData.length++;
    18471894
     
    18571904                goto found;
    18581905        } else if (attributes[lbh.currentPosition].whiteSpace) {
     1906            lbh.whiteSpaceOrObject = true;
    18591907            while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
    18601908                addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
     
    18661914            }
    18671915        } else {
     1916            lbh.whiteSpaceOrObject = false;
    18681917            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
    18691921            do {
    18701922                addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
     
    19101962            // expand the text beyond the edge.
    19111963            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
    19131968                    lbh.adjustRightBearing();
    19141969                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);
    19151975                    if (!breakany) {
    19161976                        line.textWidth += lbh.softHyphenWidth;
     
    19261986    LB_DEBUG("reached end of line");
    19271987    lbh.checkFullOtherwiseExtend(line);
    1928 found:       
    1929     if (lbh.rightBearing > 0) // If right bearing has not yet been adjusted
     1988found:
     1989    if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
    19301990        lbh.adjustRightBearing();
    19311991    line.textAdvance = line.textWidth;
Note: See TracChangeset for help on using the changeset viewer.