src/gui/painting/qpainter.cpp
changeset 30 5dc02b23752f
parent 29 b72c6db6890b
child 33 3e2da88830cd
--- a/src/gui/painting/qpainter.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/gui/painting/qpainter.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -38,6 +38,7 @@
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
+
 // QtCore
 #include <qdebug.h>
 #include <qmath.h>
@@ -69,6 +70,8 @@
 #include <private/qwidget_p.h>
 #include <private/qpaintengine_raster_p.h>
 #include <private/qmath_p.h>
+#include <qstatictext.h>
+#include <private/qstatictext_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -967,7 +970,7 @@
     devices. If the painter is active, device() returns the paint
     device on which the painter paints, and paintEngine() returns the
     paint engine that the painter is currently operating on. For more
-    information, see \l {The Paint System} documentation.
+    information, see the \l {Paint System}.
 
     Sometimes it is desirable to make someone else paint on an unusual
     QPaintDevice. QPainter supports a static function to do this,
@@ -1012,7 +1015,7 @@
 
     \o viewport(), window(), worldTransform() make up the painter's coordinate
         transformation system. For more information, see the \l
-        {Coordinate Transformations} section and the \l {The Coordinate
+        {Coordinate Transformations} section and the \l {Coordinate
         System} documentation.
 
     \o hasClipping() tells whether the painter clips at all. (The paint
@@ -1219,7 +1222,7 @@
     All the tranformation operations operate on the transformation
     worldTransform(). A matrix transforms a point in the plane to another
     point. For more information about the transformation matrix, see
-    the \l {The Coordinate System} and QTransform documentation.
+    the \l {Coordinate System} and QTransform documentation.
 
     The setWorldTransform() function can replace or add to the currently
     set worldTransform(). The resetTransform() function resets any
@@ -1241,7 +1244,7 @@
     logical coordinates, and the worldTransform() is identical with the
     transformation matrix.
 
-    See also \l {The Coordinate System} documentation.
+    See also \l {Coordinate System}
 
     \section1 Clipping
 
@@ -2877,8 +2880,7 @@
     functions is safe.
 
     For more information about the coordinate system, transformations
-    and window-viewport conversion, see \l {The Coordinate System}
-    documentation.
+    and window-viewport conversion, see \l {Coordinate System}.
 
     \sa setWorldTransform(), QTransform
 */
@@ -2898,7 +2900,7 @@
     preserve the properties of perspective transformations.
 
     \sa {QPainter#Coordinate Transformations}{Coordinate Transformations},
-    {The Coordinate System}
+    {Coordinate System}
 */
 
 const QMatrix &QPainter::worldMatrix() const
@@ -3041,7 +3043,7 @@
     Returns true if world transformation is enabled; otherwise returns
     false.
 
-    \sa setWorldMatrixEnabled(), worldTransform(), {The Coordinate System}
+    \sa setWorldMatrixEnabled(), worldTransform(), {Coordinate System}
 */
 
 bool QPainter::worldMatrixEnabled() const
@@ -3383,7 +3385,7 @@
     \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 6
     \endtable
 
-    \sa drawLines(), drawPolyline(), {The Coordinate System}
+    \sa drawLines(), drawPolyline(), {Coordinate System}
 */
 
 /*!
@@ -3430,7 +3432,7 @@
     \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 7
     \endtable
 
-    \sa drawRects(), drawPolygon(), {The Coordinate System}
+    \sa drawRects(), drawPolygon(), {Coordinate System}
 */
 
 /*!
@@ -3594,7 +3596,7 @@
     Draws a single point at the given \a position using the current
     pen's color.
 
-    \sa {The Coordinate System}
+    \sa {Coordinate System}
 */
 
 /*!
@@ -3616,7 +3618,7 @@
     Draws the first \a pointCount points in the array \a points using
     the current pen's color.
 
-    \sa {The Coordinate System}
+    \sa {Coordinate System}
 */
 void QPainter::drawPoints(const QPointF *points, int pointCount)
 {
@@ -4222,7 +4224,7 @@
     \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 9
     \endtable
 
-    \sa drawPie(), {The Coordinate System}
+    \sa drawPie(), {Coordinate System}
 */
 void QPainter::drawEllipse(const QRectF &r)
 {
@@ -4352,7 +4354,7 @@
     \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 10
     \endtable
 
-    \sa drawPie(), drawChord(), {The Coordinate System}
+    \sa drawPie(), drawChord(), {Coordinate System}
 */
 
 void QPainter::drawArc(const QRectF &r, int a, int alen)
@@ -4416,7 +4418,7 @@
     \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 11
     \endtable
 
-    \sa drawEllipse(), drawChord(), {The Coordinate System}
+    \sa drawEllipse(), drawChord(), {Coordinate System}
 */
 void QPainter::drawPie(const QRectF &r, int a, int alen)
 {
@@ -4485,7 +4487,7 @@
     \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 12
     \endtable
 
-    \sa drawArc(), drawPie(), {The Coordinate System}
+    \sa drawArc(), drawPie(), {Coordinate System}
 */
 void QPainter::drawChord(const QRectF &r, int a, int alen)
 {
@@ -4776,7 +4778,7 @@
     \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 13
     \endtable
 
-    \sa drawLines(), drawPolygon(), {The Coordinate System}
+    \sa drawLines(), drawPolygon(), {Coordinate System}
 */
 void QPainter::drawPolyline(const QPointF *points, int pointCount)
 {
@@ -4915,7 +4917,7 @@
     \l{Qt::FillRule} for a more detailed description of these fill
     rules.
 
-    \sa  drawConvexPolygon(), drawPolyline(), {The Coordinate System}
+    \sa  drawConvexPolygon(), drawPolyline(), {Coordinate System}
 */
 void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
 {
@@ -5066,7 +5068,7 @@
     On some platforms (e.g. X11), the drawConvexPolygon() function can
     be faster than the drawPolygon() function.
 
-    \sa drawPolygon(), drawPolyline(), {The Coordinate System}
+    \sa drawPolygon(), drawPolyline(), {Coordinate System}
 */
 
 /*!
@@ -5411,10 +5413,15 @@
         scale(w / sw, h / sh);
         setBackgroundMode(Qt::TransparentMode);
         setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
-        QBrush brush(d->state->pen.color(), pm);
+        QBrush brush;
+
+        if (sw == pm.width() && sh == pm.height())
+            brush = QBrush(d->state->pen.color(), pm);
+        else
+            brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
+
         setBrush(brush);
         setPen(Qt::NoPen);
-        setBrushOrigin(QPointF(-sx, -sy));
 
         drawRect(QRectF(0, 0, sw, sh));
         restore();
@@ -5697,6 +5704,93 @@
     d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
 }
 
+
+void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray,
+                    int glyphCount)
+{
+    QPainterPrivate *painter_d = QPainterPrivate::get(painter);
+    painter_d->drawGlyphs(glyphArray, positionArray, glyphCount);
+}
+
+void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *positionArray,
+                                 int glyphCount)
+{
+    updateState(state);
+
+    QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common);
+
+    while (fontEngine->type() == QFontEngine::Multi) {
+        // Pick engine based on first glyph in array if we are using a multi engine.
+        // (all glyphs must be for same font)
+        int engineIdx = 0;
+        if (glyphCount > 0)
+            engineIdx = glyphArray[0] >> 24;
+
+        fontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
+    }
+
+    QVarLengthArray<QFixedPoint, 128> positions;
+    for (int i=0; i<glyphCount; ++i) {
+        QFixedPoint fp = QFixedPoint::fromPointF(positionArray[i]);
+        positions.append(fp);
+    }
+
+    if (extended != 0) {
+        QStaticTextItem staticTextItem;
+        staticTextItem.color = state->pen.color();
+        staticTextItem.font = state->font;
+        staticTextItem.fontEngine = fontEngine;
+        staticTextItem.numGlyphs = glyphCount;
+        staticTextItem.glyphs = reinterpret_cast<glyph_t *>(const_cast<glyph_t *>(glyphArray));
+        staticTextItem.glyphPositions = positions.data();
+
+        extended->drawStaticTextItem(&staticTextItem);
+    } else {
+        QTextItemInt textItem;
+        textItem.f = &state->font;
+        textItem.fontEngine = fontEngine;
+
+        QVarLengthArray<QFixed, 128> advances(glyphCount);
+        QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
+        QVarLengthArray<HB_GlyphAttributes, 128> glyphAttributes(glyphCount);
+        qMemSet(glyphAttributes.data(), 0, glyphAttributes.size() * sizeof(HB_GlyphAttributes));
+        qMemSet(advances.data(), 0, advances.size() * sizeof(QFixed));
+        qMemSet(glyphJustifications.data(), 0, glyphJustifications.size() * sizeof(QGlyphJustification));
+
+        textItem.glyphs.numGlyphs = glyphCount;
+        textItem.glyphs.glyphs = reinterpret_cast<HB_Glyph *>(const_cast<quint32 *>(glyphArray));
+        textItem.glyphs.offsets = positions.data();
+        textItem.glyphs.advances_x = advances.data();
+        textItem.glyphs.advances_y = advances.data();
+        textItem.glyphs.justifications = glyphJustifications.data();
+        textItem.glyphs.attributes = glyphAttributes.data();
+
+        engine->drawTextItem(QPointF(0, 0), textItem);
+    }
+}
+
+/*!
+
+    \fn void QPainter::drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText)
+    \since 4.7
+    \overload
+
+    Draws the \a staticText at the \a topLeftPosition.
+
+    \note The y-position is used as the top of the font.
+
+*/
+
+/*!
+    \fn void QPainter::drawStaticText(int left, int top, const QStaticText &staticText)
+    \since 4.7
+    \overload
+
+    Draws the \a staticText at coordinates \a left and \a top.
+
+    \note The y-position is used as the top of the font.
+*/
+
 /*!
     \fn void QPainter::drawText(const QPointF &position, const QString &text)
 
@@ -5720,6 +5814,115 @@
 }
 
 /*!
+    \since 4.7
+
+    Draws the given \a staticText at the given \a topLeftPosition.
+
+    The text will be drawn using the font and the transformation set on the painter. If the
+    font and/or transformation set on the painter are different from the ones used to initialize
+    the layout of the QStaticText, then the layout will have to be recalculated. Use
+    QStaticText::prepare() to initialize \a staticText with the font and transformation with which
+    it will later be drawn.
+
+    If \a topLeftPosition is not the same as when \a staticText was initialized, or when it was
+    last drawn, then there will be a slight overhead when translating the text to its new position.
+
+    \note If the painter's transformation is not affine, then \a staticText will be drawn using
+    regular calls to drawText(), losing any potential for performance improvement.
+
+    \note The y-position is used as the top of the font.
+
+    \sa QStaticText
+*/
+void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText)
+{
+    Q_D(QPainter);
+    if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
+        return;
+
+    QStaticTextPrivate *staticText_d =
+            const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
+
+    if (font() != staticText_d->font) {
+        staticText_d->font = font();
+        staticText_d->needsRelayout = true;
+    }
+
+    // If we don't have an extended paint engine, or if the painter is projected,
+    // we go through standard code path
+    if (d->extended == 0 || !d->state->matrix.isAffine()) {
+        staticText_d->paintText(topLeftPosition, this);
+        return;
+    }
+
+    // Don't recalculate entire layout because of translation, rather add the dx and dy
+    // into the position to move each text item the correct distance.
+    QPointF transformedPosition = topLeftPosition * d->state->matrix;
+    QTransform matrix = d->state->matrix;
+
+    // The translation has been applied to transformedPosition. Remove translation
+    // component from matrix.
+    if (d->state->matrix.isTranslating()) {
+        qreal m11 = d->state->matrix.m11();
+        qreal m12 = d->state->matrix.m12();
+        qreal m13 = d->state->matrix.m13();
+        qreal m21 = d->state->matrix.m21();
+        qreal m22 = d->state->matrix.m22();
+        qreal m23 = d->state->matrix.m23();
+        qreal m33 = d->state->matrix.m33();
+
+        d->state->matrix.setMatrix(m11, m12, m13,
+                                   m21, m22, m23,
+                                   0.0, 0.0, m33);
+    }
+
+    // If the transform is not identical to the text transform,
+    // we have to relayout the text (for other transformations than plain translation)
+    bool staticTextNeedsReinit = staticText_d->needsRelayout;
+    if (staticText_d->matrix != d->state->matrix) {
+        staticText_d->matrix = d->state->matrix;
+        staticTextNeedsReinit = true;
+    }
+
+    // Recreate the layout of the static text because the matrix or font has changed
+    if (staticTextNeedsReinit)
+        staticText_d->init();    
+
+    if (transformedPosition != staticText_d->position) { // Translate to actual position
+        QFixed fx = QFixed::fromReal(transformedPosition.x());
+        QFixed fy = QFixed::fromReal(transformedPosition.y());
+        QFixed oldX = QFixed::fromReal(staticText_d->position.x());
+        QFixed oldY = QFixed::fromReal(staticText_d->position.y());
+        for (int item=0; item<staticText_d->itemCount;++item) {
+            QStaticTextItem *textItem = staticText_d->items + item;
+            for (int i=0; i<textItem->numGlyphs; ++i) {
+                textItem->glyphPositions[i].x += fx - oldX;
+                textItem->glyphPositions[i].y += fy - oldY;
+            }
+            textItem->userDataNeedsUpdate = true;
+        }
+
+        staticText_d->position = transformedPosition;
+    }
+
+    QPen oldPen = d->state->pen;
+    QColor currentColor = oldPen.color();
+    for (int i=0; i<staticText_d->itemCount; ++i) {
+        QStaticTextItem *item = staticText_d->items + i;
+        if (item->color.isValid() && currentColor != item->color) {
+            setPen(item->color);
+            currentColor = item->color;
+        }
+        d->extended->drawStaticTextItem(item);
+    }
+    if (currentColor != oldPen.color())
+        setPen(oldPen);
+
+    if (matrix.isTranslating())
+        d->state->matrix = matrix;
+}
+
+/*!
    \internal
 */
 void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
@@ -6908,7 +7111,7 @@
     The default window rectangle is the same as the device's
     rectangle.
 
-    \sa window(), viewTransformEnabled(), {The Coordinate
+    \sa window(), viewTransformEnabled(), {Coordinate
     System#Window-Viewport Conversion}{Window-Viewport Conversion}
 */
 
@@ -6972,7 +7175,7 @@
     The default viewport rectangle is the same as the device's
     rectangle.
 
-    \sa viewport(), viewTransformEnabled() {The Coordinate
+    \sa viewport(), viewTransformEnabled() {Coordinate
     System#Window-Viewport Conversion}{Window-Viewport Conversion}
 */
 
@@ -7056,7 +7259,7 @@
     Enables view transformations if \a enable is true, or disables
     view transformations if \a enable is false.
 
-    \sa viewTransformEnabled(), {The Coordinate System#Window-Viewport
+    \sa viewTransformEnabled(), {Coordinate System#Window-Viewport
     Conversion}{Window-Viewport Conversion}
 */
 
@@ -7806,7 +8009,7 @@
         for (int i = 0; i < textLayout.lineCount(); i++) {
             QTextLine line = textLayout.lineAt(i);
 
-            qreal advance = textLayout.engine()->lines[i].textAdvance.toReal();
+            qreal advance = line.horizontalAdvance();
             if (tf & Qt::AlignRight)
                 xoff = r.width() - advance;
             else if (tf & Qt::AlignHCenter)
@@ -8715,6 +8918,167 @@
     return d->state->worldMatrix * d->viewTransform();
 }
 
+/*!
+    \since 4.7
+
+    This function is used to draw \a pixmap, or a sub-rectangle of \a pixmap,
+    at multiple positions with different scale, rotation and opacity. \a
+    fragments is an array of \a fragmentCount elements specifying the
+    parameters used to draw each pixmap fragment. The \a hints
+    parameter can be used to pass in drawing hints.
+
+    This function is potentially faster than multiple calls to drawPixmap(),
+    since the backend can optimize state changes.
+
+    \sa QPainter::PixmapFragment, QPainter::PixmapFragmentHint
+*/
+
+void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount,
+                                   const QPixmap &pixmap, PixmapFragmentHints hints)
+{
+    Q_D(QPainter);
+
+    if (!d->engine)
+        return;
+
+    if (d->engine->isExtended()) {
+        d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
+    } else {
+        qreal oldOpacity = opacity();
+        QTransform oldTransform = transform();
+
+        for (int i = 0; i < fragmentCount; ++i) {
+            QTransform transform = oldTransform;
+            qreal xOffset = 0;
+            qreal yOffset = 0;
+            if (fragments[i].rotation == 0) {
+                xOffset = fragments[i].x;
+                yOffset = fragments[i].y;
+            } else {
+                transform.translate(fragments[i].x, fragments[i].y);
+                transform.rotate(fragments[i].rotation);
+            }
+            setOpacity(oldOpacity * fragments[i].opacity);
+            setTransform(transform);
+
+            qreal w = fragments[i].scaleX * fragments[i].width;
+            qreal h = fragments[i].scaleY * fragments[i].height;
+            QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
+                              fragments[i].width, fragments[i].height);
+            drawPixmap(QRectF(-0.5 * w + xOffset, -0.5 * h + yOffset, w, h), pixmap, sourceRect);
+        }
+
+        setOpacity(oldOpacity);
+        setTransform(oldTransform);
+    }
+}
+
+/*!
+    \since 4.7
+    \class QPainter::PixmapFragment
+
+    \brief This class is used in conjunction with the
+    QPainter::drawPixmapFragments() function to specify how a pixmap, or
+    sub-rect of a pixmap, is drawn.
+
+    The \a sourceLeft, \a sourceTop, \a width and \a height variables are used
+    as a source rectangle within the pixmap passed into the
+    QPainter::drawPixmapFragments() function. The variables \a x, \a y, \a
+    width and \a height are used to calculate the target rectangle that is
+    drawn. \a x and \a y denotes the center of the target rectangle. The \a
+    width and \a heigth in the target rectangle is scaled by the \a scaleX and
+    \a scaleY values. The resulting target rectangle is then rotated \a
+    rotation degrees around the \a x, \a y center point.
+
+    \sa QPainter::drawPixmapFragments()
+*/
+
+/*!
+    \since 4.7
+
+    This is a convenience function that returns a QPainter::PixmapFragment that is
+    initialized with the \a pos, \a sourceRect, \a scaleX, \a scaleY, \a
+    rotation, \a opacity parameters.
+*/
+
+QPainter::PixmapFragment QPainter::PixmapFragment::create(const QPointF &pos, const QRectF &sourceRect,
+                                              qreal scaleX, qreal scaleY, qreal rotation,
+                                              qreal opacity)
+{
+    PixmapFragment fragment = {pos.x(), pos.y(), sourceRect.x(), sourceRect.y(), sourceRect.width(),
+                               sourceRect.height(), scaleX, scaleY, rotation, opacity};
+    return fragment;
+}
+
+/*!
+    \variable QPainter::PixmapFragment::x
+    \brief the x coordinate of center point in the target rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::y
+    \brief the y coordinate of the center point in the target rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::sourceLeft
+    \brief the left coordinate of the source rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::sourceTop
+    \brief the top coordinate of the source rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::width
+
+    \brief the width of the source rectangle and is used to calculate the width
+    of the target rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::height
+
+    \brief the height of the source rectangle and is used to calculate the
+    height of the target rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::scaleX
+    \brief the horizontal scale of the target rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::scaleY
+    \brief the vertical scale of the target rectangle.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::rotation
+
+    \brief the rotation of the target rectangle in degrees. The target
+    rectangle is rotated after it has been scaled.
+*/
+
+/*!
+    \variable QPainter::PixmapFragment::opacity
+
+    \brief the opacity of the target rectangle, where 0.0 is fully transparent
+    and 1.0 is fully opaque.
+*/
+
+/*!
+    \since 4.7
+
+    \enum QPainter::PixmapFragmentHint
+
+    \value OpaqueHint Indicates that the pixmap fragments to be drawn are
+    opaque. Opaque fragments are potentially faster to draw.
+
+    \sa QPainter::drawPixmapFragments(), QPainter::PixmapFragment
+*/
+
 void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
 {
     p->draw_helper(path, operation);