src/gui/painting/qpainter.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
    70 #include <private/qwidget_p.h>
    70 #include <private/qwidget_p.h>
    71 #include <private/qpaintengine_raster_p.h>
    71 #include <private/qpaintengine_raster_p.h>
    72 #include <private/qmath_p.h>
    72 #include <private/qmath_p.h>
    73 #include <qstatictext.h>
    73 #include <qstatictext.h>
    74 #include <private/qstatictext_p.h>
    74 #include <private/qstatictext_p.h>
       
    75 #include <private/qstylehelper_p.h>
    75 
    76 
    76 QT_BEGIN_NAMESPACE
    77 QT_BEGIN_NAMESPACE
    77 
    78 
    78 #define QGradient_StretchToDevice 0x10000000
    79 #define QGradient_StretchToDevice 0x10000000
    79 #define QPaintEngine_OpaqueBackground 0x40000000
    80 #define QPaintEngine_OpaqueBackground 0x40000000
  1561     } else if (d->engine) {
  1562     } else if (d->engine) {
  1562         d->engine->setDirty(QPaintEngine::DirtyPen);
  1563         d->engine->setDirty(QPaintEngine::DirtyPen);
  1563         d->engine->setDirty(QPaintEngine::DirtyBrush);
  1564         d->engine->setDirty(QPaintEngine::DirtyBrush);
  1564         d->engine->setDirty(QPaintEngine::DirtyFont);
  1565         d->engine->setDirty(QPaintEngine::DirtyFont);
  1565     }
  1566     }
  1566     d->state->layoutDirection = widget->layoutDirection();
       
  1567 }
  1567 }
  1568 
  1568 
  1569 
  1569 
  1570 /*!
  1570 /*!
  1571     Saves the current painter state (pushes the state onto a stack). A
  1571     Saves the current painter state (pushes the state onto a stack). A
  1871     // required for QPixmap::grabWidget()
  1871     // required for QPixmap::grabWidget()
  1872     if (d->original_device->devType() == QInternal::Widget) {
  1872     if (d->original_device->devType() == QInternal::Widget) {
  1873         QWidget *widget = static_cast<QWidget *>(d->original_device);
  1873         QWidget *widget = static_cast<QWidget *>(d->original_device);
  1874         initFrom(widget);
  1874         initFrom(widget);
  1875     } else {
  1875     } else {
  1876         d->state->layoutDirection = QApplication::layoutDirection();
  1876         d->state->layoutDirection = Qt::LayoutDirectionAuto;
  1877         // make sure we have a font compatible with the paintdevice
  1877         // make sure we have a font compatible with the paintdevice
  1878         d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
  1878         d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
  1879     }
  1879     }
  1880 
  1880 
  1881     QRect systemRect = d->engine->systemRect();
  1881     QRect systemRect = d->engine->systemRect();
  2389     Q_D(QPainter);
  2389     Q_D(QPainter);
  2390     if (!d->engine) {
  2390     if (!d->engine) {
  2391         qWarning("QPainter::setCompositionMode: Painter not active");
  2391         qWarning("QPainter::setCompositionMode: Painter not active");
  2392         return;
  2392         return;
  2393     }
  2393     }
       
  2394     if (d->state->composition_mode == mode)
       
  2395         return;
  2394     if (d->extended) {
  2396     if (d->extended) {
  2395         d->state->composition_mode = mode;
  2397         d->state->composition_mode = mode;
  2396         d->extended->compositionModeChanged();
  2398         d->extended->compositionModeChanged();
  2397         return;
  2399         return;
  2398     }
  2400     }
  4236 
  4238 
  4237     if (!d->engine)
  4239     if (!d->engine)
  4238         return;
  4240         return;
  4239 
  4241 
  4240     QRectF rect(r.normalized());
  4242     QRectF rect(r.normalized());
  4241     if (rect.isEmpty())
       
  4242         return;
       
  4243 
  4243 
  4244     if (d->extended) {
  4244     if (d->extended) {
  4245         d->extended->drawEllipse(rect);
  4245         d->extended->drawEllipse(rect);
  4246         return;
  4246         return;
  4247     }
  4247     }
  4279 
  4279 
  4280     if (!d->engine)
  4280     if (!d->engine)
  4281         return;
  4281         return;
  4282 
  4282 
  4283     QRect rect(r.normalized());
  4283     QRect rect(r.normalized());
  4284     if (rect.isEmpty())
       
  4285         return;
       
  4286 
  4284 
  4287     if (d->extended) {
  4285     if (d->extended) {
  4288         d->extended->drawEllipse(rect);
  4286         d->extended->drawEllipse(rect);
  4289         return;
  4287         return;
  4290     }
  4288     }
  5853     if (d->extended == 0 || !d->state->matrix.isAffine()) {
  5851     if (d->extended == 0 || !d->state->matrix.isAffine()) {
  5854         staticText_d->paintText(topLeftPosition, this);
  5852         staticText_d->paintText(topLeftPosition, this);
  5855         return;
  5853         return;
  5856     }
  5854     }
  5857 
  5855 
       
  5856     if (d->extended->type() == QPaintEngine::OpenGL2 && !staticText_d->untransformedCoordinates) {
       
  5857         staticText_d->untransformedCoordinates = true;
       
  5858         staticText_d->needsRelayout = true;
       
  5859     } else if (d->extended->type() != QPaintEngine::OpenGL2 && staticText_d->untransformedCoordinates) {
       
  5860         staticText_d->untransformedCoordinates = false;
       
  5861         staticText_d->needsRelayout = true;
       
  5862     }
       
  5863 
  5858     // Don't recalculate entire layout because of translation, rather add the dx and dy
  5864     // Don't recalculate entire layout because of translation, rather add the dx and dy
  5859     // into the position to move each text item the correct distance.
  5865     // into the position to move each text item the correct distance.
  5860     QPointF transformedPosition = topLeftPosition * d->state->matrix;
  5866     QPointF transformedPosition = topLeftPosition;
  5861     QTransform matrix = d->state->matrix;
  5867     if (!staticText_d->untransformedCoordinates)
       
  5868         transformedPosition = transformedPosition * d->state->matrix;
       
  5869     QTransform oldMatrix;
  5862 
  5870 
  5863     // The translation has been applied to transformedPosition. Remove translation
  5871     // The translation has been applied to transformedPosition. Remove translation
  5864     // component from matrix.
  5872     // component from matrix.
  5865     if (d->state->matrix.isTranslating()) {
  5873     if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
  5866         qreal m11 = d->state->matrix.m11();
  5874         qreal m11 = d->state->matrix.m11();
  5867         qreal m12 = d->state->matrix.m12();
  5875         qreal m12 = d->state->matrix.m12();
  5868         qreal m13 = d->state->matrix.m13();
  5876         qreal m13 = d->state->matrix.m13();
  5869         qreal m21 = d->state->matrix.m21();
  5877         qreal m21 = d->state->matrix.m21();
  5870         qreal m22 = d->state->matrix.m22();
  5878         qreal m22 = d->state->matrix.m22();
  5871         qreal m23 = d->state->matrix.m23();
  5879         qreal m23 = d->state->matrix.m23();
  5872         qreal m33 = d->state->matrix.m33();
  5880         qreal m33 = d->state->matrix.m33();
  5873 
  5881 
       
  5882         oldMatrix = d->state->matrix;
  5874         d->state->matrix.setMatrix(m11, m12, m13,
  5883         d->state->matrix.setMatrix(m11, m12, m13,
  5875                                    m21, m22, m23,
  5884                                    m21, m22, m23,
  5876                                    0.0, 0.0, m33);
  5885                                    0.0, 0.0, m33);
  5877     }
  5886     }
  5878 
  5887 
  5879     // If the transform is not identical to the text transform,
  5888     // If the transform is not identical to the text transform,
  5880     // we have to relayout the text (for other transformations than plain translation)
  5889     // we have to relayout the text (for other transformations than plain translation)
  5881     bool staticTextNeedsReinit = staticText_d->needsRelayout;
  5890     bool staticTextNeedsReinit = staticText_d->needsRelayout;
  5882     if (staticText_d->matrix != d->state->matrix) {
  5891     if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
  5883         staticText_d->matrix = d->state->matrix;
  5892         staticText_d->matrix = d->state->matrix;
  5884         staticTextNeedsReinit = true;
  5893         staticTextNeedsReinit = true;
  5885     }
  5894     }
  5886 
  5895 
  5887     // Recreate the layout of the static text because the matrix or font has changed
  5896     // Recreate the layout of the static text because the matrix or font has changed
  5916         d->extended->drawStaticTextItem(item);
  5925         d->extended->drawStaticTextItem(item);
  5917     }
  5926     }
  5918     if (currentColor != oldPen.color())
  5927     if (currentColor != oldPen.color())
  5919         setPen(oldPen);
  5928         setPen(oldPen);
  5920 
  5929 
  5921     if (matrix.isTranslating())
  5930     if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
  5922         d->state->matrix = matrix;
  5931         d->state->matrix = oldMatrix;
  5923 }
  5932 }
  5924 
  5933 
  5925 /*!
  5934 /*!
  5926    \internal
  5935    \internal
  5927 */
  5936 */
  5934 
  5943 
  5935     Q_D(QPainter);
  5944     Q_D(QPainter);
  5936 
  5945 
  5937     if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
  5946     if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
  5938         return;
  5947         return;
       
  5948 
       
  5949     if (tf & Qt::TextBypassShaping) {
       
  5950         // Skip harfbuzz complex shaping, shape using glyph advances only
       
  5951         int len = str.length();
       
  5952         int numGlyphs = len;
       
  5953         QVarLengthGlyphLayoutArray glyphs(len);
       
  5954         QFontEngine *fontEngine = d->state->font.d->engineForScript(QUnicodeTables::Common);
       
  5955         if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) {
       
  5956             glyphs.resize(numGlyphs);
       
  5957             if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0))
       
  5958                 Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
       
  5959         }
       
  5960 
       
  5961         QTextItemInt gf(glyphs, &d->state->font, str.data(), len, fontEngine);
       
  5962         drawTextItem(p, gf);
       
  5963         return;
       
  5964     }
  5939 
  5965 
  5940     QStackTextEngine engine(str, d->state->font);
  5966     QStackTextEngine engine(str, d->state->font);
  5941     engine.option.setTextDirection(d->state->layoutDirection);
  5967     engine.option.setTextDirection(d->state->layoutDirection);
  5942     if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
  5968     if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
  5943         engine.ignoreBidi = true;
  5969         engine.ignoreBidi = true;
  6215 
  6241 
  6216 static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
  6242 static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
  6217 {
  6243 {
  6218     const qreal radiusBase = qMax(qreal(1), maxRadius);
  6244     const qreal radiusBase = qMax(qreal(1), maxRadius);
  6219 
  6245 
  6220     QString key = QLatin1String("WaveUnderline-");
  6246     QString key = QLatin1Literal("WaveUnderline-")
  6221     key += pen.color().name();
  6247                   % pen.color().name()
  6222     key += QLatin1Char('-');
  6248                   % HexString<qreal>(radiusBase);
  6223     key += QString::number(radiusBase);
       
  6224 
  6249 
  6225     QPixmap pixmap;
  6250     QPixmap pixmap;
  6226     if (QPixmapCache::find(key, pixmap))
  6251     if (QPixmapCache::find(key, pixmap))
  6227         return pixmap;
  6252         return pixmap;
  6228 
  6253 
  8026 
  8051 
  8027 /*!
  8052 /*!
  8028     Sets the layout direction used by the painter when drawing text,
  8053     Sets the layout direction used by the painter when drawing text,
  8029     to the specified \a direction.
  8054     to the specified \a direction.
  8030 
  8055 
  8031     \sa layoutDirection(), drawText(), {QPainter#Settings}{Settings}
  8056     The default is Qt::LayoutDirectionAuto, which will implicitly determine the
       
  8057     direction from the text drawn.
       
  8058 
       
  8059     \sa QTextOption::setTextDirection(), layoutDirection(), drawText(), {QPainter#Settings}{Settings}
  8032 */
  8060 */
  8033 void QPainter::setLayoutDirection(Qt::LayoutDirection direction)
  8061 void QPainter::setLayoutDirection(Qt::LayoutDirection direction)
  8034 {
  8062 {
  8035     Q_D(QPainter);
  8063     Q_D(QPainter);
  8036     if (d->state)
  8064     if (d->state)
  8038 }
  8066 }
  8039 
  8067 
  8040 /*!
  8068 /*!
  8041     Returns the layout direction used by the painter when drawing text.
  8069     Returns the layout direction used by the painter when drawing text.
  8042 
  8070 
  8043     \sa setLayoutDirection(), drawText(), {QPainter#Settings}{Settings}
  8071     \sa QTextOption::textDirection(), setLayoutDirection(), drawText(), {QPainter#Settings}{Settings}
  8044 */
  8072 */
  8045 Qt::LayoutDirection QPainter::layoutDirection() const
  8073 Qt::LayoutDirection QPainter::layoutDirection() const
  8046 {
  8074 {
  8047     Q_D(const QPainter);
  8075     Q_D(const QPainter);
  8048     return d->state ? d->state->layoutDirection : Qt::LeftToRight;
  8076     return d->state ? d->state->layoutDirection : Qt::LayoutDirectionAuto;
  8049 }
  8077 }
  8050 
  8078 
  8051 QPainterState::QPainterState(const QPainterState *s)
  8079 QPainterState::QPainterState(const QPainterState *s)
  8052     : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
  8080     : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
  8053       pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
  8081       pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
  8939     Q_D(QPainter);
  8967     Q_D(QPainter);
  8940 
  8968 
  8941     if (!d->engine)
  8969     if (!d->engine)
  8942         return;
  8970         return;
  8943 
  8971 
       
  8972 #ifndef QT_NO_DEBUG
       
  8973     for (int i = 0; i < fragmentCount; ++i) {
       
  8974         QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
       
  8975                           fragments[i].width, fragments[i].height);
       
  8976         if (!(QRectF(pixmap.rect()).contains(sourceRect)))
       
  8977             qWarning("QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
       
  8978     }
       
  8979 #endif
       
  8980 
  8944     if (d->engine->isExtended()) {
  8981     if (d->engine->isExtended()) {
  8945         d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
  8982         d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
  8946     } else {
  8983     } else {
  8947         qreal oldOpacity = opacity();
  8984         qreal oldOpacity = opacity();
  8948         QTransform oldTransform = transform();
  8985         QTransform oldTransform = transform();