Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/svg/qsvggraphics.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the QtSvg module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    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.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5757QT_BEGIN_NAMESPACE
    5858
    59 #define QT_SVG_DRAW_SHAPE(command)                  \
    60     applyStyle(p, states);                          \
    61     qreal oldOpacity = p->opacity();                \
    62     QBrush oldBrush = p->brush();                   \
    63     QPen oldPen = p->pen();                         \
    64     p->setPen(Qt::NoPen);                           \
    65     p->setOpacity(oldOpacity * states.fillOpacity); \
    66     command;                                        \
    67     p->setOpacity(oldOpacity);                      \
    68     p->setPen(oldPen);                              \
    69     p->setBrush(Qt::NoBrush);                       \
    70     command;                                        \
    71     p->setBrush(oldBrush);                          \
    72     revertStyle(p, states);
     59#define QT_SVG_DRAW_SHAPE(command)                          \
     60    qreal oldOpacity = p->opacity();                        \
     61    QBrush oldBrush = p->brush();                           \
     62    QPen oldPen = p->pen();                                 \
     63    p->setPen(Qt::NoPen);                                   \
     64    p->setOpacity(oldOpacity * states.fillOpacity);         \
     65    command;                                                \
     66    p->setPen(oldPen);                                      \
     67    if (oldPen.widthF() != 0) {                             \
     68        p->setOpacity(oldOpacity * states.strokeOpacity);   \
     69        p->setBrush(Qt::NoBrush);                           \
     70        command;                                            \
     71        p->setBrush(oldBrush);                              \
     72    }                                                       \
     73    p->setOpacity(oldOpacity);
    7374
    7475
     
    9596{
    9697    qreal sw = strokeWidth();
    97     if (qFuzzyCompare(sw + 1, 1))
     98    if (qFuzzyIsNull(sw))
    9899        return m_bounds;
    99100    else {
     
    106107void QSvgCircle::draw(QPainter *p, QSvgExtraStates &states)
    107108{
     109    applyStyle(p, states);
    108110    QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds));
     111    revertStyle(p, states);
    109112}
    110113
     
    118121{
    119122    applyStyle(p, states);
    120     p->drawPath(cubic);
     123    if (p->pen().widthF() != 0) {
     124        qreal oldOpacity = p->opacity();
     125        p->setOpacity(oldOpacity * states.strokeOpacity);
     126        p->drawPath(cubic);
     127        p->setOpacity(oldOpacity);
     128    }
    121129    revertStyle(p, states);
    122130}
     
    130138{
    131139    qreal sw = strokeWidth();
    132     if (qFuzzyCompare(sw + 1, 1))
     140    if (qFuzzyIsNull(sw))
    133141        return m_bounds;
    134142    else {
     
    141149void QSvgEllipse::draw(QPainter *p, QSvgExtraStates &states)
    142150{
     151    applyStyle(p, states);
    143152    QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds));
     153    revertStyle(p, states);
    144154}
    145155
     
    172182{
    173183    applyStyle(p, states);
    174     p->drawLine(m_bounds);
     184    if (p->pen().widthF() != 0) {
     185        qreal oldOpacity = p->opacity();
     186        p->setOpacity(oldOpacity * states.strokeOpacity);
     187        p->drawLine(m_bounds);
     188        p->setOpacity(oldOpacity);
     189    }
    175190    revertStyle(p, states);
    176191}
     
    179194    : QSvgNode(parent), m_path(qpath)
    180195{
    181     //m_cachedBounds = m_path.controlPointRect();
    182     m_cachedBounds = m_path.boundingRect();
    183196}
    184197
    185198void QSvgPath::draw(QPainter *p, QSvgExtraStates &states)
    186199{
     200    applyStyle(p, states);
     201    m_path.setFillRule(states.fillRule);
    187202    QT_SVG_DRAW_SHAPE(p->drawPath(m_path));
     203    revertStyle(p, states);
    188204}
    189205
     
    191207{
    192208    qreal sw = strokeWidth();
    193     if (qFuzzyCompare(sw + 1, 1))
     209    if (qFuzzyIsNull(sw)) {
     210        if (m_cachedBounds.isNull())
     211            //m_cachedBounds = m_path.controlPointRect();
     212            m_cachedBounds = m_path.boundingRect();
     213
    194214        return m_cachedBounds;
     215    }
    195216    else {
    196217        return boundsOnStroke(m_path, sw);
     
    201222    : QSvgNode(parent), m_poly(poly)
    202223{
    203 
    204224}
    205225
     
    207227{
    208228    qreal sw = strokeWidth();
    209     if (qFuzzyCompare(sw + 1, 1))
     229    if (qFuzzyIsNull(sw))
    210230        return m_poly.boundingRect();
    211231    else {
     
    218238void QSvgPolygon::draw(QPainter *p, QSvgExtraStates &states)
    219239{
    220     QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly));
     240    applyStyle(p, states);
     241    QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, states.fillRule));
     242    revertStyle(p, states);
    221243}
    222244
     
    231253{
    232254    applyStyle(p, states);
     255    qreal oldOpacity = p->opacity();
    233256    if (p->brush().style() != Qt::NoBrush) {
    234257        QPen save = p->pen();
    235258        p->setPen(QPen(Qt::NoPen));
    236         p->drawPolygon(m_poly);
     259        p->setOpacity(oldOpacity * states.fillOpacity);
     260        p->drawPolygon(m_poly, states.fillRule);
    237261        p->setPen(save);
    238262    }
    239     p->drawPolyline(m_poly);
     263    if (p->pen().widthF() != 0) {
     264        p->setOpacity(oldOpacity * states.strokeOpacity);
     265        p->drawPolyline(m_poly);
     266    }
     267    p->setOpacity(oldOpacity);
    240268    revertStyle(p, states);
    241269}
     
    250278{
    251279    qreal sw = strokeWidth();
    252     if (qFuzzyCompare(sw + 1, 1))
     280    if (qFuzzyIsNull(sw))
    253281        return m_rect;
    254282    else {
     
    261289void QSvgRect::draw(QPainter *p, QSvgExtraStates &states)
    262290{
     291    applyStyle(p, states);
    263292    if (m_rx || m_ry) {
    264293        QT_SVG_DRAW_SHAPE(p->drawRoundedRect(m_rect, m_rx, m_ry, Qt::RelativeSize));
     
    266295        QT_SVG_DRAW_SHAPE(p->drawRect(m_rect));
    267296    }
    268 }
     297    revertStyle(p, states);
     298}
     299
     300QSvgTspan * const QSvgText::LINEBREAK = 0;
    269301
    270302QSvgText::QSvgText(QSvgNode *parent, const QPointF &coord)
    271303    : QSvgNode(parent)
    272304    , m_coord(coord)
    273     , m_textAlignment(Qt::AlignLeft)
    274     , m_scale(1)
    275     , m_appendSpace(false)
    276305    , m_type(TEXT)
    277306    , m_size(0, 0)
    278 {
    279     m_paragraphs.push_back(QString());
    280     m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
     307    , m_mode(Default)
     308{
    281309}
    282310
    283311QSvgText::~QSvgText()
    284312{
     313    for (int i = 0; i < m_tspans.size(); ++i) {
     314        if (m_tspans[i] != LINEBREAK)
     315            delete m_tspans[i];
     316    }
    285317}
    286318
     
    296328{
    297329    applyStyle(p, states);
    298 
    299     QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
    300         styleProperty(QSvgStyleProperty::FONT));
    301     if (fontStyle && fontStyle->svgFont()) {
    302         // SVG fonts not fully supported...
    303         QString text = m_paragraphs.front();
    304         for (int i = 1; i < m_paragraphs.size(); ++i) {
    305             text.append(QLatin1Char('\n'));
    306             text.append(m_paragraphs[i]);
    307         }
    308         fontStyle->svgFont()->draw(p, m_coord, text, fontStyle->pointSize(), m_textAlignment);
    309         revertStyle(p, states);
    310         return;
    311     }
    312 
    313     // Scale the font to its correct size.
     330    qreal oldOpacity = p->opacity();
     331    p->setOpacity(oldOpacity * states.fillOpacity);
     332
     333    // Force the font to have a size of 100 pixels to avoid truncation problems
     334    // when the font is very small.
     335    qreal scale = 100.0 / p->font().pointSizeF();
     336    Qt::Alignment alignment = states.textAnchor;
     337
    314338    QTransform oldTransform = p->worldTransform();
    315     p->scale(1 / m_scale, 1 / m_scale);
     339    p->scale(1 / scale, 1 / scale);
    316340
    317341    qreal y = 0;
    318342    bool initial = true;
    319     qreal px = m_coord.x() * m_scale;
    320     qreal py = m_coord.y() * m_scale;
    321     QSizeF scaledSize = m_size * m_scale;
     343    qreal px = m_coord.x() * scale;
     344    qreal py = m_coord.y() * scale;
     345    QSizeF scaledSize = m_size * scale;
    322346
    323347    if (m_type == TEXTAREA) {
    324         if (m_textAlignment == Qt::AlignHCenter)
     348        if (alignment == Qt::AlignHCenter)
    325349            px += scaledSize.width() / 2;
    326         else if (m_textAlignment == Qt::AlignRight)
     350        else if (alignment == Qt::AlignRight)
    327351            px += scaledSize.width();
    328352    }
     
    330354    QRectF bounds;
    331355    if (m_size.height() != 0)
    332         bounds = QRectF(0, 0, 1, scaledSize.height());
    333 
    334     for (int i = 0; i < m_paragraphs.size(); ++i) {
    335         QTextLayout tl(m_paragraphs[i]);
    336         QTextOption op = tl.textOption();
    337         op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    338         tl.setTextOption(op);
    339         tl.setAdditionalFormats(m_formatRanges[i]);
    340         tl.beginLayout();
    341         forever {
    342             QTextLine line = tl.createLine();
    343             if (!line.isValid())
     356        bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used.
     357
     358    bool appendSpace = false;
     359    QVector<QString> paragraphs;
     360    QStack<QTextCharFormat> formats;
     361    QVector<QList<QTextLayout::FormatRange> > formatRanges;
     362    paragraphs.push_back(QString());
     363    formatRanges.push_back(QList<QTextLayout::FormatRange>());
     364
     365    for (int i = 0; i < m_tspans.size(); ++i) {
     366        if (m_tspans[i] == LINEBREAK) {
     367            if (m_type == TEXTAREA) {
     368                if (paragraphs.back().isEmpty()) {
     369                    QFont font = p->font();
     370                    font.setPixelSize(font.pointSizeF() * scale);
     371
     372                    QTextLayout::FormatRange range;
     373                    range.start = 0;
     374                    range.length = 1;
     375                    range.format.setFont(font);
     376                    formatRanges.back().append(range);
     377
     378                    paragraphs.back().append(QLatin1Char(' '));;
     379                }
     380                appendSpace = false;
     381                paragraphs.push_back(QString());
     382                formatRanges.push_back(QList<QTextLayout::FormatRange>());
     383            }
     384        } else {
     385            WhitespaceMode mode = m_tspans[i]->whitespaceMode();
     386            m_tspans[i]->applyStyle(p, states);
     387
     388            QFont font = p->font();
     389            font.setPixelSize(font.pointSizeF() * scale);
     390
     391            QString newText(m_tspans[i]->text());
     392            newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
     393            newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
     394
     395            bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
     396            if (appendSpace || prependSpace)
     397                paragraphs.back().append(QLatin1Char(' '));
     398
     399            bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
     400
     401            if (mode == Default) {
     402                newText = newText.simplified();
     403                if (newText.isEmpty())
     404                    appendSpaceNext = false;
     405            }
     406
     407            QTextLayout::FormatRange range;
     408            range.start = paragraphs.back().length();
     409            range.length = newText.length();
     410            range.format.setFont(font);
     411            range.format.setTextOutline(p->pen());
     412            range.format.setForeground(p->brush());
     413
     414            if (appendSpace) {
     415                Q_ASSERT(!formatRanges.back().isEmpty());
     416                ++formatRanges.back().back().length;
     417            } else if (prependSpace) {
     418                --range.start;
     419                ++range.length;
     420            }
     421            formatRanges.back().append(range);
     422
     423            appendSpace = appendSpaceNext;
     424            paragraphs.back() += newText;
     425
     426            m_tspans[i]->revertStyle(p, states);
     427        }
     428    }
     429
     430    if (states.svgFont) {
     431        // SVG fonts not fully supported...
     432        QString text = paragraphs.front();
     433        for (int i = 1; i < paragraphs.size(); ++i) {
     434            text.append(QLatin1Char('\n'));
     435            text.append(paragraphs[i]);
     436        }
     437        states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor);
     438    } else {
     439        for (int i = 0; i < paragraphs.size(); ++i) {
     440            QTextLayout tl(paragraphs[i]);
     441            QTextOption op = tl.textOption();
     442            op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
     443            tl.setTextOption(op);
     444            tl.setAdditionalFormats(formatRanges[i]);
     445            tl.beginLayout();
     446
     447            forever {
     448                QTextLine line = tl.createLine();
     449                if (!line.isValid())
     450                    break;
     451                if (m_size.width() != 0)
     452                    line.setLineWidth(scaledSize.width());
     453            }
     454            tl.endLayout();
     455
     456            bool endOfBoundsReached = false;
     457            for (int i = 0; i < tl.lineCount(); ++i) {
     458                QTextLine line = tl.lineAt(i);
     459
     460                qreal x = 0;
     461                if (alignment == Qt::AlignHCenter)
     462                    x -= 0.5 * line.naturalTextWidth();
     463                else if (alignment == Qt::AlignRight)
     464                    x -= line.naturalTextWidth();
     465
     466                if (initial && m_type == TEXT)
     467                    y -= line.ascent();
     468                initial = false;
     469
     470                line.setPosition(QPointF(x, y));
     471
     472                // Check if the current line fits into the bounding rectangle.
     473                if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
     474                    || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
     475                    // I need to set the bounds height to 'y-epsilon' to avoid drawing the current
     476                    // line. Since the font is scaled to 100 units, 1 should be a safe epsilon.
     477                    bounds.setHeight(y - 1);
     478                    endOfBoundsReached = true;
     479                    break;
     480                }
     481
     482                y += 1.1 * line.height();
     483            }
     484            tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
     485
     486            if (endOfBoundsReached)
    344487                break;
    345 
    346             if (m_size.width() != 0)
    347                 line.setLineWidth(scaledSize.width());
    348488        }
    349         tl.endLayout();
    350 
    351         bool endOfBoundsReached = false;
    352         for (int i = 0; i < tl.lineCount(); ++i) {
    353             QTextLine line = tl.lineAt(i);
    354 
    355             qreal x = 0;
    356             if (m_textAlignment == Qt::AlignHCenter)
    357                 x -= line.naturalTextWidth() / 2;
    358             else if (m_textAlignment == Qt::AlignRight)
    359                 x -= line.naturalTextWidth();
    360 
    361             if (initial && m_type == TEXT)
    362                 y -= line.ascent();
    363             initial = false;
    364 
    365             line.setPosition(QPointF(x, y));
    366             if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
    367                 || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
    368                 bounds.setHeight(y);
    369                 endOfBoundsReached = true;
    370                 break;
    371             }
    372 
    373             y += 1.1 * line.height();
    374         }
    375         tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
    376 
    377         if (endOfBoundsReached)
    378             break;
    379489    }
    380490
    381491    p->setWorldTransform(oldTransform, false);
    382     revertStyle(p, states);
    383 }
    384 
    385 void QSvgText::insertText(const QString &text, WhitespaceMode mode)
    386 {
    387     bool isTSpan = (m_formats.count() == 2);
    388     QString newText(text);
    389     newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
    390     newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
    391 
    392     bool prependSpace = !m_appendSpace && !isTSpan && (mode == Default) && !m_paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
    393     if (m_appendSpace || prependSpace)
    394         m_paragraphs.back().append(QLatin1Char(' '));
    395 
    396     bool appendSpaceNext = (!isTSpan && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
    397 
    398     if (mode == Default) {
    399         newText = newText.simplified();
    400         if (newText.isEmpty())
    401             appendSpaceNext = false;
    402     }
    403 
    404     if (!m_formats.isEmpty()) {
    405         QTextLayout::FormatRange range;
    406         range.start = m_paragraphs.back().length();
    407         range.length = newText.length();
    408         range.format = m_formats.top();
    409         if (m_appendSpace) {
    410             Q_ASSERT(!m_formatRanges.back().isEmpty());
    411             ++m_formatRanges.back().back().length;
    412         } else if (prependSpace) {
    413             --range.start;
    414             ++range.length;
    415         }
    416         m_formatRanges.back().append(range);
    417     }
    418 
    419     m_appendSpace = appendSpaceNext;
    420     m_paragraphs.back() += newText;
    421 }
    422 
    423 void QSvgText::insertFormat(const QTextCharFormat &format)
    424 {
    425     QTextCharFormat mergedFormat = format;
    426     if (!m_formats.isEmpty()) {
    427         mergedFormat = m_formats.top();
    428         mergedFormat.merge(format);
    429     }
    430     m_formats.push(mergedFormat);
    431 }
    432 
    433 void QSvgText::insertLineBreak()
    434 {
    435     if (m_type == TEXTAREA) {
    436         if (m_paragraphs.back().isEmpty())
    437             insertText(QLatin1String(" "), Preserve);
    438         m_appendSpace = false;
    439         m_paragraphs.push_back(QString());
    440         m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
    441     }
    442 }
    443 
    444 void QSvgText::popFormat()
    445 {
    446     if (m_formats.count() > 1)
    447         m_formats.pop();
    448 }
    449 
    450 qreal QSvgText::scale() const
    451 {
    452     return m_scale;
    453 }
    454 
    455 void QSvgText::setScale(qreal scale)
    456 {
    457     m_scale = scale;
    458 }
    459 
    460 const QTextCharFormat &QSvgText::topFormat() const
    461 {
    462     return m_formats.top();
    463 }
    464 
    465 void QSvgText::setTextAlignment(const Qt::Alignment &alignment)
    466 {
    467     m_textAlignment = alignment;
     492    p->setOpacity(oldOpacity);
     493    revertStyle(p, states);
     494}
     495
     496void QSvgText::addText(const QString &text)
     497{
     498    m_tspans.append(new QSvgTspan(this, false));
     499    m_tspans.back()->setWhitespaceMode(m_mode);
     500    m_tspans.back()->addText(text);
    468501}
    469502
     
    597630{
    598631    qreal sw = strokeWidth();
    599     if (qFuzzyCompare(sw + 1, 1))
     632    if (qFuzzyIsNull(sw))
    600633        return m_poly.boundingRect();
    601634    else {
     
    609642{
    610643    qreal sw = strokeWidth();
    611     if (qFuzzyCompare(sw + 1, 1))
     644    if (qFuzzyIsNull(sw))
    612645        return m_cachedBounds;
    613646    else {
     
    624657{
    625658    qreal sw = strokeWidth();
    626     if (qFuzzyCompare(sw + 1, 1)) {
     659    if (qFuzzyIsNull(sw)) {
    627660        qreal minX = qMin(m_bounds.x1(), m_bounds.x2());
    628661        qreal minY = qMin(m_bounds.y1(), m_bounds.y2());
Note: See TracChangeset for help on using the changeset viewer.