summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qpainter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting/qpainter.cpp')
-rw-r--r--src/gui/painting/qpainter.cpp8526
1 files changed, 8526 insertions, 0 deletions
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
new file mode 100644
index 0000000..1f61e2f
--- /dev/null
+++ b/src/gui/painting/qpainter.cpp
@@ -0,0 +1,8526 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+// QtCore
+#include <qdebug.h>
+#include <qmath.h>
+#include <qmutex.h>
+
+// QtGui
+#include "qbitmap.h"
+#include "qimage.h"
+#include "qpaintdevice.h"
+#include "qpaintengine.h"
+#include "qpainter.h"
+#include "qpainter_p.h"
+#include "qpainterpath.h"
+#include "qpicture.h"
+#include "qpixmapcache.h"
+#include "qpolygon.h"
+#include "qtextlayout.h"
+#include "qwidget.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qthread.h"
+#include "qvarlengtharray.h"
+
+#include <private/qfontengine_p.h>
+#include <private/qpaintengine_p.h>
+#include <private/qemulationpaintengine_p.h>
+#include <private/qpainterpath_p.h>
+#include <private/qtextengine_p.h>
+#include <private/qwidget_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <private/qmath_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QGradient_StretchToDevice 0x10000000
+#define QPaintEngine_OpaqueBackground 0x40000000
+
+// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
+
+// #define QT_DEBUG_DRAW
+#ifdef QT_DEBUG_DRAW
+bool qt_show_painter_debug_output = true;
+#endif
+
+extern QPixmap qt_pixmapForBrush(int style, bool invert);
+
+void qt_format_text(const QFont &font,
+ const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
+ int tabstops, int* tabarray, int tabarraylen,
+ QPainter *painter);
+
+static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
+{
+ switch (brush.style()) {
+ case Qt::LinearGradientPattern:
+ case Qt::RadialGradientPattern:
+ case Qt::ConicalGradientPattern:
+ return brush.gradient()->coordinateMode();
+ default:
+ ;
+ }
+ return QGradient::LogicalMode;
+}
+
+/* Returns true if the gradient requires stretch to device...*/
+static inline bool check_gradient(const QBrush &brush)
+{
+ return coordinateMode(brush) == QGradient::StretchToDeviceMode;
+}
+
+extern bool qHasPixmapTexture(const QBrush &);
+
+static inline bool is_brush_transparent(const QBrush &brush) {
+ Qt::BrushStyle s = brush.style();
+ bool brushBitmap = qHasPixmapTexture(brush)
+ ? brush.texture().isQBitmap()
+ : (brush.textureImage().depth() == 1);
+ return ((s >= Qt::Dense1Pattern && s <= Qt::DiagCrossPattern)
+ || (s == Qt::TexturePattern && brushBitmap));
+}
+
+static inline bool is_pen_transparent(const QPen &pen) {
+ return pen.style() > Qt::SolidLine || is_brush_transparent(pen.brush());
+}
+
+/* Discards the emulation flags that are not relevant for line drawing
+ and returns the result
+*/
+static inline uint line_emulation(uint emulation)
+{
+ return emulation & (QPaintEngine::PrimitiveTransform
+ | QPaintEngine::AlphaBlend
+ | QPaintEngine::Antialiasing
+ | QPaintEngine::BrushStroke
+ | QPaintEngine::ConstantOpacity
+ | QGradient_StretchToDevice
+ | QPaintEngine::ObjectBoundingModeGradients
+ | QPaintEngine_OpaqueBackground);
+}
+
+#ifndef QT_NO_DEBUG
+static bool qt_painter_thread_test(int devType, const char *what, bool extraCondition = false)
+{
+ switch (devType) {
+ case QInternal::Image:
+ case QInternal::Printer:
+ case QInternal::Picture:
+ // can be drawn onto these devices safely from any thread
+#ifndef Q_WS_WIN
+ if (extraCondition)
+#endif
+ break;
+ default:
+ if (!extraCondition && QThread::currentThread() != qApp->thread()) {
+ qWarning("QPainter: It is not safe to use %s outside the GUI thread", what);
+ return false;
+ }
+ break;
+ }
+ return true;
+}
+#endif
+
+void QPainterPrivate::checkEmulation()
+{
+ Q_ASSERT(extended);
+ bool doEmulation = false;
+ if (state->bgMode == Qt::OpaqueMode)
+ doEmulation = true;
+
+ const QGradient *bg = state->brush.gradient();
+ if (bg && bg->coordinateMode() > QGradient::LogicalMode)
+ doEmulation = true;
+
+ const QGradient *pg = qpen_brush(state->pen).gradient();
+ if (pg && pg->coordinateMode() > QGradient::LogicalMode)
+ doEmulation = true;
+
+ if (doEmulation) {
+ if (extended != emulationEngine) {
+ if (!emulationEngine)
+ emulationEngine = new QEmulationPaintEngine(extended);
+ extended = emulationEngine;
+ extended->setState(state);
+ }
+ } else if (emulationEngine && emulationEngine != extended) {
+ extended = emulationEngine->real_engine;
+ }
+}
+
+
+QPainterPrivate::~QPainterPrivate()
+{
+ delete emulationEngine;
+ for (int i=0; i<states.size(); ++i)
+ delete states.at(i);
+
+ if (dummyState)
+ delete dummyState;
+}
+
+
+QTransform QPainterPrivate::viewTransform() const
+{
+ if (state->VxF) {
+ qreal scaleW = qreal(state->vw)/qreal(state->ww);
+ qreal scaleH = qreal(state->vh)/qreal(state->wh);
+ return QTransform(scaleW, 0, 0, scaleH,
+ state->vx - state->wx*scaleW, state->vy - state->wy*scaleH);
+ }
+ return QTransform();
+}
+
+
+/*
+ \internal
+ Returns true if using a shared painter; otherwise false.
+*/
+bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev)
+{
+ Q_ASSERT(q);
+ Q_ASSERT(pdev);
+
+ if (pdev->devType() != QInternal::Widget)
+ return false;
+
+ QWidget *widget = static_cast<QWidget *>(pdev);
+ Q_ASSERT(widget);
+
+ // Someone either called QPainter::setRedirected in the widget's paint event
+ // right before this painter was created (or begin was called) or
+ // sent a paint event directly to the widget.
+ if (!widget->d_func()->redirectDev)
+ return false;
+
+ QPainter *sp = widget->d_func()->sharedPainter();
+ if (!sp || !sp->isActive())
+ return false;
+
+ if (sp->paintEngine()->paintDevice() != widget->d_func()->redirectDev)
+ return false;
+
+ // Check if we're attempting to paint outside a paint event.
+ if (!sp->d_ptr->engine->hasFeature(QPaintEngine::PaintOutsidePaintEvent)
+ && !widget->testAttribute(Qt::WA_PaintOutsidePaintEvent)
+ && !widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
+
+ qWarning("QPainter::begin: Widget painting can only begin as a result of a paintEvent");
+ return false;
+ }
+
+ // Save the current state of the shared painter and assign
+ // the current d_ptr to the shared painter's d_ptr.
+ sp->save();
+ if (!sp->d_ptr->d_ptrs) {
+ // Allocate space for 4 d-pointers (enough for up to 4 sub-sequent
+ // redirections within the same paintEvent(), which should be enough
+ // in 99% of all cases). E.g: A renders B which renders C which renders D.
+ sp->d_ptr->d_ptrs_size = 4;
+ sp->d_ptr->d_ptrs = (QPainterPrivate **)malloc(4 * sizeof(QPainterPrivate *));
+ } else if (sp->d_ptr->refcount - 1 == sp->d_ptr->d_ptrs_size) {
+ // However, to support corner cases we grow the array dynamically if needed.
+ sp->d_ptr->d_ptrs_size <<= 1;
+ const int newSize = sp->d_ptr->d_ptrs_size * sizeof(QPainterPrivate *);
+ sp->d_ptr->d_ptrs = (QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize);
+ }
+ sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr;
+ q->d_ptr = sp->d_ptr;
+
+ Q_ASSERT(q->d_ptr->state);
+
+ // Now initialize the painter with correct widget properties.
+ q->initFrom(widget);
+ QPoint offset;
+ widget->d_func()->redirected(&offset);
+ offset += q->d_ptr->engine->coordinateOffset();
+
+ // Update system rect.
+ q->d_ptr->state->ww = q->d_ptr->state->vw = widget->width();
+ q->d_ptr->state->wh = q->d_ptr->state->vh = widget->height();
+
+ // Update matrix.
+ if (q->d_ptr->state->WxF)
+ q->d_ptr->state->worldMatrix.translate(-offset.x(), -offset.y());
+ else
+ q->d_ptr->state->redirection_offset = offset;
+ q->d_ptr->updateMatrix();
+
+ QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
+ if (enginePrivate->currentClipWidget == widget) {
+ enginePrivate->systemStateChanged();
+ return true;
+ }
+
+ // Update system transform and clip.
+ enginePrivate->currentClipWidget = widget;
+ enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
+ return true;
+}
+
+void QPainterPrivate::detachPainterPrivate(QPainter *q)
+{
+ Q_ASSERT(refcount > 1);
+ Q_ASSERT(q);
+
+ QPainterPrivate *original = d_ptrs[--refcount - 1];
+ if (inDestructor) {
+ inDestructor = false;
+ if (original)
+ original->inDestructor = true;
+ } else if (!original) {
+ original = new QPainterPrivate(q);
+ }
+
+ d_ptrs[refcount - 1] = 0;
+ q->restore();
+ q->d_ptr = original;
+
+ if (emulationEngine) {
+ extended = emulationEngine->real_engine;
+ delete emulationEngine;
+ emulationEngine = 0;
+ }
+}
+
+
+void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperation op)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output) {
+ printf("QPainter::drawHelper\n");
+ }
+#endif
+
+ if (originalPath.isEmpty())
+ return;
+
+ QPaintEngine::PaintEngineFeatures gradientStretch =
+ QPaintEngine::PaintEngineFeatures(QGradient_StretchToDevice
+ | QPaintEngine::ObjectBoundingModeGradients);
+
+ const bool mustEmulateObjectBoundingModeGradients = extended
+ || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
+ && !engine->hasFeature(QPaintEngine::PatternTransform));
+
+ if (!(state->emulationSpecifier & ~gradientStretch)
+ && !mustEmulateObjectBoundingModeGradients) {
+ drawStretchedGradient(originalPath, op);
+ return;
+ } else if (state->emulationSpecifier & QPaintEngine_OpaqueBackground) {
+ drawOpaqueBackground(originalPath, op);
+ return;
+ }
+
+ Q_Q(QPainter);
+
+ qreal strokeOffsetX = 0, strokeOffsetY = 0;
+
+ QPainterPath path = originalPath * state->matrix;
+ QRectF pathBounds = path.boundingRect();
+ QRectF strokeBounds;
+ bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
+ if (doStroke) {
+ qreal penWidth = state->pen.widthF();
+ if (penWidth == 0) {
+ strokeOffsetX = 1;
+ strokeOffsetY = 1;
+ } else {
+ // In case of complex xform
+ if (state->matrix.type() > QTransform::TxScale) {
+ QPainterPathStroker stroker;
+ stroker.setWidth(penWidth);
+ stroker.setJoinStyle(state->pen.joinStyle());
+ stroker.setCapStyle(state->pen.capStyle());
+ QPainterPath stroke = stroker.createStroke(originalPath);
+ strokeBounds = (stroke * state->matrix).boundingRect();
+ } else {
+ strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0);
+ strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0);
+ }
+ }
+ }
+
+ QRect absPathRect;
+ if (!strokeBounds.isEmpty()) {
+ absPathRect = strokeBounds.intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
+ } else {
+ absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
+ .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
+ }
+
+ if (q->hasClipping()) {
+ bool hasPerspectiveTransform = false;
+ for (int i = 0; i < state->clipInfo.size(); ++i) {
+ const QPainterClipInfo &info = state->clipInfo.at(i);
+ if (info.matrix.type() == QTransform::TxProject) {
+ hasPerspectiveTransform = true;
+ break;
+ }
+ }
+ // avoid mapping QRegions with perspective transforms
+ if (!hasPerspectiveTransform) {
+ // The trick with txinv and invMatrix is done in order to
+ // avoid transforming the clip to logical coordinates, and
+ // then back to device coordinates. This is a problem with
+ // QRegion/QRect based clips, since they use integer
+ // coordinates and converting to/from logical coordinates will
+ // lose precision.
+ bool old_txinv = txinv;
+ QTransform old_invMatrix = invMatrix;
+ txinv = true;
+ invMatrix = QTransform().translate(-state->redirection_offset.x(), -state->redirection_offset.y());
+ QPainterPath clipPath = q->clipPath();
+ QRectF r = clipPath.boundingRect().intersected(absPathRect);
+ absPathRect = r.toAlignedRect();
+ txinv = old_txinv;
+ invMatrix = old_invMatrix;
+ }
+ }
+
+// qDebug("\nQPainterPrivate::draw_helper(), x=%d, y=%d, w=%d, h=%d",
+// devMinX, devMinY, device->width(), device->height());
+// qDebug() << " - matrix" << state->matrix;
+// qDebug() << " - originalPath.bounds" << originalPath.boundingRect();
+// qDebug() << " - path.bounds" << path.boundingRect();
+
+ if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
+ return;
+
+ QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
+ image.fill(0);
+
+ QPainter p(&image);
+
+ p.d_ptr->helper_device = helper_device;
+
+ p.setOpacity(state->opacity);
+ p.translate(-absPathRect.x(), -absPathRect.y());
+ p.setTransform(state->matrix, true);
+ p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
+ p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
+ p.setBackground(state->bgBrush);
+ p.setBackgroundMode(state->bgMode);
+ p.setBrushOrigin(state->brushOrigin);
+
+ p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
+ p.setRenderHint(QPainter::SmoothPixmapTransform,
+ state->renderHints & QPainter::SmoothPixmapTransform);
+
+ p.drawPath(originalPath);
+
+#ifndef QT_NO_DEBUG
+ static bool do_fallback_overlay = qgetenv("QT_PAINT_FALLBACK_OVERLAY").size() > 0;
+ if (do_fallback_overlay) {
+ QImage block(8, 8, QImage::Format_ARGB32_Premultiplied);
+ QPainter pt(&block);
+ pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
+ pt.drawLine(0, 0, 8, 8);
+ pt.end();
+ p.resetTransform();
+ p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
+ p.setOpacity(0.5);
+ p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
+ }
+#endif
+
+ p.end();
+
+ q->save();
+ q->resetMatrix();
+ updateState(state);
+ engine->drawImage(absPathRect,
+ image,
+ QRectF(0, 0, absPathRect.width(), absPathRect.height()),
+ Qt::OrderedDither | Qt::OrderedAlphaDither);
+ q->restore();
+}
+
+void QPainterPrivate::drawOpaqueBackground(const QPainterPath &path, DrawOperation op)
+{
+ Q_Q(QPainter);
+
+ q->setBackgroundMode(Qt::TransparentMode);
+
+ if (op & FillDraw && state->brush.style() != Qt::NoBrush) {
+ q->fillPath(path, state->bgBrush.color());
+ q->fillPath(path, state->brush);
+ }
+
+ if (op & StrokeDraw && state->pen.style() != Qt::NoPen) {
+ q->strokePath(path, QPen(state->bgBrush.color(), state->pen.width()));
+ q->strokePath(path, state->pen);
+ }
+
+ q->setBackgroundMode(Qt::OpaqueMode);
+}
+
+static inline QBrush stretchGradientToUserSpace(const QBrush &brush, const QRectF &boundingRect)
+{
+ Q_ASSERT(brush.style() >= Qt::LinearGradientPattern
+ && brush.style() <= Qt::ConicalGradientPattern);
+
+ QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
+ boundingRect.x(), boundingRect.y());
+
+ QGradient g = *brush.gradient();
+ g.setCoordinateMode(QGradient::LogicalMode);
+
+ QBrush b(g);
+ b.setTransform(gradientToUser * b.transform());
+ return b;
+}
+
+void QPainterPrivate::drawStretchedGradient(const QPainterPath &path, DrawOperation op)
+{
+ Q_Q(QPainter);
+
+ const qreal sw = helper_device->width();
+ const qreal sh = helper_device->height();
+
+ bool changedPen = false;
+ bool changedBrush = false;
+ bool needsFill = false;
+
+ const QPen pen = state->pen;
+ const QBrush brush = state->brush;
+
+ const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
+ const QGradient::CoordinateMode brushMode = coordinateMode(brush);
+
+ QRectF boundingRect;
+
+ // Draw the xformed fill if the brush is a stretch gradient.
+ if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
+ if (brushMode == QGradient::StretchToDeviceMode) {
+ q->setPen(Qt::NoPen);
+ changedPen = pen.style() != Qt::NoPen;
+ q->scale(sw, sh);
+ updateState(state);
+
+ const qreal isw = 1.0 / sw;
+ const qreal ish = 1.0 / sh;
+ QTransform inv(isw, 0, 0, ish, 0, 0);
+ engine->drawPath(path * inv);
+ q->scale(isw, ish);
+ } else {
+ needsFill = true;
+
+ if (brushMode == QGradient::ObjectBoundingMode) {
+ Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
+ boundingRect = path.boundingRect();
+ q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
+ changedBrush = true;
+ }
+ }
+ }
+
+ if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
+ // Draw the xformed outline if the pen is a stretch gradient.
+ if (penMode == QGradient::StretchToDeviceMode) {
+ q->setPen(Qt::NoPen);
+ changedPen = true;
+
+ if (needsFill) {
+ updateState(state);
+ engine->drawPath(path);
+ }
+
+ q->scale(sw, sh);
+ q->setBrush(pen.brush());
+ changedBrush = true;
+ updateState(state);
+
+ QPainterPathStroker stroker;
+ stroker.setDashPattern(pen.style());
+ stroker.setWidth(pen.widthF());
+ stroker.setJoinStyle(pen.joinStyle());
+ stroker.setCapStyle(pen.capStyle());
+ stroker.setMiterLimit(pen.miterLimit());
+ QPainterPath stroke = stroker.createStroke(path);
+
+ const qreal isw = 1.0 / sw;
+ const qreal ish = 1.0 / sh;
+ QTransform inv(isw, 0, 0, ish, 0, 0);
+ engine->drawPath(stroke * inv);
+ q->scale(isw, ish);
+ } else {
+ if (!needsFill && brush.style() != Qt::NoBrush) {
+ q->setBrush(Qt::NoBrush);
+ changedBrush = true;
+ }
+
+ if (penMode == QGradient::ObjectBoundingMode) {
+ Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
+
+ // avoid computing the bounding rect twice
+ if (!needsFill || brushMode != QGradient::ObjectBoundingMode)
+ boundingRect = path.boundingRect();
+
+ QPen p = pen;
+ p.setBrush(stretchGradientToUserSpace(pen.brush(), boundingRect));
+ q->setPen(p);
+ changedPen = true;
+ } else if (changedPen) {
+ q->setPen(pen);
+ changedPen = false;
+ }
+
+ updateState(state);
+ engine->drawPath(path);
+ }
+ } else if (needsFill) {
+ if (pen.style() != Qt::NoPen) {
+ q->setPen(Qt::NoPen);
+ changedPen = true;
+ }
+
+ updateState(state);
+ engine->drawPath(path);
+ }
+
+ if (changedPen)
+ q->setPen(pen);
+ if (changedBrush)
+ q->setBrush(brush);
+}
+
+
+void QPainterPrivate::updateMatrix()
+{
+ state->matrix = state->WxF ? state->worldMatrix : QTransform();
+ if (state->VxF)
+ state->matrix *= viewTransform();
+
+ txinv = false; // no inverted matrix
+ if (!state->redirection_offset.isNull()) {
+ // We want to translate in dev space so we do the adding of the redirection
+ // offset manually.
+ if (state->matrix.isAffine()) {
+ state->matrix = QTransform(state->matrix.m11(), state->matrix.m12(),
+ state->matrix.m21(), state->matrix.m22(),
+ state->matrix.dx()-state->redirection_offset.x(),
+ state->matrix.dy()-state->redirection_offset.y());
+ } else {
+ QTransform temp;
+ temp.translate(-state->redirection_offset.x(), -state->redirection_offset.y());
+ state->matrix *= temp;
+ }
+ }
+ if (extended)
+ extended->transformChanged();
+ else
+ state->dirtyFlags |= QPaintEngine::DirtyTransform;
+
+// printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);
+// qDebug() << " --- using matrix" << state->matrix << redirection_offset;
+}
+
+/*! \internal */
+void QPainterPrivate::updateInvMatrix()
+{
+ Q_ASSERT(txinv == false);
+ txinv = true; // creating inverted matrix
+ QTransform m;
+
+ if (state->VxF)
+ m = viewTransform();
+
+ if (state->WxF) {
+ if (state->VxF)
+ m = state->worldMatrix * m;
+ else
+ m = state->worldMatrix;
+ }
+ invMatrix = m.inverted(); // invert matrix
+}
+
+void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
+{
+ bool alpha = false;
+ bool linearGradient = false;
+ bool radialGradient = false;
+ bool conicalGradient = false;
+ bool patternBrush = false;
+ bool xform = false;
+ bool complexXform = false;
+
+ bool skip = true;
+
+ // Pen and brush properties (we have to check both if one changes because the
+ // one that's unchanged can still be in a state which requires emulation)
+ if (s->state() & (QPaintEngine::DirtyPen | QPaintEngine::DirtyBrush | QPaintEngine::DirtyHints)) {
+ // Check Brush stroke emulation
+ if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
+ s->emulationSpecifier |= QPaintEngine::BrushStroke;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
+
+ skip = false;
+
+ QBrush penBrush = s->pen.brush();
+ Qt::BrushStyle brushStyle = s->brush.style();
+ Qt::BrushStyle penBrushStyle = penBrush.style();
+ alpha = (penBrushStyle != Qt::NoBrush
+ && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
+ && !penBrush.isOpaque())
+ || (brushStyle != Qt::NoBrush
+ && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
+ && !s->brush.isOpaque());
+ linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
+ (brushStyle == Qt::LinearGradientPattern));
+ radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
+ (brushStyle == Qt::RadialGradientPattern));
+ conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
+ (brushStyle == Qt::ConicalGradientPattern));
+ patternBrush = (((penBrushStyle > Qt::SolidPattern
+ && penBrushStyle < Qt::LinearGradientPattern)
+ || penBrushStyle == Qt::TexturePattern) ||
+ ((brushStyle > Qt::SolidPattern
+ && brushStyle < Qt::LinearGradientPattern)
+ || brushStyle == Qt::TexturePattern));
+
+ bool penTextureAlpha = false;
+ if (penBrush.style() == Qt::TexturePattern)
+ penTextureAlpha = qHasPixmapTexture(penBrush)
+ ? penBrush.texture().hasAlpha()
+ : penBrush.textureImage().hasAlphaChannel();
+ bool brushTextureAlpha = false;
+ if (s->brush.style() == Qt::TexturePattern)
+ brushTextureAlpha = qHasPixmapTexture(s->brush)
+ ? s->brush.texture().hasAlpha()
+ : s->brush.textureImage().hasAlphaChannel();
+ if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
+ || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
+ && !engine->hasFeature(QPaintEngine::MaskedBrush))
+ s->emulationSpecifier |= QPaintEngine::MaskedBrush;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
+ }
+
+ if (s->state() & (QPaintEngine::DirtyHints
+ | QPaintEngine::DirtyOpacity
+ | QPaintEngine::DirtyBackgroundMode)) {
+ skip = false;
+ }
+
+ if (skip)
+ return;
+
+#if 0
+ qDebug("QPainterPrivate::updateEmulationSpecifier, state=%p\n"
+ " - alpha: %d\n"
+ " - linearGradient: %d\n"
+ " - radialGradient: %d\n"
+ " - conicalGradient: %d\n"
+ " - patternBrush: %d\n"
+ " - hints: %x\n"
+ " - xform: %d\n",
+ s,
+ alpha,
+ linearGradient,
+ radialGradient,
+ conicalGradient,
+ patternBrush,
+ uint(s->renderHints),
+ xform);
+#endif
+
+ // XForm properties
+ if (s->state() & QPaintEngine::DirtyTransform) {
+ xform = !s->matrix.isIdentity();
+ complexXform = !s->matrix.isAffine();
+ } else if (s->matrix.type() >= QTransform::TxTranslate) {
+ xform = true;
+ complexXform = !s->matrix.isAffine();
+ }
+
+ const bool brushXform = (!s->brush.transform().type() == QTransform::TxNone);
+ const bool penXform = (!s->pen.brush().transform().type() == QTransform::TxNone);
+
+ const bool patternXform = patternBrush && (xform || brushXform || penXform);
+
+ // Check alphablending
+ if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
+ s->emulationSpecifier |= QPaintEngine::AlphaBlend;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
+
+ // Linear gradient emulation
+ if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
+ s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
+
+ // Radial gradient emulation
+ if (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill))
+ s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
+
+ // Conical gradient emulation
+ if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
+ s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
+
+ // Pattern brushes
+ if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
+ s->emulationSpecifier |= QPaintEngine::PatternBrush;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
+
+ // Pattern XForms
+ if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
+ s->emulationSpecifier |= QPaintEngine::PatternTransform;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
+
+ // Primitive XForms
+ if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
+ s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
+
+ // Perspective XForms
+ if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
+ s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
+
+ // Constant opacity
+ if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
+ s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
+
+ bool gradientStretch = false;
+ bool objectBoundingMode = false;
+ if (linearGradient || conicalGradient || radialGradient) {
+ QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
+ QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
+
+ gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
+ gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
+
+ objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode);
+ objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode);
+ }
+ if (gradientStretch)
+ s->emulationSpecifier |= QGradient_StretchToDevice;
+ else
+ s->emulationSpecifier &= ~QGradient_StretchToDevice;
+
+ if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
+ s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
+
+ // Opaque backgrounds...
+ if (s->bgMode == Qt::OpaqueMode &&
+ (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
+ s->emulationSpecifier |= QPaintEngine_OpaqueBackground;
+ else
+ s->emulationSpecifier &= ~QPaintEngine_OpaqueBackground;
+
+#if 0
+ //won't be correct either way because the device can already have
+ // something rendered to it in which case subsequent emulation
+ // on a fully transparent qimage and then blitting the results
+ // won't produce correct results
+ // Blend modes
+ if (state->composition_mode > QPainter::CompositionMode_Xor &&
+ !engine->hasFeature(QPaintEngine::BlendModes))
+ s->emulationSpecifier |= QPaintEngine::BlendModes;
+ else
+ s->emulationSpecifier &= ~QPaintEngine::BlendModes;
+#endif
+}
+
+void QPainterPrivate::updateStateImpl(QPainterState *newState)
+{
+ // ### we might have to call QPainter::begin() here...
+ if (!engine->state) {
+ engine->state = newState;
+ engine->setDirty(QPaintEngine::AllDirty);
+ }
+
+ if (engine->state->painter() != newState->painter)
+ // ### this could break with clip regions vs paths.
+ engine->setDirty(QPaintEngine::AllDirty);
+
+ // Upon restore, revert all changes since last save
+ else if (engine->state != newState)
+ newState->dirtyFlags |= QPaintEngine::DirtyFlags(static_cast<QPainterState *>(engine->state)->changeFlags);
+
+ // We need to store all changes made so that restore can deal with them
+ else
+ newState->changeFlags |= newState->dirtyFlags;
+
+ updateEmulationSpecifier(newState);
+
+ // Unset potential dirty background mode
+ newState->dirtyFlags &= ~(QPaintEngine::DirtyBackgroundMode
+ | QPaintEngine::DirtyBackground);
+
+ engine->state = newState;
+ engine->updateState(*newState);
+ engine->clearDirty(QPaintEngine::AllDirty);
+
+}
+
+void QPainterPrivate::updateState(QPainterState *newState)
+{
+
+ if (!newState) {
+ engine->state = newState;
+
+ } else if (newState->state() || engine->state!=newState) {
+ bool setNonCosmeticPen = (newState->renderHints & QPainter::NonCosmeticDefaultPen)
+ && newState->pen.widthF() == 0;
+ if (setNonCosmeticPen) {
+ // Override the default pen's cosmetic state if the
+ // NonCosmeticDefaultPen render hint is used.
+ QPen oldPen = newState->pen;
+ newState->pen.setWidth(1);
+ newState->pen.setCosmetic(false);
+ newState->dirtyFlags |= QPaintEngine::DirtyPen;
+
+ updateStateImpl(newState);
+
+ // Restore the state pen back to its default to preserve visible
+ // state.
+ newState->pen = oldPen;
+ } else {
+ updateStateImpl(newState);
+ }
+ }
+}
+
+
+/*!
+ \class QPainter
+ \brief The QPainter class performs low-level painting on widgets and
+ other paint devices.
+
+ \ingroup multimedia
+ \mainclass
+ \reentrant
+
+ QPainter provides highly optimized functions to do most of the
+ drawing GUI programs require. It can draw everything from simple
+ lines to complex shapes like pies and chords. It can also draw
+ aligned text and pixmaps. Normally, it draws in a "natural"
+ coordinate system, but it can also do view and world
+ transformation. QPainter can operate on any object that inherits
+ the QPaintDevice class.
+
+ The common use of QPainter is inside a widget's paint event:
+ Construct and customize (e.g. set the pen or the brush) the
+ painter. Then draw. Remember to destroy the QPainter object after
+ drawing. For example:
+
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 0
+
+ The core functionality of QPainter is drawing, but the class also
+ provide several functions that allows you to customize QPainter's
+ settings and its rendering quality, and others that enable
+ clipping. In addition you can control how different shapes are
+ merged together by specifying the painter's composition mode.
+
+ The isActive() function indicates whether the painter is active. A
+ painter is activated by the begin() function and the constructor
+ that takes a QPaintDevice argument. The end() function, and the
+ destructor, deactivates it.
+
+ Together with the QPaintDevice and QPaintEngine classes, QPainter
+ form the basis for Qt's paint system. QPainter is the class used
+ to perform drawing operations. QPaintDevice represents a device
+ that can be painted on using a QPainter. QPaintEngine provides the
+ interface that the painter uses to draw onto different types of
+ 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.
+
+ Sometimes it is desirable to make someone else paint on an unusual
+ QPaintDevice. QPainter supports a static function to do this,
+ setRedirected().
+
+ \warning When the paintdevice is a widget, QPainter can only be
+ used inside a paintEvent() function or in a function called by
+ paintEvent(); that is unless the Qt::WA_PaintOutsidePaintEvent
+ widget attribute is set. On Mac OS X and Windows, you can only
+ paint in a paintEvent() function regardless of this attribute's
+ setting.
+
+ \tableofcontents
+
+ \section1 Settings
+
+ There are several settings that you can customize to make QPainter
+ draw according to your preferences:
+
+ \list
+
+ \o font() is the font used for drawing text. If the painter
+ isActive(), you can retrieve information about the currently set
+ font, and its metrics, using the fontInfo() and fontMetrics()
+ functions respectively.
+
+ \o brush() defines the color or pattern that is used for filling
+ shapes.
+
+ \o pen() defines the color or stipple that is used for drawing
+ lines or boundaries.
+
+ \o backgroundMode() defines whether there is a background() or
+ not, i.e it is either Qt::OpaqueMode or Qt::TransparentMode.
+
+ \o background() only applies when backgroundMode() is \l
+ Qt::OpaqueMode and pen() is a stipple. In that case, it
+ describes the color of the background pixels in the stipple.
+
+ \o brushOrigin() defines the origin of the tiled brushes, normally
+ the origin of widget's background.
+
+ \o viewport(), window(), worldMatrix() make up the painter's coordinate
+ transformation system. For more information, see the \l
+ {Coordinate Transformations} section and the \l {The Coordinate
+ System} documentation.
+
+ \o hasClipping() tells whether the painter clips at all. (The paint
+ device clips, too.) If the painter clips, it clips to clipRegion().
+
+ \o layoutDirection() defines the layout direction used by the
+ painter when drawing text.
+
+ \o matrixEnabled() tells whether world transformation is enabled.
+
+ \o viewTransformEnabled() tells whether view transformation is
+ enabled.
+
+ \endlist
+
+ Note that some of these settings mirror settings in some paint
+ devices, e.g. QWidget::font(). The QPainter::begin() function (or
+ equivalently the QPainter constructor) copies these attributes
+ from the paint device.
+
+ You can at any time save the QPainter's state by calling the
+ save() function which saves all the available settings on an
+ internal stack. The restore() function pops them back.
+
+ \section1 Drawing
+
+ QPainter provides functions to draw most primitives: drawPoint(),
+ drawPoints(), drawLine(), drawRect(), drawRoundedRect(),
+ drawEllipse(), drawArc(), drawPie(), drawChord(), drawPolyline(),
+ drawPolygon(), drawConvexPolygon() and drawCubicBezier(). The two
+ convenience functions, drawRects() and drawLines(), draw the given
+ number of rectangles or lines in the given array of \l
+ {QRect}{QRects} or \l {QLine}{QLines} using the current pen and
+ brush.
+
+ The QPainter class also provides the fillRect() function which
+ fills the given QRect, with the given QBrush, and the eraseRect()
+ function that erases the area inside the given rectangle.
+
+ All of these functions have both integer and floating point
+ versions.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-basicdrawing.png
+ \o
+ \bold {Basic Drawing Example}
+
+ The \l {painting/basicdrawing}{Basic Drawing} example shows how to
+ display basic graphics primitives in a variety of styles using the
+ QPainter class.
+
+ \endtable
+
+ If you need to draw a complex shape, especially if you need to do
+ so repeatedly, consider creating a QPainterPath and drawing it
+ using drawPath().
+
+ \table 100%
+ \row
+ \o
+ \bold {Painter Paths example}
+
+ The QPainterPath class provides a container for painting
+ operations, enabling graphical shapes to be constructed and
+ reused.
+
+ The \l {painting/painterpaths}{Painter Paths} example shows how
+ painter paths can be used to build complex shapes for rendering.
+
+ \o \inlineimage qpainter-painterpaths.png
+ \endtable
+
+ QPainter also provides the fillPath() function which fills the
+ given QPainterPath with the given QBrush, and the strokePath()
+ function that draws the outline of the given path (i.e. strokes
+ the path).
+
+ See also the \l {demos/deform}{Vector Deformation} demo which
+ shows how to use advanced vector techniques to draw text using a
+ QPainterPath, the \l {demos/gradients}{Gradients} demo which shows
+ the different types of gradients that are available in Qt, and the \l
+ {demos/pathstroke}{Path Stroking} demo which shows Qt's built-in
+ dash patterns and shows how custom patterns can be used to extend
+ the range of available patterns.
+
+ \table
+ \row
+ \o \inlineimage qpainter-vectordeformation.png
+ \o \inlineimage qpainter-gradients.png
+ \o \inlineimage qpainter-pathstroking.png
+ \header
+ \o \l {demos/deform}{Vector Deformation}
+ \o \l {demos/gradients}{Gradients}
+ \o \l {demos/pathstroke}{Path Stroking}
+ \endtable
+
+
+ There are functions to draw pixmaps/images, namely drawPixmap(),
+ drawImage() and drawTiledPixmap(). Both drawPixmap() and drawImage()
+ produce the same result, except that drawPixmap() is faster
+ on-screen while drawImage() may be faster on a QPrinter or other
+ devices.
+
+ Text drawing is done using drawText(). When you need
+ fine-grained positioning, boundingRect() tells you where a given
+ drawText() command will draw.
+
+ There is a drawPicture() function that draws the contents of an
+ entire QPicture. The drawPicture() function is the only function
+ that disregards all the painter's settings as QPicture has its own
+ settings.
+
+ \section1 Rendering Quality
+
+ To get the optimal rendering result using QPainter, you should use
+ the platform independent QImage as paint device; i.e. using QImage
+ will ensure that the result has an identical pixel representation
+ on any platform.
+
+ The QPainter class also provides a means of controlling the
+ rendering quality through its RenderHint enum and the support for
+ floating point precision: All the functions for drawing primitives
+ has a floating point version. These are often used in combination
+ with the \l {RenderHint}{QPainter::Antialiasing} render hint.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-concentriccircles.png
+ \o
+ \bold {Concentric Circles Example}
+
+ The \l {painting/concentriccircles}{Concentric Circles} example
+ shows the improved rendering quality that can be obtained using
+ floating point precision and anti-aliasing when drawing custom
+ widgets.
+
+ The application's main window displays several widgets which are
+ drawn using the various combinations of precision and
+ anti-aliasing.
+
+ \endtable
+
+ The RenderHint enum specifies flags to QPainter that may or may
+ not be respected by any given engine. \l
+ {RenderHint}{QPainter::Antialiasing} indicates that the engine
+ should antialias edges of primitives if possible, \l
+ {RenderHint}{QPainter::TextAntialiasing} indicates that the engine
+ should antialias text if possible, and the \l
+ {RenderHint}{QPainter::SmoothPixmapTransform} indicates that the
+ engine should use a smooth pixmap transformation algorithm.
+ \l {RenderHint}{HighQualityAntialiasing} is an OpenGL-specific rendering hint
+ indicating that the engine should use fragment programs and offscreen
+ rendering for antialiasing.
+
+ The renderHints() function returns a flag that specifies the
+ rendering hints that are set for this painter. Use the
+ setRenderHint() function to set or clear the currently set
+ RenderHints.
+
+ \section1 Coordinate Transformations
+
+ Normally, the QPainter operates on the device's own coordinate
+ system (usually pixels), but QPainter has good support for
+ coordinate transformations.
+
+ \table
+ \row
+ \o \inlineimage qpainter-clock.png
+ \o \inlineimage qpainter-rotation.png
+ \o \inlineimage qpainter-scale.png
+ \o \inlineimage qpainter-translation.png
+ \header
+ \o nop \o rotate() \o scale() \o translate()
+ \endtable
+
+ The most commonly used transformations are scaling, rotation,
+ translation and shearing. Use the scale() function to scale the
+ coordinate system by a given offset, the rotate() function to
+ rotate it clockwise and translate() to translate it (i.e. adding a
+ given offset to the points). You can also twist the coordinate
+ system around the origin using the shear() function. See the \l
+ {demos/affine}{Affine Transformations} demo for a visualization of
+ a sheared coordinate system.
+
+ See also the \l {painting/transformations}{Transformations}
+ example which shows how transformations influence the way that
+ QPainter renders graphics primitives. In particular it shows how
+ the order of transformations affects the result.
+
+ \table 100%
+ \row
+ \o
+ \bold {Affine Transformations Demo}
+
+ The \l {demos/affine}{Affine Transformations} demo show Qt's
+ ability to perform affine transformations on painting
+ operations. The demo also allows the user to experiment with the
+ transformation operations and see the results immediately.
+
+ \o \inlineimage qpainter-affinetransformations.png
+ \endtable
+
+ All the tranformation operations operate on the transformation
+ worldMatrix(). 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 QMatrix documentation.
+
+ The setWorldMatrix() function can replace or add to the currently
+ set worldMatrix(). The resetMatrix() function resets any
+ transformations that were made using translate(), scale(),
+ shear(), rotate(), setWorldMatrix(), setViewport() and setWindow()
+ functions. The deviceMatrix() returns the matrix that transforms
+ from logical coordinates to device coordinates of the platform
+ dependent paint device. The latter function is only needed when
+ using platform painting commands on the platform dependent handle,
+ and the platform does not do transformations nativly.
+
+ When drawing with QPainter, we specify points using logical
+ coordinates which then are converted into the physical coordinates
+ of the paint device. The mapping of the logical coordinates to the
+ physical coordinates are handled by QPainter's combinedMatrix(), a
+ combination of viewport() and window() and worldMatrix(). The
+ viewport() represents the physical coordinates specifying an
+ arbitrary rectangle, the window() describes the same rectangle in
+ logical coordinates, and the worldMatrix() is identical with the
+ transformation matrix.
+
+ See also \l {The Coordinate System} documentation.
+
+ \section1 Clipping
+
+ QPainter can clip any drawing operation to a rectangle, a region,
+ or a vector path. The current clip is available using the
+ functions clipRegion() and clipPath(). Whether paths or regions are
+ preferred (faster) depends on the underlying paintEngine(). For
+ example, the QImage paint engine prefers paths while the X11 paint
+ engine prefers regions. Setting a clip is done in the painters
+ logical coordinates.
+
+ After QPainter's clipping, the paint device may also clip. For
+ example, most widgets clip away the pixels used by child widgets,
+ and most printers clip away an area near the edges of the paper.
+ This additional clipping is not reflected by the return value of
+ clipRegion() or hasClipping().
+
+ \section1 Composition Modes
+ \target Composition Modes
+
+ QPainter provides the CompositionMode enum which defines the
+ Porter-Duff rules for digital image compositing; it describes a
+ model for combining the pixels in one image, the source, with the
+ pixels in another image, the destination.
+
+ The two most common forms of composition are \l
+ {QPainter::CompositionMode}{Source} and \l
+ {QPainter::CompositionMode}{SourceOver}. \l
+ {QPainter::CompositionMode}{Source} is used to draw opaque objects
+ onto a paint device. In this mode, each pixel in the source
+ replaces the corresponding pixel in the destination. In \l
+ {QPainter::CompositionMode}{SourceOver} composition mode, the
+ source object is transparent and is drawn on top of the
+ destination.
+
+ Note that composition transformation operates pixelwise. For that
+ reason, there is a difference between using the grahic primitive
+ itself and its bounding rectangle: The bounding rect contains
+ pixels with alpha == 0 (i.e the pixels surrounding the
+ primitive). These pixels will overwrite the other image's pixels,
+ affectively clearing those, while the primitive only overwrites
+ its own area.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-compositiondemo.png
+
+ \o
+ \bold {Composition Modes Demo}
+
+ The \l {demos/composition}{Composition Modes} demo, available in
+ Qt's demo directory, allows you to experiment with the various
+ composition modes and see the results immediately.
+
+ \endtable
+
+ \section1 Limitations
+ \target Limitations
+
+ If you are using coordinates with Qt's raster-based paint engine, it is
+ important to note that, while coordinates greater than +/- 2\sup 15 can
+ be used, any painting performed with coordinates outside this range is not
+ guaranteed to be shown; the drawing may be clipped. This is due to the
+ use of \c{short int} in the implementation.
+
+ The outlines generated by Qt's stroker are only an approximation when dealing
+ with curved shapes. It is in most cases impossible to represent the outline of
+ a bezier curve segment using another bezier curve segment, and so Qt approximates
+ the curve outlines by using several smaller curves. For performance reasons there
+ is a limit to how many curves Qt uses for these outlines, and thus when using
+ large pen widths or scales the outline error increases. To generate outlines with
+ smaller errors it is possible to use the QPainterPathStroker class, which has the
+ setCurveThreshold member function which let's the user specify the error tolerance.
+ Another workaround is to convert the paths to polygons first and then draw the
+ polygons instead.
+
+ \sa QPaintDevice, QPaintEngine, {QtSvg Module}, {Basic Drawing Example}
+*/
+
+/*!
+ \enum QPainter::RenderHint
+
+ Renderhints are used to specify flags to QPainter that may or
+ may not be respected by any given engine.
+
+ \value Antialiasing Indicates that the engine should antialias
+ edges of primitives if possible.
+
+ \value TextAntialiasing Indicates that the engine should antialias
+ text if possible. To forcibly disable antialiasing for text, do not
+ use this hint. Instead, set QFont::NoAntialias on your font's style
+ strategy.
+
+ \value SmoothPixmapTransform Indicates that the engine should use
+ a smooth pixmap transformation algorithm (such as bilinear) rather
+ than nearest neighbor.
+
+ \value HighQualityAntialiasing An OpenGL-specific rendering hint
+ indicating that the engine should use fragment programs and offscreen
+ rendering for antialiasing.
+
+ \value NonCosmeticDefaultPen The engine should interpret pens with a width
+ of 0 (which otherwise enables QPen::isCosmetic()) as being a non-cosmetic
+ pen with a width of 1.
+
+ \sa renderHints(), setRenderHint(), {QPainter#Rendering
+ Quality}{Rendering Quality}, {Concentric Circles Example}
+
+*/
+
+/*!
+ Constructs a painter.
+
+ \sa begin(), end()
+*/
+
+QPainter::QPainter()
+{
+ d_ptr = new QPainterPrivate(this);
+}
+
+/*!
+ \fn QPainter::QPainter(QPaintDevice *device)
+
+ Constructs a painter that begins painting the paint \a device
+ immediately.
+
+ This constructor is convenient for short-lived painters, e.g. in a
+ QWidget::paintEvent() and should be used only once. The
+ constructor calls begin() for you and the QPainter destructor
+ automatically calls end().
+
+ Here's an example using begin() and end():
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 1
+
+ The same example using this constructor:
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 2
+
+ Since the constructor cannot provide feedback when the initialization
+ of the painter failed you should rather use begin() and end() to paint
+ on external devices, e.g. printers.
+
+ \sa begin(), end()
+*/
+
+QPainter::QPainter(QPaintDevice *pd)
+ : d_ptr(0)
+{
+ Q_ASSERT(pd != 0);
+ if (!QPainterPrivate::attachPainterPrivate(this, pd)) {
+ d_ptr = new QPainterPrivate(this);
+ begin(pd);
+ }
+ Q_ASSERT(d_ptr);
+}
+
+/*!
+ Destroys the painter.
+*/
+QPainter::~QPainter()
+{
+ d_ptr->inDestructor = true;
+ if (isActive())
+ end();
+ else if (d_ptr->refcount > 1)
+ d_ptr->detachPainterPrivate(this);
+
+ if (d_ptr) {
+ // Make sure we haven't messed things up.
+ Q_ASSERT(d_ptr->inDestructor);
+ d_ptr->inDestructor = false;
+ Q_ASSERT(d_ptr->refcount == 1);
+ if (d_ptr->d_ptrs)
+ free(d_ptr->d_ptrs);
+ delete d_ptr;
+ }
+}
+
+/*!
+ Returns the paint device on which this painter is currently
+ painting, or 0 if the painter is not active.
+
+ \sa isActive()
+*/
+
+QPaintDevice *QPainter::device() const
+{
+ Q_D(const QPainter);
+ if (isActive() && d->engine->d_func()->currentClipWidget)
+ return d->engine->d_func()->currentClipWidget;
+ return d->original_device;
+}
+
+/*!
+ Returns true if begin() has been called and end() has not yet been
+ called; otherwise returns false.
+
+ \sa begin(), QPaintDevice::paintingActive()
+*/
+
+bool QPainter::isActive() const
+{
+ Q_D(const QPainter);
+ return d->engine;
+}
+
+/*!
+ Initializes the painters pen, background and font to the same as
+ the given \a widget. Call this function after begin() while the
+ painter is active.
+
+ \sa begin(), {QPainter#Settings}{Settings}
+*/
+void QPainter::initFrom(const QWidget *widget)
+{
+ Q_ASSERT_X(widget, "QPainter::initFrom(const QWidget *widget)", "Widget cannot be 0");
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::initFrom: Painter not active, aborted");
+ return;
+ }
+
+ const QPalette &pal = widget->palette();
+ d->state->pen = QPen(pal.brush(widget->foregroundRole()), 0);
+ d->state->bgBrush = pal.brush(widget->backgroundRole());
+ d->state->deviceFont = QFont(widget->font(), const_cast<QWidget*> (widget));
+ d->state->font = d->state->deviceFont;
+ if (d->engine) {
+ d->engine->setDirty(QPaintEngine::DirtyPen);
+ d->engine->setDirty(QPaintEngine::DirtyBrush);
+ d->engine->setDirty(QPaintEngine::DirtyFont);
+ }
+ d->state->layoutDirection = widget->layoutDirection();
+}
+
+
+/*!
+ Saves the current painter state (pushes the state onto a stack). A
+ save() must be followed by a corresponding restore(); the end()
+ function unwinds the stack.
+
+ \sa restore()
+*/
+
+void QPainter::save()
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::save()\n");
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::save: Painter not active");
+ return;
+ }
+
+ if (d->extended) {
+ d->state = d->extended->createState(d->states.back());
+ d->extended->setState(d->state);
+ } else {
+ d->updateState(d->state);
+ d->state = new QPainterState(d->states.back());
+ d->engine->state = d->state;
+ }
+ d->states.push_back(d->state);
+}
+
+/*!
+ Restores the current painter state (pops a saved state off the
+ stack).
+
+ \sa save()
+*/
+
+void QPainter::restore()
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::restore()\n");
+#endif
+ Q_D(QPainter);
+ if (d->states.size()<=1) {
+ qWarning("QPainter::restore: Unbalanced save/restore");
+ return;
+ } else if (!d->engine) {
+ qWarning("QPainter::restore: Painter not active");
+ return;
+ }
+
+ QPainterState *tmp = d->state;
+ d->states.pop_back();
+ d->state = d->states.back();
+ d->txinv = false;
+
+ if (d->extended) {
+ d->checkEmulation();
+ d->extended->setState(d->state);
+ delete tmp;
+ return;
+ }
+
+ // trigger clip update if the clip path/region has changed since
+ // last save
+ if (!d->state->clipInfo.isEmpty()
+ && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
+ // reuse the tmp state to avoid any extra allocs...
+ tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
+ tmp->clipOperation = Qt::NoClip;
+ tmp->clipPath = QPainterPath();
+ d->engine->updateState(*tmp);
+ // replay the list of clip states,
+ for (int i=0; i<d->state->clipInfo.size(); ++i) {
+ const QPainterClipInfo &info = d->state->clipInfo.at(i);
+ tmp->matrix.setMatrix(info.matrix.m11(), info.matrix.m12(), info.matrix.m13(),
+ info.matrix.m21(), info.matrix.m22(), info.matrix.m23(),
+ info.matrix.dx() - d->state->redirection_offset.x(),
+ info.matrix.dy() - d->state->redirection_offset.y(), info.matrix.m33());
+ tmp->clipOperation = info.operation;
+ if (info.clipType == QPainterClipInfo::RectClip) {
+ tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
+ tmp->clipRegion = info.rect;
+ } else if (info.clipType == QPainterClipInfo::RegionClip) {
+ tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
+ tmp->clipRegion = info.region;
+ } else { // clipType == QPainterClipInfo::PathClip
+ tmp->dirtyFlags = QPaintEngine::DirtyClipPath | QPaintEngine::DirtyTransform;
+ tmp->clipPath = info.path;
+ }
+ d->engine->updateState(*tmp);
+ }
+
+
+ //Since we've updated the clip region anyway, pretend that the clip path hasn't changed:
+ d->state->dirtyFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
+ tmp->changeFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
+ tmp->changeFlags |= QPaintEngine::DirtyTransform;
+ }
+
+ d->updateState(d->state);
+ delete tmp;
+}
+
+
+/*!
+
+ \fn bool QPainter::begin(QPaintDevice *device)
+
+ Begins painting the paint \a device and returns true if
+ successful; otherwise returns false.
+
+ Notice that all painter settings (setPen(), setBrush() etc.) are reset
+ to default values when begin() is called.
+
+ The errors that can occur are serious problems, such as these:
+
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 3
+
+ Note that most of the time, you can use one of the constructors
+ instead of begin(), and that end() is automatically done at
+ destruction.
+
+ \warning A paint device can only be painted by one painter at a
+ time.
+
+ \sa end(), QPainter()
+*/
+
+bool QPainter::begin(QPaintDevice *pd)
+{
+ Q_ASSERT(pd);
+
+ if (pd->painters > 0) {
+ qWarning("QPainter::begin: A paint device can only be painted by one painter at a time.");
+ return false;
+ }
+
+ if (d_ptr->engine) {
+ qWarning("QPainter::begin: Painter already active");
+ return false;
+ }
+
+ if (QPainterPrivate::attachPainterPrivate(this, pd))
+ return true;
+
+ Q_D(QPainter);
+
+ d->helper_device = pd;
+ d->original_device = pd;
+ QPaintDevice *rpd = 0;
+
+ QPoint redirectionOffset;
+ // We know for sure that redirection is broken when the widget is inside
+ // its paint event, so it's safe to use our hard-coded redirection. However,
+ // there IS one particular case we still need to support, and that's
+ // when people call QPainter::setRedirected in the widget's paint event right
+ // before any painter is created (or QPainter::begin is called). In that
+ // particular case our hard-coded redirection is restored and the redirection
+ // is retrieved from QPainter::redirected (as before).
+ if (pd->devType() == QInternal::Widget)
+ rpd = static_cast<QWidget *>(pd)->d_func()->redirected(&redirectionOffset);
+
+ if (!rpd)
+ rpd = redirected(pd, &redirectionOffset);
+
+ if (rpd)
+ pd = rpd;
+
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
+#endif
+
+
+ d->device = pd;
+ if (pd->devType() == QInternal::Pixmap)
+ static_cast<QPixmap *>(pd)->detach();
+ else if (pd->devType() == QInternal::Image)
+ static_cast<QImage *>(pd)->detach();
+
+ d->engine = pd->paintEngine();
+ d->extended = d->engine && d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine) : 0;
+ if (d->emulationEngine)
+ d->emulationEngine->real_engine = d->extended;
+
+ // Setup new state...
+ Q_ASSERT(!d->state);
+ d->state = d->extended ? d->extended->createState(0) : new QPainterState;
+ d->state->painter = this;
+ d->states.push_back(d->state);
+
+ d->state->redirection_offset = redirectionOffset;
+ d->state->brushOrigin = QPointF();
+
+ if (!d->engine) {
+ qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
+ return true;
+ }
+
+ // Slip a painter state into the engine before we do any other operations
+ if (d->extended)
+ d->extended->setState(d->state);
+ else
+ d->engine->state = d->state;
+
+ switch (pd->devType()) {
+ case QInternal::Widget:
+ {
+ const QWidget *widget = static_cast<const QWidget *>(pd);
+ Q_ASSERT(widget);
+
+ const bool paintOutsidePaintEvent = widget->testAttribute(Qt::WA_PaintOutsidePaintEvent);
+ const bool inPaintEvent = widget->testAttribute(Qt::WA_WState_InPaintEvent);
+ if(!d->engine->hasFeature(QPaintEngine::PaintOutsidePaintEvent)
+ && !paintOutsidePaintEvent && !inPaintEvent) {
+ qWarning("QPainter::begin: Widget painting can only begin as a "
+ "result of a paintEvent");
+ d->engine = 0;
+ d->device = 0;
+ return false;
+ }
+
+ // Adjust offset for alien widgets painting outside the paint event.
+ if (!inPaintEvent && paintOutsidePaintEvent && !widget->internalWinId()
+ && widget->testAttribute(Qt::WA_WState_Created)) {
+ d->state->redirection_offset -= widget->mapTo(widget->nativeParentWidget(), QPoint());
+ }
+ break;
+ }
+ case QInternal::Pixmap:
+ {
+ QPixmap *pm = static_cast<QPixmap *>(pd);
+ Q_ASSERT(pm);
+ if (pm->isNull()) {
+ qWarning("QPainter::begin: Cannot paint on a null pixmap");
+ d->engine = 0;
+ d->device = 0;
+ return false;
+ }
+
+ if (pm->depth() == 1) {
+ d->state->pen = QPen(Qt::color1);
+ d->state->brush = QBrush(Qt::color0);
+ }
+ break;
+ }
+ case QInternal::Image:
+ {
+ QImage *img = static_cast<QImage *>(pd);
+ Q_ASSERT(img);
+ if (img->isNull()) {
+ qWarning("QPainter::begin: Cannot paint on a null image");
+ d->engine = 0;
+ d->device = 0;
+ return false;
+ }
+ if (img->depth() == 1) {
+ d->state->pen = QPen(Qt::color1);
+ d->state->brush = QBrush(Qt::color0);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (d->state->ww == 0) // For compat with 3.x painter defaults
+ d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
+
+ d->engine->setPaintDevice(pd);
+
+ bool begun = d->engine->begin(pd);
+ if (!begun) {
+ qWarning("QPainter::begin(): Returned false");
+ if (d->engine->isActive()) {
+ end();
+ } else {
+ d->states.clear();
+ delete d->state;
+ d->state = 0;
+ }
+ d->engine = 0;
+ d->device = 0;
+ return false;
+ } else {
+ d->engine->setActive(begun);
+ }
+
+ // Copy painter properties from original paint device,
+ // required for QPixmap::grabWidget()
+ if (d->original_device->devType() == QInternal::Widget) {
+ QWidget *widget = static_cast<QWidget *>(d->original_device);
+ initFrom(widget);
+ } else {
+ d->state->layoutDirection = QApplication::layoutDirection();
+ // make sure we have a font compatible with the paintdevice
+ d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
+ }
+
+ QRect systemRect = d->engine->systemRect();
+ if (!systemRect.isEmpty()) {
+ d->state->ww = d->state->vw = systemRect.width();
+ d->state->wh = d->state->vh = systemRect.height();
+ } else {
+ d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
+ d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
+ }
+
+ d->state->redirection_offset += d->engine->coordinateOffset();
+
+ Q_ASSERT(d->engine->isActive());
+
+ if (!d->state->redirection_offset.isNull())
+ d->updateMatrix();
+
+ Q_ASSERT(d->engine->isActive());
+ d->state->renderHints = QPainter::TextAntialiasing;
+ ++d->device->painters;
+
+ d->state->emulationSpecifier = 0;
+
+ return true;
+}
+
+/*!
+ Ends painting. Any resources used while painting are released. You
+ don't normally need to call this since it is called by the
+ destructor.
+
+ Returns true if the painter is no longer active; otherwise returns false.
+
+ \sa begin(), isActive()
+*/
+
+bool QPainter::end()
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::end()\n");
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::end: Painter not active, aborted");
+ d->states.clear();
+ delete d->state;
+ d->state = 0;
+ d->device = 0;
+ return false;
+ }
+
+ if (d->refcount > 1) {
+ d->detachPainterPrivate(this);
+ return true;
+ }
+
+ if (d->states.size() > 1) {
+ qWarning("QPainter::end: Painter ended with %d saved states",
+ d->states.size());
+ }
+
+ bool ended = true;
+
+ if (d->engine->isActive()) {
+ ended = d->engine->end();
+ d->updateState(0);
+
+ --d->device->painters;
+ if (d->device->painters == 0) {
+ d->engine->setPaintDevice(0);
+ d->engine->setActive(false);
+ }
+ }
+
+ if (d->engine->autoDestruct()) {
+ delete d->engine;
+ }
+
+ d->engine = 0;
+
+ if (d->emulationEngine) {
+ delete d->emulationEngine;
+ d->emulationEngine = 0;
+ }
+
+ if (d->extended) {
+ d->extended = 0;
+ }
+
+ d->states.clear();
+ delete d->state;
+ d->state = 0;
+
+ d->device = 0;
+ return ended;
+}
+
+
+/*!
+ Returns the paint engine that the painter is currently operating
+ on if the painter is active; otherwise 0.
+
+ \sa isActive()
+*/
+QPaintEngine *QPainter::paintEngine() const
+{
+ Q_D(const QPainter);
+ return d->engine;
+}
+
+
+/*!
+ Returns the font metrics for the painter if the painter is
+ active. Otherwise, the return value is undefined.
+
+ \sa font(), isActive(), {QPainter#Settings}{Settings}
+*/
+
+QFontMetrics QPainter::fontMetrics() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::fontMetrics: Painter not active");
+ return QFontMetrics(QFont());
+ }
+ return QFontMetrics(d->state->font);
+}
+
+
+/*!
+ Returns the font info for the painter if the painter is
+ active. Otherwise, the return value is undefined.
+
+ \sa font(), isActive(), {QPainter#Settings}{Settings}
+*/
+
+QFontInfo QPainter::fontInfo() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::fontInfo: Painter not active");
+ return QFontInfo(QFont());
+ }
+ return QFontInfo(d->state->font);
+}
+
+/*!
+ \since 4.2
+
+ Returns the opacity of the painter. The default value is
+ 1.
+*/
+
+qreal QPainter::opacity() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::opacity: Painter not active");
+ return 1.0;
+ }
+ return d->state->opacity;
+}
+
+/*!
+ \since 4.2
+
+ Sets the opacity of the painter to \a opacity. The value should
+ be in the range 0.0 to 1.0, where 0.0 is fully transparent and
+ 1.0 is fully opaque.
+
+ Opacity set on the painter will apply to all drawing operations
+ individually.
+*/
+
+void QPainter::setOpacity(qreal opacity)
+{
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setOpacity: Painter not active");
+ return;
+ }
+
+ opacity = qMin(qreal(1), qMax(qreal(0), opacity));
+
+ if (opacity == d->state->opacity)
+ return;
+
+ d->state->opacity = opacity;
+
+ if (d->extended)
+ d->extended->opacityChanged();
+ else
+ d->state->dirtyFlags |= QPaintEngine::DirtyOpacity;
+}
+
+
+/*!
+ Returns the currently set brush origin.
+
+ \sa setBrushOrigin(), {QPainter#Settings}{Settings}
+*/
+
+QPoint QPainter::brushOrigin() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::brushOrigin: Painter not active");
+ return QPoint();
+ }
+ return QPointF(d->state->brushOrigin).toPoint();
+}
+
+/*!
+ \fn void QPainter::setBrushOrigin(const QPointF &position)
+
+ Sets the brush origin to \a position.
+
+ The brush origin specifies the (0, 0) coordinate of the painter's
+ brush. This setting only applies to pattern brushes and pixmap
+ brushes.
+
+ Note that while the brushOrigin() was necessary to adopt the
+ parent's background for a widget in Qt 3, this is no longer the
+ case since the Qt 4 painter doesn't paint the background unless
+ you explicitly tell it to do so by setting the widget's \l
+ {QWidget::autoFillBackground}{autoFillBackground} property to
+ true.
+
+ \sa brushOrigin(), {QPainter#Settings}{Settings}
+*/
+
+void QPainter::setBrushOrigin(const QPointF &p)
+{
+ Q_D(QPainter);
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setBrushOrigin(), (%.2f,%.2f)\n", p.x(), p.y());
+#endif
+
+ if (!d->engine) {
+ qWarning("QPainter::setBrushOrigin: Painter not active");
+ return;
+ }
+
+ d->state->brushOrigin = p;
+
+ if (d->extended) {
+ d->extended->brushOriginChanged();
+ return;
+ }
+
+ d->state->dirtyFlags |= QPaintEngine::DirtyBrushOrigin;
+}
+
+/*!
+ \fn void QPainter::setBrushOrigin(const QPoint &position)
+ \overload
+
+ Sets the brush's origin to the given \a position.
+*/
+
+/*!
+ \fn void QPainter::setBrushOrigin(int x, int y)
+
+ \overload
+
+ Sets the brush's origin to point (\a x, \a y).
+*/
+
+/*!
+ \enum QPainter::CompositionMode
+
+ Defines the modes supported for digital image compositing.
+ Composition modes are used to specify how the pixels in one image,
+ the source, are merged with the pixel in another image, the
+ destination.
+
+ Please note that the bitwise raster operation modes, denoted with
+ a RasterOp prefix, are only natively supported in the X11 and
+ raster paint engines. This means that the only way to utilize
+ these modes on the Mac is via a QImage. The RasterOp denoted blend
+ modes are \e not supported for pens and brushes with alpha
+ components. Also, turning on the QPainter::Antialiasing render
+ hint will effectively disable the RasterOp modes.
+
+
+ \image qpainter-compositionmode1.png
+ \image qpainter-compositionmode2.png
+
+ The most common type is SourceOver (often referred to as just
+ alpha blending) where the source pixel is blended on top of the
+ destination pixel in such a way that the alpha component of the
+ source defines the translucency of the pixel.
+
+ When the paint device is a QImage, the image format must be set to
+ \l {QImage::Format}{Format_ARGB32Premultiplied} or
+ \l {QImage::Format}{Format_ARGB32} for the composition modes to have
+ any effect. For performance the premultiplied version is the preferred
+ format.
+
+ When a composition mode is set it applies to all painting
+ operator, pens, brushes, gradients and pixmap/image drawing.
+
+ \value CompositionMode_SourceOver This is the default mode. The
+ alpha of the source is used to blend the pixel on top of the
+ destination.
+
+ \value CompositionMode_DestinationOver The alpha of the
+ destination is used to blend it on top of the source pixels. This
+ mode is the inverse of CompositionMode_SourceOver.
+
+ \value CompositionMode_Clear The pixels in the destination are
+ cleared (set to fully transparent) independent of the source.
+
+ \value CompositionMode_Source The output is the source
+ pixel. (This means a basic copy operation and is identical to
+ SourceOver when the source pixel is opaque).
+
+ \value CompositionMode_Destination The output is the destination
+ pixel. This means that the blending has no effect. This mode is
+ the inverse of CompositionMode_Source.
+
+ \value CompositionMode_SourceIn The output is the source, where
+ the alpha is reduced by that of the destination.
+
+ \value CompositionMode_DestinationIn The output is the
+ destination, where the alpha is reduced by that of the
+ source. This mode is the inverse of CompositionMode_SourceIn.
+
+ \value CompositionMode_SourceOut The output is the source, where
+ the alpha is reduced by the inverse of destination.
+
+ \value CompositionMode_DestinationOut The output is the
+ destination, where the alpha is reduced by the inverse of the
+ source. This mode is the inverse of CompositionMode_SourceOut.
+
+ \value CompositionMode_SourceAtop The source pixel is blended on
+ top of the destination, with the alpha of the source pixel reduced
+ by the alpha of the destination pixel.
+
+ \value CompositionMode_DestinationAtop The destination pixel is
+ blended on top of the source, with the alpha of the destination
+ pixel is reduced by the alpha of the destination pixel. This mode
+ is the inverse of CompositionMode_SourceAtop.
+
+ \value CompositionMode_Xor The source, whose alpha is reduced with
+ the inverse of the destination alpha, is merged with the
+ destination, whose alpha is reduced by the inverse of the source
+ alpha. CompositionMode_Xor is not the same as the bitwise Xor.
+
+ \value CompositionMode_Plus Both the alpha and color of the source
+ and destination pixels are added together.
+
+ \value CompositionMode_Multiply The output is the source color
+ multiplied by the destination. Multiplying a color with white
+ leaves the color unchanged, while multiplying a color
+ with black produces black.
+
+ \value CompositionMode_Screen The source and destination colors
+ are inverted and then multiplied. Screening a color with white
+ produces white, whereas screening a color with black leaves the
+ color unchanged.
+
+ \value CompositionMode_Overlay Multiplies or screens the colors
+ depending on the destination color. The destination color is mixed
+ with the source color to reflect the lightness or darkness of the
+ destination.
+
+ \value CompositionMode_Darken The darker of the source and
+ destination colors is selected.
+
+ \value CompositionMode_Lighten The lighter of the source and
+ destination colors is selected.
+
+ \value CompositionMode_ColorDodge The destination color is
+ brightened to reflect the source color. A black source color
+ leaves the destination color unchanged.
+
+ \value CompositionMode_ColorBurn The destination color is darkened
+ to reflect the source color. A white source color leaves the
+ destination color unchanged.
+
+ \value CompositionMode_HardLight Multiplies or screens the colors
+ depending on the source color. A light source color will lighten
+ the destination color, whereas a dark source color will darken the
+ destination color.
+
+ \value CompositionMode_SoftLight Darkens or lightens the colors
+ depending on the source color. Similar to
+ CompositionMode_HardLight.
+
+ \value CompositionMode_Difference Subtracts the darker of the
+ colors from the lighter. Painting with white inverts the
+ destination color, whereas painting with black leaves the
+ destination color unchanged.
+
+ \value CompositionMode_Exclusion Similar to
+ CompositionMode_Difference, but with a lower contrast. Painting
+ with white inverts the destination color, whereas painting with
+ black leaves the destination color unchanged.
+
+ \value RasterOp_SourceOrDestination Does a bitwise OR operation on
+ the source and destination pixels (src OR dst).
+
+ \value RasterOp_SourceAndDestination Does a bitwise AND operation
+ on the source and destination pixels (src AND dst).
+
+ \value RasterOp_SourceXorDestination Does a bitwise XOR operation
+ on the source and destination pixels (src XOR dst).
+
+ \value RasterOp_NotSourceAndNotDestination Does a bitwise NOR
+ operation on the source and destination pixels ((NOT src) AND (NOT
+ dst)).
+
+ \value RasterOp_NotSourceOrNotDestination Does a bitwise NAND
+ operation on the source and destination pixels ((NOT src) OR (NOT
+ dst)).
+
+ \value RasterOp_NotSourceXorDestination Does a bitwise operation
+ where the source pixels are inverted and then XOR'ed with the
+ destination ((NOT src) XOR dst).
+
+ \value RasterOp_NotSource Does a bitwise operation where the
+ source pixels are inverted (NOT src).
+
+ \value RasterOp_NotSourceAndDestination Does a bitwise operation
+ where the source is inverted and then AND'ed with the destination
+ ((NOT src) AND dst).
+
+ \value RasterOp_SourceAndNotDestination Does a bitwise operation
+ where the source is AND'ed with the inverted destination pixels
+ (src AND (NOT dst)).
+
+ \sa compositionMode(), setCompositionMode(), {QPainter#Composition
+ Modes}{Composition Modes}, {Image Composition Example}
+*/
+
+/*!
+ Sets the composition mode to the given \a mode.
+
+ \warning You can only set the composition mode for QPainter
+ objects that operates on a QImage.
+
+ \sa compositionMode()
+*/
+void QPainter::setCompositionMode(CompositionMode mode)
+{
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setCompositionMode: Painter not active");
+ return;
+ }
+ if (d->extended) {
+ d->state->composition_mode = mode;
+ d->extended->compositionModeChanged();
+ return;
+ }
+
+ if (mode >= QPainter::RasterOp_SourceOrDestination) {
+ if (!d->engine->hasFeature(QPaintEngine::RasterOpModes)) {
+ qWarning("QPainter::setCompositionMode: "
+ "Raster operation modes not supported on device");
+ return;
+ }
+ } else if (mode >= QPainter::CompositionMode_Plus) {
+ if (!d->engine->hasFeature(QPaintEngine::BlendModes)) {
+ qWarning("QPainter::setCompositionMode: "
+ "Blend modes not supported on device");
+ return;
+ }
+ } else if (!d->engine->hasFeature(QPaintEngine::PorterDuff)) {
+ if (mode != CompositionMode_Source && mode != CompositionMode_SourceOver) {
+ qWarning("QPainter::setCompositionMode: "
+ "PorterDuff modes not supported on device");
+ return;
+ }
+ }
+
+ d->state->composition_mode = mode;
+ d->state->dirtyFlags |= QPaintEngine::DirtyCompositionMode;
+}
+
+/*!
+ Returns the current composition mode.
+
+ \sa CompositionMode, setCompositionMode()
+*/
+QPainter::CompositionMode QPainter::compositionMode() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::compositionMode: Painter not active");
+ return QPainter::CompositionMode_SourceOver;
+ }
+ return d->state->composition_mode;
+}
+
+/*!
+ Returns the current background brush.
+
+ \sa setBackground(), {QPainter#Settings}{Settings}
+*/
+
+const QBrush &QPainter::background() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::background: Painter not active");
+ return d->fakeState()->brush;
+ }
+ return d->state->bgBrush;
+}
+
+
+/*!
+ Returns true if clipping has been set; otherwise returns false.
+
+ \sa setClipping(), {QPainter#Clipping}{Clipping}
+*/
+
+bool QPainter::hasClipping() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::hasClipping: Painter not active");
+ return false;
+ }
+ return d->state->clipEnabled && d->state->clipOperation != Qt::NoClip;
+}
+
+
+/*!
+ Enables clipping if \a enable is true, or disables clipping if \a
+ enable is false.
+
+ \sa hasClipping(), {QPainter#Clipping}{Clipping}
+*/
+
+void QPainter::setClipping(bool enable)
+{
+ Q_D(QPainter);
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setClipping(), enable=%s, was=%s\n",
+ enable ? "on" : "off",
+ hasClipping() ? "on" : "off");
+#endif
+ if (!d->engine) {
+ qWarning("QPainter::setClipping: Painter not active, state will be reset by begin");
+ return;
+ }
+
+ if (hasClipping() == enable)
+ return;
+
+ // we can't enable clipping if we don't have a clip
+ if (enable
+ && (d->state->clipInfo.isEmpty() || d->state->clipInfo.last().operation == Qt::NoClip))
+ return;
+ d->state->clipEnabled = enable;
+
+ if (d->extended) {
+ d->extended->clipEnabledChanged();
+ return;
+ }
+
+ d->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
+ d->updateState(d->state);
+}
+
+
+/*!
+ Returns the currently set clip region. Note that the clip region
+ is given in logical coordinates.
+
+ \sa setClipRegion(), clipPath(), setClipping()
+*/
+
+QRegion QPainter::clipRegion() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::clipRegion: Painter not active");
+ return QRegion();
+ }
+
+ QRegion region;
+ bool lastWasNothing = true;
+
+ if (!d->txinv)
+ const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
+
+ // ### Falcon: Use QPainterPath
+ for (int i=0; i<d->state->clipInfo.size(); ++i) {
+ const QPainterClipInfo &info = d->state->clipInfo.at(i);
+ QRegion other;
+ switch (info.clipType) {
+
+ case QPainterClipInfo::RegionClip: {
+ QTransform matrix = (info.matrix * d->invMatrix);
+ if (lastWasNothing) {
+ region = info.region * matrix;
+ lastWasNothing = false;
+ continue;
+ }
+ if (info.operation == Qt::IntersectClip)
+ region &= info.region * matrix;
+ else if (info.operation == Qt::UniteClip)
+ region |= info.region * matrix;
+ else if (info.operation == Qt::NoClip) {
+ lastWasNothing = true;
+ region = QRegion();
+ } else
+ region = info.region * matrix;
+ break;
+ }
+
+ case QPainterClipInfo::PathClip: {
+ QTransform matrix = (info.matrix * d->invMatrix);
+ if (lastWasNothing) {
+ region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
+ info.path.fillRule());
+ lastWasNothing = false;
+ continue;
+ }
+ if (info.operation == Qt::IntersectClip) {
+ region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
+ info.path.fillRule());
+ } else if (info.operation == Qt::UniteClip) {
+ region |= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
+ info.path.fillRule());
+ } else if (info.operation == Qt::NoClip) {
+ lastWasNothing = true;
+ region = QRegion();
+ } else {
+ region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
+ info.path.fillRule());
+ }
+ break;
+ }
+
+ case QPainterClipInfo::RectClip: {
+ QTransform matrix = (info.matrix * d->invMatrix);
+ if (lastWasNothing) {
+ region = QRegion(info.rect) * matrix;
+ lastWasNothing = false;
+ continue;
+ }
+ if (info.operation == Qt::IntersectClip)
+ region &= QRegion(info.rect) * matrix;
+ else if (info.operation == Qt::UniteClip)
+ region |= QRegion(info.rect) * matrix;
+ else if (info.operation == Qt::NoClip) {
+ lastWasNothing = true;
+ region = QRegion();
+ } else
+ region = QRegion(info.rect) * matrix;
+ break;
+ }
+
+ case QPainterClipInfo::RectFClip: {
+ QTransform matrix = (info.matrix * d->invMatrix);
+ if (lastWasNothing) {
+ region = QRegion(info.rectf.toRect()) * matrix;
+ lastWasNothing = false;
+ continue;
+ }
+ if (info.operation == Qt::IntersectClip)
+ region &= QRegion(info.rectf.toRect()) * matrix;
+ else if (info.operation == Qt::UniteClip)
+ region |= QRegion(info.rectf.toRect()) * matrix;
+ else if (info.operation == Qt::NoClip) {
+ lastWasNothing = true;
+ region = QRegion();
+ } else
+ region = QRegion(info.rectf.toRect()) * matrix;
+ break;
+ }
+ }
+ }
+
+ return region;
+}
+
+/*!
+ Returns the currently clip as a path. Note that the clip path is
+ given in logical coordinates.
+
+ \sa setClipPath(), clipRegion(), setClipping()
+*/
+QPainterPath QPainter::clipPath() const
+{
+ Q_D(const QPainter);
+
+ // ### Since we do not support path intersections and path unions yet,
+ // we just use clipRegion() here...
+ if (!d->engine) {
+ qWarning("QPainter::clipPath: Painter not active");
+ return QPainterPath();
+ }
+
+ // No clip, return empty
+ if (d->state->clipInfo.size() == 0) {
+ return QPainterPath();
+ } else {
+
+ // Update inverse matrix, used below.
+ if (!d->txinv)
+ const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
+
+ // For the simple case avoid conversion.
+ if (d->state->clipInfo.size() == 1
+ && d->state->clipInfo.at(0).clipType == QPainterClipInfo::PathClip) {
+ QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
+ return d->state->clipInfo.at(0).path * matrix;
+
+ } else if (d->state->clipInfo.size() == 1
+ && d->state->clipInfo.at(0).clipType == QPainterClipInfo::RectClip) {
+ QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
+ QPainterPath path;
+ path.addRect(d->state->clipInfo.at(0).rect);
+ return path * matrix;
+ } else {
+ // Fallback to clipRegion() for now, since we don't have isect/unite for paths
+ extern QPainterPath qt_regionToPath(const QRegion &region);
+ return qt_regionToPath(clipRegion());
+ }
+ }
+}
+
+/*!
+ \fn void QPainter::setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
+
+ Enables clipping, and sets the clip region to the given \a
+ rectangle using the given clip \a operation. The default operation
+ is to replace the current clip rectangle.
+
+ Note that the clip rectangle is specified in logical (painter)
+ coordinates.
+
+ \sa clipRegion(), setClipping(), {QPainter#Clipping}{Clipping}
+*/
+void QPainter::setClipRect(const QRectF &rect, Qt::ClipOperation op)
+{
+ Q_D(QPainter);
+
+ if (d->extended) {
+ if (!d->engine) {
+ qWarning("QPainter::setClipRect: Painter not active");
+ return;
+ }
+ qreal right = rect.x() + rect.width();
+ qreal bottom = rect.y() + rect.height();
+ qreal pts[] = { rect.x(), rect.y(),
+ right, rect.y(),
+ right, bottom,
+ rect.x(), bottom };
+ QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint);
+ d->state->clipEnabled = true;
+ d->extended->clip(vp, op);
+ d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform());
+ d->state->clipOperation = op;
+ return;
+ }
+
+ if (qreal(int(rect.top())) == rect.top()
+ && qreal(int(rect.bottom())) == rect.bottom()
+ && qreal(int(rect.left())) == rect.left()
+ && qreal(int(rect.right())) == rect.right())
+ {
+ setClipRect(rect.toRect(), op);
+ return;
+ }
+
+ if (rect.isEmpty()) {
+ setClipRegion(QRegion(), op);
+ return;
+ }
+
+ QPainterPath path;
+ path.addRect(rect);
+ setClipPath(path, op);
+}
+
+/*!
+ \fn void QPainter::setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
+ \overload
+
+ Enables clipping, and sets the clip region to the given \a rectangle using the given
+ clip \a operation.
+*/
+void QPainter::setClipRect(const QRect &rect, Qt::ClipOperation op)
+{
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setClipRect: Painter not active");
+ return;
+ }
+
+ if (d->extended) {
+ d->state->clipEnabled = true;
+ d->extended->clip(rect, op);
+ d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform());
+ d->state->clipOperation = op;
+ return;
+ }
+
+ if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))
+ op = Qt::ReplaceClip;
+
+ d->state->clipRegion = rect;
+ d->state->clipOperation = op;
+ if (op == Qt::NoClip || op == Qt::ReplaceClip)
+ d->state->clipInfo.clear();
+ d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform());
+ d->state->clipEnabled = true;
+ d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
+ d->updateState(d->state);
+}
+
+/*!
+ \fn void QPainter::setClipRect(int x, int y, int width, int height, Qt::ClipOperation operation)
+
+ Enables clipping, and sets the clip region to the rectangle beginning at (\a x, \a y)
+ with the given \a width and \a height.
+*/
+
+/*!
+ \fn void QPainter::setClipRegion(const QRegion &region, Qt::ClipOperation operation)
+
+ Sets the clip region to the given \a region using the specified clip
+ \a operation. The default clip operation is to replace the current
+ clip region.
+
+ Note that the clip region is given in logical coordinates.
+
+ \sa clipRegion(), setClipRect(), {QPainter#Clipping}{Clipping}
+*/
+void QPainter::setClipRegion(const QRegion &r, Qt::ClipOperation op)
+{
+ Q_D(QPainter);
+#ifdef QT_DEBUG_DRAW
+ QRect rect = r.boundingRect();
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
+ r.rects().size(), rect.x(), rect.y(), rect.width(), rect.height());
+#endif
+ if (!d->engine) {
+ qWarning("QPainter::setClipRegion: Painter not active");
+ return;
+ }
+
+ if (d->extended) {
+ d->state->clipEnabled = true;
+ d->extended->clip(r, op);
+ d->state->clipInfo << QPainterClipInfo(r, op, combinedTransform());
+ d->state->clipOperation = op;
+ return;
+ }
+
+ if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))
+ op = Qt::ReplaceClip;
+
+ d->state->clipRegion = r;
+ d->state->clipOperation = op;
+ if (op == Qt::NoClip || op == Qt::ReplaceClip)
+ d->state->clipInfo.clear();
+ d->state->clipInfo << QPainterClipInfo(r, op, combinedTransform());
+ d->state->clipEnabled = true;
+ d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
+ d->updateState(d->state);
+}
+
+/*!
+ \since 4.2
+
+ Sets the transformation matrix to \a matrix and enables transformations.
+
+ \note It is advisable to use setWorldTransform() instead of this function to
+ preserve the properties of perspective transformations.
+
+ If \a combine is true, then \a matrix is combined with the current
+ transformation matrix; otherwise \a matrix replaces the current
+ transformation matrix.
+
+ If \a matrix is the identity matrix and \a combine is false, this
+ function calls setWorldMatrixEnabled(false). (The identity matrix is the
+ matrix where QMatrix::m11() and QMatrix::m22() are 1.0 and the
+ rest are 0.0.)
+
+ The following functions can transform the coordinate system without using
+ a QMatrix:
+ \list
+ \i translate()
+ \i scale()
+ \i shear()
+ \i rotate()
+ \endlist
+
+ They operate on the painter's worldMatrix() and are implemented like this:
+
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 4
+
+ Note that when using setWorldMatrix() function you should always have
+ \a combine be true when you are drawing into a QPicture. Otherwise
+ it may not be possible to replay the picture with additional
+ transformations; using the translate(), scale(), etc. convenience
+ functions is safe.
+
+ For more information about the coordinate system, transformations
+ and window-viewport conversion, see \l {The Coordinate System}
+ documentation.
+
+ \sa worldMatrixEnabled(), QMatrix
+*/
+
+void QPainter::setWorldMatrix(const QMatrix &matrix, bool combine)
+{
+ setWorldTransform(QTransform(matrix), combine);
+}
+
+/*!
+ \since 4.2
+
+ Returns the world transformation matrix.
+
+ It is advisable to use worldTransform() because worldMatrix() does not
+ preserve the properties of perspective transformations.
+
+ \sa {QPainter#Coordinate Transformations}{Coordinate Transformations},
+ {The Coordinate System}
+*/
+
+const QMatrix &QPainter::worldMatrix() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::worldMatrix: Painter not active");
+ return d->fakeState()->transform.toAffine();
+ }
+ return d->state->worldMatrix.toAffine();
+}
+
+/*!
+ \obsolete
+
+ Use setWorldTransform() instead.
+
+ \sa setWorldTransform()
+*/
+
+void QPainter::setMatrix(const QMatrix &matrix, bool combine)
+{
+ setWorldTransform(QTransform(matrix), combine);
+}
+
+/*!
+ \obsolete
+
+ Use worldTransform() instead.
+
+ \sa worldTransform()
+*/
+
+const QMatrix &QPainter::matrix() const
+{
+ return worldMatrix();
+}
+
+
+/*!
+ \since 4.2
+
+ Returns the transformation matrix combining the current
+ window/viewport and world transformation.
+
+ It is advisable to use combinedTransform() instead of this
+ function to preserve the properties of perspective transformations.
+
+ \sa setWorldMatrix(), setWindow(), setViewport()
+*/
+QMatrix QPainter::combinedMatrix() const
+{
+ return combinedTransform().toAffine();
+}
+
+
+/*!
+ Returns the matrix that transforms from logical coordinates to
+ device coordinates of the platform dependent paint device.
+
+ \note It is advisable to use deviceTransform() instead of this
+ function to preserve the properties of perspective transformations.
+
+ This function is \e only needed when using platform painting
+ commands on the platform dependent handle (Qt::HANDLE), and the
+ platform does not do transformations nativly.
+
+ The QPaintEngine::PaintEngineFeature enum can be queried to
+ determine whether the platform performs the transformations or
+ not.
+
+ \sa worldMatrix(), QPaintEngine::hasFeature(),
+*/
+const QMatrix &QPainter::deviceMatrix() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::deviceMatrix: Painter not active");
+ return d->fakeState()->transform.toAffine();
+ }
+ return d->state->matrix.toAffine();
+}
+
+/*!
+ Resets any transformations that were made using translate(), scale(),
+ shear(), rotate(), setWorldMatrix(), setViewport() and
+ setWindow().
+
+ It is advisable to use resetTransform() instead of this function
+ to preserve the properties of perspective transformations.
+
+ \sa {QPainter#Coordinate Transformations}{Coordinate
+ Transformations}
+*/
+
+void QPainter::resetMatrix()
+{
+ resetTransform();
+}
+
+
+/*!
+ \since 4.2
+
+ Enables transformations if \a enable is true, or disables
+ transformations if \a enable is false. The world transformation
+ matrix is not changed.
+
+ \sa worldMatrixEnabled(), worldMatrix(), {QPainter#Coordinate
+ Transformations}{Coordinate Transformations}
+*/
+
+void QPainter::setWorldMatrixEnabled(bool enable)
+{
+ Q_D(QPainter);
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setMatrixEnabled(), enable=%d\n", enable);
+#endif
+
+ if (!d->engine) {
+ qWarning("QPainter::setMatrixEnabled: Painter not active");
+ return;
+ }
+ if (enable == d->state->WxF)
+ return;
+
+ d->state->WxF = enable;
+ d->updateMatrix();
+}
+
+/*!
+ \since 4.2
+
+ Returns true if world transformation is enabled; otherwise returns
+ false.
+
+ \sa setWorldMatrixEnabled(), worldMatrix(), {The Coordinate System}
+*/
+
+bool QPainter::worldMatrixEnabled() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::worldMatrixEnabled: Painter not active");
+ return false;
+ }
+ return d->state->WxF;
+}
+
+/*!
+ \obsolete
+
+ Use setWorldMatrixEnabled() instead.
+
+ \sa setWorldMatrixEnabled()
+*/
+
+void QPainter::setMatrixEnabled(bool enable)
+{
+ setWorldMatrixEnabled(enable);
+}
+
+/*!
+ \obsolete
+
+ Use worldMatrixEnabled() instead
+
+ \sa worldMatrixEnabled()
+*/
+
+bool QPainter::matrixEnabled() const
+{
+ return worldMatrixEnabled();
+}
+
+/*!
+ Scales the coordinate system by (\a{sx}, \a{sy}).
+
+ \sa setWorldMatrix() {QPainter#Coordinate Transformations}{Coordinate
+ Transformations}
+*/
+
+void QPainter::scale(qreal sx, qreal sy)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::scale(), sx=%f, sy=%f\n", sx, sy);
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::scale: Painter not active");
+ return;
+ }
+
+ d->state->worldMatrix.scale(sx,sy);
+ d->state->WxF = true;
+ d->updateMatrix();
+}
+
+/*!
+ Shears the coordinate system by (\a{sh}, \a{sv}).
+
+ \sa setWorldMatrix(), {QPainter#Coordinate Transformations}{Coordinate
+ Transformations}
+*/
+
+void QPainter::shear(qreal sh, qreal sv)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::shear(), sh=%f, sv=%f\n", sh, sv);
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::shear: Painter not active");
+ return;
+ }
+
+ d->state->worldMatrix.shear(sh, sv);
+ d->state->WxF = true;
+ d->updateMatrix();
+}
+
+/*!
+ \fn void QPainter::rotate(qreal angle)
+
+ Rotates the coordinate system the given \a angle clockwise.
+
+ \sa setWorldMatrix(), {QPainter#Coordinate Transformations}{Coordinate
+ Transformations}
+*/
+
+void QPainter::rotate(qreal a)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::rotate(), angle=%f\n", a);
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::rotate: Painter not active");
+ return;
+ }
+
+ d->state->worldMatrix.rotate(a);
+ d->state->WxF = true;
+ d->updateMatrix();
+}
+
+/*!
+ Translates the coordinate system by the given \a offset; i.e. the
+ given \a offset is added to points.
+
+ \sa setWorldMatrix(), {QPainter#Coordinate Transformations}{Coordinate
+ Transformations}
+*/
+void QPainter::translate(const QPointF &offset)
+{
+ qreal dx = offset.x();
+ qreal dy = offset.y();
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::translate(), dx=%f, dy=%f\n", dx, dy);
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::translate: Painter not active");
+ return;
+ }
+
+ d->state->worldMatrix.translate(dx, dy);
+ d->state->WxF = true;
+ d->updateMatrix();
+}
+
+/*!
+ \fn void QPainter::translate(const QPoint &offset)
+ \overload
+
+ Translates the coordinate system by the given \a offset.
+*/
+
+/*!
+ \fn void QPainter::translate(qreal dx, qreal dy)
+ \overload
+
+ Translates the coordinate system by the vector (\a dx, \a dy).
+*/
+
+/*!
+ \fn void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation operation)
+
+ Enables clipping, and sets the clip path for the painter to the
+ given \a path, with the clip \a operation.
+
+ Note that the clip path is specified in logical (painter)
+ coordinates.
+
+ \sa clipPath(), clipRegion(), {QPainter#Clipping}{Clipping}
+
+*/
+void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output) {
+ QRectF b = path.boundingRect();
+ printf("QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
+ path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
+ }
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setClipPath: Painter not active");
+ return;
+ }
+
+ if (d->extended) {
+ d->state->clipEnabled = true;
+ d->extended->clip(path, op);
+ d->state->clipInfo << QPainterClipInfo(path, op, combinedTransform());
+ d->state->clipOperation = op;
+ return;
+ }
+
+
+
+ if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))
+ op = Qt::ReplaceClip;
+
+ d->state->clipPath = path;
+ d->state->clipOperation = op;
+ if (op == Qt::NoClip || op == Qt::ReplaceClip)
+ d->state->clipInfo.clear();
+ d->state->clipInfo << QPainterClipInfo(path, op, combinedTransform());
+ d->state->clipEnabled = true;
+ d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
+ d->updateState(d->state);
+}
+
+/*!
+ Draws the outline (strokes) the path \a path with the pen specified
+ by \a pen
+
+ \sa fillPath(), {QPainter#Drawing}{Drawing}
+*/
+void QPainter::strokePath(const QPainterPath &path, const QPen &pen)
+{
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::strokePath: Painter not active");
+ return;
+ }
+
+ if (d->extended) {
+ const QGradient *g = qpen_brush(pen).gradient();
+ if (!g || g->coordinateMode() == QGradient::LogicalMode) {
+ d->extended->stroke(qtVectorPathForPath(path), pen);
+ return;
+ }
+ }
+
+ QBrush oldBrush = d->state->brush;
+ QPen oldPen = d->state->pen;
+
+ setPen(pen);
+ setBrush(Qt::NoBrush);
+
+ drawPath(path);
+
+ // Reset old state
+ setPen(oldPen);
+ setBrush(oldBrush);
+}
+
+/*!
+ Fills the given \a path using the given \a brush. The outline is
+ not drawn.
+
+ Alternatively, you can specify a QColor instead of a QBrush; the
+ QBrush constructor (taking a QColor argument) will automatically
+ create a solid pattern brush.
+
+ \sa drawPath()
+*/
+void QPainter::fillPath(const QPainterPath &path, const QBrush &brush)
+{
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::fillPath: Painter not active");
+ return;
+ }
+
+ if (d->extended) {
+ const QGradient *g = brush.gradient();
+ if (!g || g->coordinateMode() == QGradient::LogicalMode) {
+ d->extended->fill(qtVectorPathForPath(path), brush);
+ return;
+ }
+ }
+
+ QBrush oldBrush = d->state->brush;
+ QPen oldPen = d->state->pen;
+
+ setPen(Qt::NoPen);
+ setBrush(brush);
+
+ drawPath(path);
+
+ // Reset old state
+ setPen(oldPen);
+ setBrush(oldBrush);
+}
+
+/*!
+ Draws the given painter \a path using the current pen for outline
+ and the current brush for filling.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-path.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 5
+ \endtable
+
+ \sa {painting/painterpaths}{the Painter Paths
+ example},{demos/deform}{the Vector Deformation demo}
+*/
+void QPainter::drawPath(const QPainterPath &path)
+{
+#ifdef QT_DEBUG_DRAW
+ QRectF pathBounds = path.boundingRect();
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPath(), size=%d, [%.2f,%.2f,%.2f,%.2f]\n",
+ path.elementCount(),
+ pathBounds.x(), pathBounds.y(), pathBounds.width(), pathBounds.height());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::drawPath: Painter not active");
+ return;
+ }
+
+ if (d->extended) {
+ d->extended->drawPath(path);
+ return;
+ }
+ d->updateState(d->state);
+
+ if (d->engine->hasFeature(QPaintEngine::PainterPaths) && d->state->emulationSpecifier == 0) {
+ d->engine->drawPath(path);
+ } else {
+ d->draw_helper(path);
+ }
+}
+
+/*!
+ \fn void QPainter::drawLine(const QLineF &line)
+
+ Draws a line defined by \a line.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-line.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 6
+ \endtable
+
+ \sa drawLines(), drawPolyline(), {The Coordinate System}
+*/
+
+/*!
+ \fn void QPainter::drawLine(const QLine &line)
+ \overload
+
+ Draws a line defined by \a line.
+*/
+
+/*!
+ \fn void QPainter::drawLine(const QPoint &p1, const QPoint &p2)
+ \overload
+
+ Draws a line from \a p1 to \a p2.
+*/
+
+/*!
+ \fn void QPainter::drawLine(const QPointF &p1, const QPointF &p2)
+ \overload
+
+ Draws a line from \a p1 to \a p2.
+*/
+
+/*!
+ \fn void QPainter::drawLine(int x1, int y1, int x2, int y2)
+ \overload
+
+ Draws a line from (\a x1, \a y1) to (\a x2, \a y2) and sets the
+ current pen position to (\a x2, \a y2).
+*/
+
+/*!
+ \fn void QPainter::drawRect(const QRectF &rectangle)
+
+ Draws the current \a rectangle with the current pen and brush.
+
+ A filled rectangle has a size of \a{rectangle}.size(). A stroked
+ rectangle has a size of \a{rectangle}.size() plus the pen width.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-rectangle.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 7
+ \endtable
+
+ \sa drawRects(), drawPolygon(), {The Coordinate System}
+*/
+
+/*!
+ \fn void QPainter::drawRect(const QRect &rectangle)
+
+ \overload
+
+ Draws the current \a rectangle with the current pen and brush.
+*/
+
+/*!
+ \fn void QPainter::drawRect(int x, int y, int width, int height)
+
+ \overload
+
+ Draws a rectangle with upper left corner at (\a{x}, \a{y}) and
+ with the given \a width and \a height.
+*/
+
+/*!
+ \fn void QPainter::drawRects(const QRectF *rectangles, int rectCount)
+
+ Draws the first \a rectCount of the given \a rectangles using the
+ current pen and brush.
+
+ \sa drawRect()
+*/
+void QPainter::drawRects(const QRectF *rects, int rectCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawRects(), count=%d\n", rectCount);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::drawRects: Painter not active");
+ return;
+ }
+
+ if (rectCount <= 0)
+ return;
+
+ if (d->extended) {
+ d->extended->drawRects(rects, rectCount);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ if (!d->state->emulationSpecifier) {
+ d->engine->drawRects(rects, rectCount);
+ return;
+ }
+
+ if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ for (int i=0; i<rectCount; ++i) {
+ QRectF r(rects[i].x() + d->state->matrix.dx(),
+ rects[i].y() + d->state->matrix.dy(),
+ rects[i].width(),
+ rects[i].height());
+ d->engine->drawRects(&r, 1);
+ }
+ } else {
+ if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
+ for (int i=0; i<rectCount; ++i) {
+ QPainterPath rectPath;
+ rectPath.addRect(rects[i]);
+ d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
+ }
+ } else {
+ QPainterPath rectPath;
+ for (int i=0; i<rectCount; ++i)
+ rectPath.addRect(rects[i]);
+ d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
+ }
+ }
+}
+
+/*!
+ \fn void QPainter::drawRects(const QRect *rectangles, int rectCount)
+ \overload
+
+ Draws the first \a rectCount of the given \a rectangles using the
+ current pen and brush.
+*/
+void QPainter::drawRects(const QRect *rects, int rectCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawRects(), count=%d\n", rectCount);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::drawRects: Painter not active");
+ return;
+ }
+
+ if (rectCount <= 0)
+ return;
+
+ if (d->extended) {
+ d->extended->drawRects(rects, rectCount);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ if (!d->state->emulationSpecifier) {
+ d->engine->drawRects(rects, rectCount);
+ return;
+ }
+
+ if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ for (int i=0; i<rectCount; ++i) {
+ QRectF r(rects[i].x() + d->state->matrix.dx(),
+ rects[i].y() + d->state->matrix.dy(),
+ rects[i].width(),
+ rects[i].height());
+
+ d->engine->drawRects(&r, 1);
+ }
+ } else {
+ if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
+ for (int i=0; i<rectCount; ++i) {
+ QPainterPath rectPath;
+ rectPath.addRect(rects[i]);
+ d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
+ }
+ } else {
+ QPainterPath rectPath;
+ for (int i=0; i<rectCount; ++i)
+ rectPath.addRect(rects[i]);
+
+ d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
+ }
+ }
+}
+
+/*!
+ \fn void QPainter::drawRects(const QVector<QRectF> &rectangles)
+ \overload
+
+ Draws the given \a rectangles using the current pen and brush.
+*/
+
+/*!
+ \fn void QPainter::drawRects(const QVector<QRect> &rectangles)
+
+ \overload
+
+ Draws the given \a rectangles using the current pen and brush.
+*/
+
+/*!
+ \fn void QPainter::drawPoint(const QPointF &position)
+
+ Draws a single point at the given \a position using the current
+ pen's color.
+
+ \sa {The Coordinate System}
+*/
+
+/*!
+ \fn void QPainter::drawPoint(const QPoint &position)
+ \overload
+
+ Draws a single point at the given \a position using the current
+ pen's color.
+*/
+
+/*! \fn void QPainter::drawPoint(int x, int y)
+
+ \overload
+
+ Draws a single point at position (\a x, \a y).
+*/
+
+/*!
+ Draws the first \a pointCount points in the array \a points using
+ the current pen's color.
+
+ \sa {The Coordinate System}
+*/
+void QPainter::drawPoints(const QPointF *points, int pointCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPoints(), count=%d\n", pointCount);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::drawPoints: Painter not active");
+ return;
+ }
+
+ if (pointCount <= 0)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPoints(points, pointCount);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ if (!d->state->emulationSpecifier) {
+ d->engine->drawPoints(points, pointCount);
+ return;
+ }
+
+ if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ // ### use drawPoints function
+ for (int i=0; i<pointCount; ++i) {
+ QPointF pt(points[i].x() + d->state->matrix.dx(),
+ points[i].y() + d->state->matrix.dy());
+ d->engine->drawPoints(&pt, 1);
+ }
+ } else {
+ QPen pen = d->state->pen;
+ bool flat_pen = pen.capStyle() == Qt::FlatCap;
+ if (flat_pen) {
+ save();
+ pen.setCapStyle(Qt::SquareCap);
+ setPen(pen);
+ }
+ QPainterPath path;
+ for (int i=0; i<pointCount; ++i) {
+ path.moveTo(points[i].x(), points[i].y());
+ path.lineTo(points[i].x() + 0.0001, points[i].y());
+ }
+ d->draw_helper(path, QPainterPrivate::StrokeDraw);
+ if (flat_pen)
+ restore();
+ }
+}
+
+/*!
+ \overload
+
+ Draws the first \a pointCount points in the array \a points using
+ the current pen's color.
+*/
+
+void QPainter::drawPoints(const QPoint *points, int pointCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPoints(), count=%d\n", pointCount);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::drawPoints: Painter not active");
+ return;
+ }
+
+ if (pointCount <= 0)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPoints(points, pointCount);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ if (!d->state->emulationSpecifier) {
+ d->engine->drawPoints(points, pointCount);
+ return;
+ }
+
+ if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ // ### use drawPoints function
+ for (int i=0; i<pointCount; ++i) {
+ QPointF pt(points[i].x() + d->state->matrix.dx(),
+ points[i].y() + d->state->matrix.dy());
+ d->engine->drawPoints(&pt, 1);
+ }
+ } else {
+ QPen pen = d->state->pen;
+ bool flat_pen = (pen.capStyle() == Qt::FlatCap);
+ if (flat_pen) {
+ save();
+ pen.setCapStyle(Qt::SquareCap);
+ setPen(pen);
+ }
+ QPainterPath path;
+ for (int i=0; i<pointCount; ++i) {
+ path.moveTo(points[i].x(), points[i].y());
+ path.lineTo(points[i].x() + 0.0001, points[i].y());
+ }
+ d->draw_helper(path, QPainterPrivate::StrokeDraw);
+ if (flat_pen)
+ restore();
+ }
+}
+
+/*!
+ \fn void QPainter::drawPoints(const QPolygonF &points)
+
+ \overload
+
+ Draws the points in the vector \a points.
+*/
+
+/*!
+ \fn void QPainter::drawPoints(const QPolygon &points)
+
+ \overload
+
+ Draws the points in the vector \a points.
+*/
+
+/*!
+ \fn void QPainter::drawPoints(const QPolygon &polygon, int index,
+ int count)
+
+ \overload
+ \compat
+
+ Draws \a count points in the vector \a polygon starting on \a index
+ using the current pen.
+
+ Use drawPoints() combined with QPolygon::constData() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawPoints(polygon, index, count);
+ \newcode
+ int pointCount = (count == -1) ? polygon.size() - index : count;
+
+ QPainter painter(this);
+ painter.drawPoints(polygon.constData() + index, pointCount);
+ \endcode
+*/
+
+/*!
+ Sets the background mode of the painter to the given \a mode
+
+ Qt::TransparentMode (the default) draws stippled lines and text
+ without setting the background pixels. Qt::OpaqueMode fills these
+ space with the current background color.
+
+ Note that in order to draw a bitmap or pixmap transparently, you
+ must use QPixmap::setMask().
+
+ \sa backgroundMode(), setBackground(),
+ {QPainter#Settings}{Settings}
+*/
+
+void QPainter::setBackgroundMode(Qt::BGMode mode)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setBackgroundMode(), mode=%d\n", mode);
+#endif
+
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setBackgroundMode: Painter not active");
+ return;
+ }
+ if (d->state->bgMode == mode)
+ return;
+
+ d->state->bgMode = mode;
+ if (d->extended) {
+ d->checkEmulation();
+ } else {
+ d->state->dirtyFlags |= QPaintEngine::DirtyBackgroundMode;
+ }
+}
+
+/*!
+ Returns the current background mode.
+
+ \sa setBackgroundMode(), {QPainter#Settings}{Settings}
+*/
+Qt::BGMode QPainter::backgroundMode() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::backgroundMode: Painter not active");
+ return Qt::TransparentMode;
+ }
+ return d->state->bgMode;
+}
+
+
+/*!
+ \overload
+
+ Sets the painter's pen to have style Qt::SolidLine, width 0 and the
+ specified \a color.
+*/
+
+void QPainter::setPen(const QColor &color)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setPen(), color=%04x\n", color.rgb());
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setPen: Painter not active");
+ return;
+ }
+
+ if (d->state->pen.style() == Qt::SolidLine
+ && d->state->pen.widthF() == 0
+ && d->state->pen.isSolid()
+ && d->state->pen.color() == color)
+ return;
+
+ QPen pen(color.isValid() ? color : QColor(Qt::black), 0, Qt::SolidLine);
+
+ d->state->pen = pen;
+ if (d->extended)
+ d->extended->penChanged();
+ else
+ d->state->dirtyFlags |= QPaintEngine::DirtyPen;
+}
+
+/*!
+ Sets the painter's pen to be the given \a pen.
+
+ The \a pen defines how to draw lines and outlines, and it also
+ defines the text color.
+
+ \sa pen(), {QPainter#Settings}{Settings}
+*/
+
+void QPainter::setPen(const QPen &pen)
+{
+
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setPen(), color=%04x, (brushStyle=%d) style=%d, cap=%d, join=%d\n",
+ pen.color().rgb(), pen.brush().style(), pen.style(), pen.capStyle(), pen.joinStyle());
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setPen: Painter not active");
+ return;
+ }
+
+ if (d->state->pen == pen)
+ return;
+
+ if (d->extended) {
+ d->state->pen = pen;
+ d->checkEmulation();
+ d->extended->penChanged();
+ return;
+ }
+
+ // Do some checks to see if we are the same pen.
+ Qt::PenStyle currentStyle = d->state->pen.style();
+ if (currentStyle == pen.style() && currentStyle != Qt::CustomDashLine) {
+ if (currentStyle == Qt::NoPen ||
+ (d->state->pen.isSolid() && pen.isSolid()
+ && d->state->pen.color() == pen.color()
+ && d->state->pen.widthF() == pen.widthF()
+ && d->state->pen.capStyle() == pen.capStyle()
+ && d->state->pen.joinStyle() == pen.joinStyle()
+ && d->state->pen.isCosmetic() == pen.isCosmetic()))
+ return;
+ }
+
+ d->state->pen = pen;
+ d->state->dirtyFlags |= QPaintEngine::DirtyPen;
+}
+
+/*!
+ \overload
+
+ Sets the painter's pen to have the given \a style, width 0 and
+ black color.
+*/
+
+void QPainter::setPen(Qt::PenStyle style)
+{
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setPen: Painter not active");
+ return;
+ }
+
+ if (d->state->pen.style() == style
+ && (style == Qt::NoPen || (d->state->pen.widthF() == 0
+ && d->state->pen.isSolid()
+ && d->state->pen.color() == QColor(Qt::black))))
+ return;
+
+ // QPen(Qt::NoPen) is to avoid creating QPenData, including its brush (from the color)
+ // Note that this works well as long as QPen(Qt::NoPen) returns a black, zero-width pen
+ d->state->pen = (style == Qt::NoPen) ? QPen(Qt::NoPen) : QPen(Qt::black, 0, style);
+
+ if (d->extended)
+ d->extended->penChanged();
+ else
+ d->state->dirtyFlags |= QPaintEngine::DirtyPen;
+
+}
+
+/*!
+ Returns the painter's current pen.
+
+ \sa setPen(), {QPainter#Settings}{Settings}
+*/
+
+const QPen &QPainter::pen() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::pen: Painter not active");
+ return d->fakeState()->pen;
+ }
+ return d->state->pen;
+}
+
+
+/*!
+ Sets the painter's brush to the given \a brush.
+
+ The painter's brush defines how shapes are filled.
+
+ \sa brush(), {QPainter#Settings}{Settings}
+*/
+
+void QPainter::setBrush(const QBrush &brush)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setBrush(), color=%04x, style=%d\n", brush.color().rgb(), brush.style());
+#endif
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setBrush: Painter not active");
+ return;
+ }
+
+ if (d->state->brush.d == brush.d)
+ return;
+
+ if (d->extended) {
+ d->state->brush = brush;
+ d->checkEmulation();
+ d->extended->brushChanged();
+ return;
+ }
+
+ Qt::BrushStyle currentStyle = d->state->brush.style();
+ if (currentStyle == brush.style()) {
+ if (currentStyle == Qt::NoBrush
+ || (currentStyle == Qt::SolidPattern
+ && d->state->brush.color() == brush.color()))
+ return;
+ }
+
+ d->state->brush = brush;
+ d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
+}
+
+
+/*!
+ \overload
+
+ Sets the painter's brush to black color and the specified \a
+ style.
+*/
+
+void QPainter::setBrush(Qt::BrushStyle style)
+{
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setBrush: Painter not active");
+ return;
+ }
+ if (d->state->brush.style() == style &&
+ (style == Qt::NoBrush
+ || (style == Qt::SolidPattern && d->state->brush.color() == QColor(0, 0, 0))))
+ return;
+ d->state->brush = QBrush(Qt::black, style);
+ if (d->extended)
+ d->extended->brushChanged();
+ else
+ d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
+}
+
+/*!
+ Returns the painter's current brush.
+
+ \sa QPainter::setBrush(), {QPainter#Settings}{Settings}
+*/
+
+const QBrush &QPainter::brush() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::brush: Painter not active");
+ return d->fakeState()->brush;
+ }
+ return d->state->brush;
+}
+
+/*!
+ \fn void QPainter::setBackground(const QBrush &brush)
+
+ Sets the background brush of the painter to the given \a brush.
+
+ The background brush is the brush that is filled in when drawing
+ opaque text, stippled lines and bitmaps. The background brush has
+ no effect in transparent background mode (which is the default).
+
+ \sa background(), setBackgroundMode(),
+ {QPainter#Settings}{Settings}
+*/
+
+void QPainter::setBackground(const QBrush &bg)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setBackground(), color=%04x, style=%d\n", bg.color().rgb(), bg.style());
+#endif
+
+ Q_D(QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::setBackground: Painter not active");
+ return;
+ }
+ d->state->bgBrush = bg;
+ if (!d->extended)
+ d->state->dirtyFlags |= QPaintEngine::DirtyBackground;
+}
+
+/*!
+ Sets the painter's font to the given \a font.
+
+ This font is used by subsequent drawText() functions. The text
+ color is the same as the pen color.
+
+ If you set a font that isn't available, Qt finds a close match.
+ font() will return what you set using setFont() and fontInfo() returns the
+ font actually being used (which may be the same).
+
+ \sa font(), drawText(), {QPainter#Settings}{Settings}
+*/
+
+void QPainter::setFont(const QFont &font)
+{
+ Q_D(QPainter);
+
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.family().toLatin1().constData(), font.pointSize());
+#endif
+
+ if (!d->engine) {
+ qWarning("QPainter::setFont: Painter not active");
+ return;
+ }
+
+ d->state->font = QFont(font.resolve(d->state->deviceFont), device());
+ if (!d->extended)
+ d->state->dirtyFlags |= QPaintEngine::DirtyFont;
+}
+
+/*!
+ Returns the currently set font used for drawing text.
+
+ \sa setFont(), drawText(), {QPainter#Settings}{Settings}
+*/
+const QFont &QPainter::font() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::font: Painter not active");
+ return d->fakeState()->font;
+ }
+ return d->state->font;
+}
+
+/*!
+ \since 4.4
+
+ Draws the given rectangle \a rect with rounded corners.
+
+ The \a xRadius and \a yRadius arguments specify the radii
+ of the ellipses defining the corners of the rounded rectangle.
+ When \a mode is Qt::RelativeSize, \a xRadius and
+ \a yRadius are specified in percentage of half the rectangle's
+ width and height respectively, and should be in the range
+ 0.0 to 100.0.
+
+ A filled rectangle has a size of rect.size(). A stroked rectangle
+ has a size of rect.size() plus the pen width.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-roundrect.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 8
+ \endtable
+
+ \sa drawRect(), QPen
+*/
+// FALCON: Should we add a specialized method in QPaintEngineEx?
+void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawRoundedRect(), [%.2f,%.2f,%.2f,%.2f]\n", rect.x(), rect.y(), rect.width(), rect.height());
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (xRadius <= 0 || yRadius <= 0) { // draw normal rectangle
+ drawRect(rect);
+ return;
+ }
+
+ if (d->extended) {
+ QPainterPath::ElementType types[] = {
+ QPainterPath::MoveToElement,
+ QPainterPath::LineToElement,
+ QPainterPath::CurveToElement,
+ QPainterPath::CurveToDataElement,
+ QPainterPath::CurveToDataElement,
+ QPainterPath::LineToElement,
+ QPainterPath::CurveToElement,
+ QPainterPath::CurveToDataElement,
+ QPainterPath::CurveToDataElement,
+ QPainterPath::LineToElement,
+ QPainterPath::CurveToElement,
+ QPainterPath::CurveToDataElement,
+ QPainterPath::CurveToDataElement,
+ QPainterPath::LineToElement,
+ QPainterPath::CurveToElement,
+ QPainterPath::CurveToDataElement,
+ QPainterPath::CurveToDataElement
+ };
+
+ qreal x1 = rect.left();
+ qreal x2 = rect.right();
+ qreal y1 = rect.top();
+ qreal y2 = rect.bottom();
+
+ if (mode == Qt::RelativeSize) {
+ xRadius = xRadius * rect.width() / 200.;
+ yRadius = yRadius * rect.height() / 200.;
+ }
+
+ xRadius = qMin(xRadius, rect.width() / 2);
+ yRadius = qMin(yRadius, rect.height() / 2);
+
+ qreal pts[] = {
+ x1 + xRadius, y1, // MoveTo
+ x2 - xRadius, y1, // LineTo
+ x2 - (1 - KAPPA) * xRadius, y1, // CurveTo
+ x2, y1 + (1 - KAPPA) * yRadius,
+ x2, y1 + yRadius,
+ x2, y2 - yRadius, // LineTo
+ x2, y2 - (1 - KAPPA) * yRadius, // CurveTo
+ x2 - (1 - KAPPA) * xRadius, y2,
+ x2 - xRadius, y2,
+ x1 + xRadius, y2, // LineTo
+ x1 + (1 - KAPPA) * xRadius, y2, // CurveTo
+ x1, y2 - (1 - KAPPA) * yRadius,
+ x1, y2 - yRadius,
+ x1, y1 + yRadius, // LineTo
+ x1, y1 + KAPPA * yRadius, // CurveTo
+ x1 + (1 - KAPPA) * xRadius, y1,
+ x1 + xRadius, y1
+ };
+
+ QVectorPath path(pts, 17, types);
+ d->extended->draw(path);
+ return;
+ }
+
+ QPainterPath path;
+ path.addRoundedRect(rect, xRadius, yRadius, mode);
+ drawPath(path);
+}
+
+/*!
+ \fn void QPainter::drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius,
+ Qt::SizeMode mode = Qt::AbsoluteSize);
+ \since 4.4
+ \overload
+
+ Draws the given rectangle \a rect with rounded corners.
+*/
+
+/*!
+ \fn void QPainter::drawRoundedRect(int x, int y, int w, int h, qreal xRadius, qreal yRadius,
+ Qt::SizeMode mode = Qt::AbsoluteSize);
+ \since 4.4
+ \overload
+
+ Draws the given rectangle \a x, \a y, \a w, \a h with rounded corners.
+*/
+
+/*!
+ \obsolete
+
+ Draws a rectangle \a r with rounded corners.
+
+ The \a xRnd and \a yRnd arguments specify how rounded the corners
+ should be. 0 is angled corners, 99 is maximum roundedness.
+
+ A filled rectangle has a size of r.size(). A stroked rectangle
+ has a size of r.size() plus the pen width.
+
+ \sa drawRoundedRect()
+*/
+void QPainter::drawRoundRect(const QRectF &r, int xRnd, int yRnd)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawRoundRectangle(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if(xRnd <= 0 || yRnd <= 0) { // draw normal rectangle
+ drawRect(r);
+ return;
+ }
+
+ QPainterPath path;
+ path.addRoundRect(r, xRnd, yRnd);
+ drawPath(path);
+}
+
+
+/*!
+ \fn void QPainter::drawRoundRect(const QRect &r, int xRnd = 25, int yRnd = 25)
+
+ \overload
+ \obsolete
+
+ Draws the rectangle \a r with rounded corners.
+*/
+
+/*!
+ \obsolete
+
+ \fn QPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd)
+
+ \overload
+
+ Draws the rectangle \a x, \a y, \a w, \a h with rounded corners.
+*/
+
+/*!
+ \fn void QPainter::drawEllipse(const QRectF &rectangle)
+
+ Draws the ellipse defined by the given \a rectangle.
+
+ A filled ellipse has a size of \a{rectangle}.\l
+ {QRect::size()}{size()}. A stroked ellipse has a size of
+ \a{rectangle}.\l {QRect::size()}{size()} plus the pen width.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-ellipse.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 9
+ \endtable
+
+ \sa drawPie(), {The Coordinate System}
+*/
+void QPainter::drawEllipse(const QRectF &r)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ QRectF rect(r.normalized());
+ if (rect.isEmpty())
+ return;
+
+ if (d->extended) {
+ d->extended->drawEllipse(rect);
+ return;
+ }
+
+ d->updateState(d->state);
+ if (d->state->emulationSpecifier) {
+ if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
+ } else {
+ QPainterPath path;
+ path.addEllipse(rect);
+ d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
+ return;
+ }
+ }
+
+ d->engine->drawEllipse(rect);
+}
+
+/*!
+ \fn QPainter::drawEllipse(const QRect &rectangle)
+
+ \overload
+
+ Draws the ellipse defined by the given \a rectangle.
+*/
+void QPainter::drawEllipse(const QRect &r)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawEllipse(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ QRect rect(r.normalized());
+ if (rect.isEmpty())
+ return;
+
+ if (d->extended) {
+ d->extended->drawEllipse(rect);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ if (d->state->emulationSpecifier) {
+ if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ rect.translate(QPoint(qRound(d->state->matrix.dx()), qRound(d->state->matrix.dy())));
+ } else {
+ QPainterPath path;
+ path.addEllipse(rect);
+ d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
+ return;
+ }
+ }
+
+ d->engine->drawEllipse(rect);
+}
+
+/*!
+ \fn QPainter::drawEllipse(int x, int y, int width, int height)
+
+ \overload
+
+ Draws the ellipse defined by the rectangle beginning at (\a{x},
+ \a{y}) with the given \a width and \a height.
+*/
+
+/*!
+ \since 4.4
+
+ \fn QPainter::drawEllipse(const QPointF &center, qreal rx, qreal ry)
+
+ \overload
+
+ Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
+*/
+
+/*!
+ \since 4.4
+
+ \fn QPainter::drawEllipse(const QPoint &center, int rx, int ry)
+
+ \overload
+
+ Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
+*/
+
+/*!
+ \fn void QPainter::drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
+
+ Draws the arc defined by the given \a rectangle, \a startAngle and
+ \a spanAngle.
+
+ The \a startAngle and \a spanAngle must be specified in 1/16th of
+ a degree, i.e. a full circle equals 5760 (16 * 360). Positive
+ values for the angles mean counter-clockwise while negative values
+ mean the clockwise direction. Zero degrees is at the 3 o'clock
+ position.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-arc.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 10
+ \endtable
+
+ \sa drawPie(), drawChord(), {The Coordinate System}
+*/
+
+void QPainter::drawArc(const QRectF &r, int a, int alen)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawArc(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
+ r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ QRectF rect = r.normalized();
+
+ QPainterPath path;
+ path.arcMoveTo(rect, a/16.0);
+ path.arcTo(rect, a/16.0, alen/16.0);
+ strokePath(path, d->state->pen);
+}
+
+/*! \fn void QPainter::drawArc(const QRect &rectangle, int startAngle,
+ int spanAngle)
+
+ \overload
+
+ Draws the arc defined by the given \a rectangle, \a startAngle and
+ \a spanAngle.
+*/
+
+/*!
+ \fn void QPainter::drawArc(int x, int y, int width, int height,
+ int startAngle, int spanAngle)
+
+ \overload
+
+ Draws the arc defined by the rectangle beginning at (\a x, \a y)
+ with the specified \a width and \a height, and the given \a
+ startAngle and \a spanAngle.
+*/
+
+/*!
+ \fn void QPainter::drawPie(const QRectF &rectangle, int startAngle, int spanAngle)
+
+ Draws a pie defined by the given \a rectangle, \a startAngle and
+ and \a spanAngle.
+
+ The pie is filled with the current brush().
+
+ The startAngle and spanAngle must be specified in 1/16th of a
+ degree, i.e. a full circle equals 5760 (16 * 360). Positive values
+ for the angles mean counter-clockwise while negative values mean
+ the clockwise direction. Zero degrees is at the 3 o'clock
+ position.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-pie.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 11
+ \endtable
+
+ \sa drawEllipse(), drawChord(), {The Coordinate System}
+*/
+void QPainter::drawPie(const QRectF &r, int a, int alen)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPie(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
+ r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (a > (360*16)) {
+ a = a % (360*16);
+ } else if (a < 0) {
+ a = a % (360*16);
+ if (a < 0) a += (360*16);
+ }
+
+ QRectF rect = r.normalized();
+
+ QPainterPath path;
+ path.moveTo(rect.center());
+ path.arcTo(rect.x(), rect.y(), rect.width(), rect.height(), a/16.0, alen/16.0);
+ path.closeSubpath();
+ drawPath(path);
+
+}
+
+/*!
+ \fn void QPainter::drawPie(const QRect &rectangle, int startAngle, int spanAngle)
+ \overload
+
+ Draws a pie defined by the given \a rectangle, \a startAngle and
+ and \a spanAngle.
+*/
+
+/*!
+ \fn void QPainter::drawPie(int x, int y, int width, int height, int
+ startAngle, int spanAngle)
+
+ \overload
+
+ Draws the pie defined by the rectangle beginning at (\a x, \a y) with
+ the specified \a width and \a height, and the given \a startAngle and
+ \a spanAngle.
+*/
+
+/*!
+ \fn void QPainter::drawChord(const QRectF &rectangle, int startAngle, int spanAngle)
+
+ Draws the chord defined by the given \a rectangle, \a startAngle and
+ \a spanAngle. The chord is filled with the current brush().
+
+ The startAngle and spanAngle must be specified in 1/16th of a
+ degree, i.e. a full circle equals 5760 (16 * 360). Positive values
+ for the angles mean counter-clockwise while negative values mean
+ the clockwise direction. Zero degrees is at the 3 o'clock
+ position.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-chord.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 12
+ \endtable
+
+ \sa drawArc(), drawPie(), {The Coordinate System}
+*/
+void QPainter::drawChord(const QRectF &r, int a, int alen)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawChord(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
+ r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ QRectF rect = r.normalized();
+
+ QPainterPath path;
+ path.arcMoveTo(rect, a/16.0);
+ path.arcTo(rect, a/16.0, alen/16.0);
+ path.closeSubpath();
+ drawPath(path);
+}
+/*!
+ \fn void QPainter::drawChord(const QRect &rectangle, int startAngle, int spanAngle)
+
+ \overload
+
+ Draws the chord defined by the given \a rectangle, \a startAngle and
+ \a spanAngle.
+*/
+
+/*!
+ \fn void QPainter::drawChord(int x, int y, int width, int height, int
+ startAngle, int spanAngle)
+
+ \overload
+
+ Draws the chord defined by the rectangle beginning at (\a x, \a y)
+ with the specified \a width and \a height, and the given \a
+ startAngle and \a spanAngle.
+*/
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn void QPainter::drawLineSegments(const QPolygon &polygon, int
+ index, int count)
+
+ Draws \a count separate lines from points defined by the \a
+ polygon, starting at \a{polygon}\e{[index]} (\a index defaults to
+ 0). If \a count is -1 (the default) all points until the end of
+ the array are used.
+
+ Use drawLines() combined with QPolygon::constData() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawLineSegments(polygon, index, count);
+ \newcode
+ int lineCount = (count == -1) ? (polygon.size() - index) / 2 : count;
+
+ QPainter painter(this);
+ painter.drawLines(polygon.constData() + index * 2, lineCount);
+ \endcode
+*/
+
+void QPainter::drawLineSegments(const QPolygon &a, int index, int nlines)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawLineSegments(), count=%d\n", a.size()/2);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (nlines < 0)
+ nlines = a.size()/2 - index/2;
+ if (index + nlines*2 > (int)a.size())
+ nlines = (a.size() - index)/2;
+ if (nlines < 1 || index < 0)
+ return;
+
+ if (d->extended) {
+ // FALCON: Use QVectorPath
+ QVector<QLineF> lines;
+ for (int i=index; i<index + nlines*2; i+=2)
+ lines << QLineF(a.at(i), a.at(i+1));
+ d->extended->drawLines(lines.data(), lines.size());
+ return;
+ }
+
+ d->updateState(d->state);
+
+ QVector<QLineF> lines;
+ if (d->state->emulationSpecifier) {
+ if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ QPointF offset(d->state->matrix.dx(), d->state->matrix.dy());
+ for (int i=index; i<index + nlines*2; i+=2)
+ lines << QLineF(a.at(i) + offset, a.at(i+1) + offset);
+ } else {
+ QPainterPath linesPath;
+ for (int i=index; i<index + nlines*2; i+=2) {
+ linesPath.moveTo(a.at(i));
+ linesPath.lineTo(a.at(i+1));
+ }
+ d->draw_helper(linesPath, QPainterPrivate::StrokeDraw);
+ return;
+ }
+ } else {
+ for (int i=index; i<index + nlines*2; i+=2)
+ lines << QLineF(a.at(i), a.at(i+1));
+ }
+
+ d->engine->drawLines(lines.data(), lines.size());
+}
+#endif // QT3_SUPPORT
+
+/*!
+ Draws the first \a lineCount lines in the array \a lines
+ using the current pen.
+
+ \sa drawLine(), drawPolyline()
+*/
+void QPainter::drawLines(const QLineF *lines, int lineCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawLines(), line count=%d\n", lineCount);
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || lineCount < 1)
+ return;
+
+ if (d->extended) {
+ d->extended->drawLines(lines, lineCount);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint lineEmulation = line_emulation(d->state->emulationSpecifier);
+
+ if (lineEmulation) {
+ if (lineEmulation == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ for (int i = 0; i < lineCount; ++i) {
+ QLineF line = lines[i];
+ line.translate(d->state->matrix.dx(), d->state->matrix.dy());
+ d->engine->drawLines(&line, 1);
+ }
+ } else {
+ QPainterPath linePath;
+ for (int i = 0; i < lineCount; ++i) {
+ linePath.moveTo(lines[i].p1());
+ linePath.lineTo(lines[i].p2());
+ }
+ d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
+ }
+ return;
+ }
+ d->engine->drawLines(lines, lineCount);
+}
+
+/*!
+ \fn void QPainter::drawLines(const QLine *lines, int lineCount)
+ \overload
+
+ Draws the first \a lineCount lines in the array \a lines
+ using the current pen.
+*/
+void QPainter::drawLines(const QLine *lines, int lineCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawLine(), line count=%d\n", lineCount);
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || lineCount < 1)
+ return;
+
+ if (d->extended) {
+ d->extended->drawLines(lines, lineCount);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint lineEmulation = line_emulation(d->state->emulationSpecifier);
+
+ if (lineEmulation) {
+ if (lineEmulation == QPaintEngine::PrimitiveTransform
+ && d->state->matrix.type() == QTransform::TxTranslate) {
+ for (int i = 0; i < lineCount; ++i) {
+ QLineF line = lines[i];
+ line.translate(d->state->matrix.dx(), d->state->matrix.dy());
+ d->engine->drawLines(&line, 1);
+ }
+ } else {
+ QPainterPath linePath;
+ for (int i = 0; i < lineCount; ++i) {
+ linePath.moveTo(lines[i].p1());
+ linePath.lineTo(lines[i].p2());
+ }
+ d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
+ }
+ return;
+ }
+ d->engine->drawLines(lines, lineCount);
+}
+
+/*!
+ \overload
+
+ Draws the first \a lineCount lines in the array \a pointPairs
+ using the current pen. The lines are specified as pairs of points
+ so the number of entries in \a pointPairs must be at least \a
+ lineCount * 2.
+*/
+void QPainter::drawLines(const QPointF *pointPairs, int lineCount)
+{
+ Q_ASSERT(sizeof(QLineF) == 2*sizeof(QPointF));
+
+ drawLines((QLineF*)pointPairs, lineCount);
+}
+
+/*!
+ \overload
+
+ Draws the first \a lineCount lines in the array \a pointPairs
+ using the current pen.
+*/
+void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
+{
+ Q_ASSERT(sizeof(QLine) == 2*sizeof(QPoint));
+
+ drawLines((QLine*)pointPairs, lineCount);
+}
+
+
+/*!
+ \fn void QPainter::drawLines(const QVector<QPointF> &pointPairs)
+ \overload
+
+ Draws a line for each pair of points in the vector \a pointPairs
+ using the current pen. If there is an odd number of points in the
+ array, the last point will be ignored.
+*/
+
+/*!
+ \fn void QPainter::drawLines(const QVector<QPoint> &pointPairs)
+ \overload
+
+ Draws a line for each pair of points in the vector \a pointPairs
+ using the current pen.
+*/
+
+/*!
+ \fn void QPainter::drawLines(const QVector<QLineF> &lines)
+ \overload
+
+ Draws the set of lines defined by the list \a lines using the
+ current pen and brush.
+*/
+
+/*!
+ \fn void QPainter::drawLines(const QVector<QLine> &lines)
+ \overload
+
+ Draws the set of lines defined by the list \a lines using the
+ current pen and brush.
+*/
+
+/*!
+ Draws the polyline defined by the first \a pointCount points in \a
+ points using the current pen.
+
+ Note that unlike the drawPolygon() function the last point is \e
+ not connected to the first, neither is the polyline filled.
+
+ \table 100%
+ \row
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 13
+ \endtable
+
+ \sa drawLines(), drawPolygon(), {The Coordinate System}
+*/
+void QPainter::drawPolyline(const QPointF *points, int pointCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPolyline(), count=%d\n", pointCount);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine || pointCount < 2)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint lineEmulation = line_emulation(d->state->emulationSpecifier);
+
+ if (lineEmulation) {
+ // ###
+// if (lineEmulation == QPaintEngine::PrimitiveTransform
+// && d->state->matrix.type() == QTransform::TxTranslate) {
+// } else {
+ QPainterPath polylinePath(points[0]);
+ for (int i=1; i<pointCount; ++i)
+ polylinePath.lineTo(points[i]);
+ d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
+// }
+ } else {
+ d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
+ }
+}
+
+/*!
+ \overload
+
+ Draws the polyline defined by the first \a pointCount points in \a
+ points using the current pen.
+ */
+void QPainter::drawPolyline(const QPoint *points, int pointCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPolyline(), count=%d\n", pointCount);
+#endif
+ Q_D(QPainter);
+
+ if (!d->engine || pointCount < 2)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint lineEmulation = line_emulation(d->state->emulationSpecifier);
+
+ if (lineEmulation) {
+ // ###
+// if (lineEmulation == QPaintEngine::PrimitiveTransform
+// && d->state->matrix.type() == QTransform::TxTranslate) {
+// } else {
+ QPainterPath polylinePath(points[0]);
+ for (int i=1; i<pointCount; ++i)
+ polylinePath.lineTo(points[i]);
+ d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
+// }
+ } else {
+ d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
+ }
+}
+
+/*!
+ \fn void QPainter::drawPolyline(const QPolygon &polygon, int index, int
+ count)
+
+ \overload
+ \compat
+
+ Draws the polyline defined by the \a count lines of the given \a
+ polygon starting at \a index (\a index defaults to 0).
+
+ Use drawPolyline() combined with QPolygon::constData() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawPolyline(polygon, index, count);
+ \newcode
+ int pointCount = (count == -1) ? polygon.size() - index : count;
+
+ QPainter painter(this);
+ painter.drawPolyline(polygon.constData() + index, pointCount);
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawPolyline(const QPolygonF &points)
+
+ \overload
+
+ Draws the polyline defined by the given \a points using the
+ current pen.
+*/
+
+/*!
+ \fn void QPainter::drawPolyline(const QPolygon &points)
+
+ \overload
+
+ Draws the polyline defined by the given \a points using the
+ current pen.
+*/
+
+/*!
+ Draws the polygon defined by the first \a pointCount points in the
+ array \a points using the current pen and brush.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-polygon.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 14
+ \endtable
+
+ The first point is implicitly connected to the last point, and the
+ polygon is filled with the current brush().
+
+ If \a fillRule is Qt::WindingFill, the polygon is filled using the
+ winding fill algorithm. If \a fillRule is Qt::OddEvenFill, the
+ polygon is filled using the odd-even fill algorithm. See
+ \l{Qt::FillRule} for a more detailed description of these fill
+ rules.
+
+ \sa drawConvexPolygon(), drawPolyline(), {The Coordinate System}
+*/
+void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPolygon(), count=%d\n", pointCount);
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || pointCount < 2)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint emulationSpecifier = d->state->emulationSpecifier;
+
+ if (emulationSpecifier) {
+ QPainterPath polygonPath(points[0]);
+ for (int i=1; i<pointCount; ++i)
+ polygonPath.lineTo(points[i]);
+ polygonPath.closeSubpath();
+ polygonPath.setFillRule(fillRule);
+ d->draw_helper(polygonPath);
+ return;
+ }
+
+ d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
+}
+
+/*! \overload
+
+ Draws the polygon defined by the first \a pointCount points in the
+ array \a points.
+*/
+void QPainter::drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPolygon(), count=%d\n", pointCount);
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || pointCount < 2)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint emulationSpecifier = d->state->emulationSpecifier;
+
+ if (emulationSpecifier) {
+ QPainterPath polygonPath(points[0]);
+ for (int i=1; i<pointCount; ++i)
+ polygonPath.lineTo(points[i]);
+ polygonPath.closeSubpath();
+ polygonPath.setFillRule(fillRule);
+ d->draw_helper(polygonPath);
+ return;
+ }
+
+ d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
+}
+
+/*! \fn void QPainter::drawPolygon(const QPolygonF &polygon, bool winding, int index = 0,
+ int count = -1)
+ \compat
+ \overload
+
+ Use drawPolygon() combined with QPolygonF::constData() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawPolygon(polygon, winding, index, count);
+ \newcode
+ int pointCount = (count == -1) ? polygon.size() - index : count;
+ int fillRule = winding ? Qt::WindingFill : Qt::OddEvenFill;
+
+ QPainter painter(this);
+ painter.drawPolygon( polygon.constData() + index, pointCount, fillRule);
+ \endcode
+*/
+
+/*! \fn void QPainter::drawPolygon(const QPolygon &polygon, bool winding,
+ int index = 0, int count = -1)
+
+ \compat
+ \overload
+
+ Use drawPolygon() combined with QPolygon::constData() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawPolygon(polygon, winding, index, count);
+ \newcode
+ int pointCount = (count == -1) ? polygon.size() - index : count;
+ int fillRule = winding ? Qt::WindingFill : Qt::OddEvenFill;
+
+ QPainter painter(this);
+ painter.drawPolygon( polygon.constData() + index, pointCount, fillRule);
+ \endcode
+*/
+
+/*! \fn void QPainter::drawPolygon(const QPolygonF &points, Qt::FillRule fillRule)
+
+ \overload
+
+ Draws the polygon defined by the given \a points using the fill
+ rule \a fillRule.
+*/
+
+/*! \fn void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule)
+
+ \overload
+
+ Draws the polygon defined by the given \a points using the fill
+ rule \a fillRule.
+*/
+
+/*!
+ \fn void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
+
+ Draws the convex polygon defined by the first \a pointCount points
+ in the array \a points using the current pen.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-polygon.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 15
+ \endtable
+
+ The first point is implicitly connected to the last point, and the
+ polygon is filled with the current brush(). If the supplied
+ polygon is not convex, i.e. it contains at least one angle larger
+ than 180 degrees, the results are undefined.
+
+ On some platforms (e.g. X11), the drawConvexPolygon() function can
+ be faster than the drawPolygon() function.
+
+ \sa drawPolygon(), drawPolyline(), {The Coordinate System}
+*/
+
+/*!
+ \fn void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
+ \overload
+
+ Draws the convex polygon defined by the first \a pointCount points
+ in the array \a points using the current pen.
+*/
+
+/*!
+ \fn void QPainter::drawConvexPolygon(const QPolygonF &polygon)
+
+ \overload
+
+ Draws the convex polygon defined by \a polygon using the current
+ pen and brush.
+*/
+
+/*!
+ \fn void QPainter::drawConvexPolygon(const QPolygon &polygon)
+ \overload
+
+ Draws the convex polygon defined by \a polygon using the current
+ pen and brush.
+*/
+
+/*!
+ \fn void QPainter::drawConvexPolygon(const QPolygonF &polygon, int
+ index, int count)
+
+ \compat
+ \overload
+
+ Use drawConvexPolygon() combined with QPolygonF::constData()
+ instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawConvexPolygon(polygon, index, count);
+ \newcode
+ int pointCount = (count == -1) ? polygon.size() - index : count;
+
+ QPainter painter(this);
+ painter.drawConvexPolygon(polygon.constData() + index, pointCount);
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawConvexPolygon(const QPolygon &polygon, int
+ index, int count)
+
+ \compat
+ \overload
+
+ Use drawConvexPolygon() combined with QPolygon::constData()
+ instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawConvexPolygon(polygon, index, count);
+ \newcode
+ int pointCount = (count == -1) ? polygon.size() - index : count;
+
+ QPainter painter(this);
+ painter.drawConvexPolygon(polygon.constData() + index, pointCount);
+ \endcode
+*/
+
+void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || pointCount < 2)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint emulationSpecifier = d->state->emulationSpecifier;
+
+ if (emulationSpecifier) {
+ QPainterPath polygonPath(points[0]);
+ for (int i=1; i<pointCount; ++i)
+ polygonPath.lineTo(points[i]);
+ polygonPath.closeSubpath();
+ polygonPath.setFillRule(Qt::WindingFill);
+ d->draw_helper(polygonPath);
+ return;
+ }
+
+ d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
+}
+
+void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || pointCount < 2)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ uint emulationSpecifier = d->state->emulationSpecifier;
+
+ if (emulationSpecifier) {
+ QPainterPath polygonPath(points[0]);
+ for (int i=1; i<pointCount; ++i)
+ polygonPath.lineTo(points[i]);
+ polygonPath.closeSubpath();
+ polygonPath.setFillRule(Qt::WindingFill);
+ d->draw_helper(polygonPath);
+ return;
+ }
+
+ d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
+}
+
+/*!
+ \fn void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
+
+ Draws the rectangular portion \a source of the given \a pixmap
+ into the given \a target in the paint device.
+
+ \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
+
+ \table 100%
+ \row
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 16
+ \endtable
+
+ If \a pixmap is a QBitmap it is drawn with the bits that are "set"
+ using the pens color. If backgroundMode is Qt::OpaqueMode, the
+ "unset" bits are drawn using the color of the background brush; if
+ backgroundMode is Qt::TransparentMode, the "unset" bits are
+ transparent. Drawing bitmaps with gradient or texture colors is
+ not supported.
+
+ \sa drawImage()
+*/
+void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
+{
+#if defined QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
+ p.x(), p.y(),
+ pm.width(), pm.height());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || pm.isNull())
+ return;
+
+#ifndef QT_NO_DEBUG
+ qt_painter_thread_test(d->device->devType(), "drawPixmap()");
+#endif
+
+ if (d->extended) {
+ d->extended->drawPixmap(p, pm);
+ return;
+ }
+
+ qreal x = p.x();
+ qreal y = p.y();
+
+ int w = pm.width();
+ int h = pm.height();
+
+ // Emulate opaque background for bitmaps
+ if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
+ fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
+ }
+
+ d->updateState(d->state);
+
+ if ((d->state->matrix.type() > QTransform::TxTranslate
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
+ || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
+ || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
+ {
+ save();
+ // If there is no scaling or transformation involved we have to make sure we use the
+ // antialiased and not the aliased coordinate system by rounding the coordinates.
+ if (d->state->matrix.type() <= QTransform::TxTranslate) {
+ x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
+ y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
+ }
+ translate(x, y);
+ setBackgroundMode(Qt::TransparentMode);
+ setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
+ QBrush brush(d->state->pen.color(), pm);
+ setBrush(brush);
+ setPen(Qt::NoPen);
+ setBrushOrigin(QPointF(0, 0));
+
+ drawRect(pm.rect());
+ restore();
+ } else {
+ if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
+ x += d->state->matrix.dx();
+ y += d->state->matrix.dy();
+ }
+ d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(0, 0, w, h));
+ }
+}
+
+void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
+{
+#if defined QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
+ r.x(), r.y(), r.width(), r.height(),
+ pm.width(), pm.height(),
+ sr.x(), sr.y(), sr.width(), sr.height());
+#endif
+
+ Q_D(QPainter);
+ if (!d->engine || pm.isNull())
+ return;
+#ifndef QT_NO_DEBUG
+ qt_painter_thread_test(d->device->devType(), "drawPixmap()");
+#endif
+
+ qreal x = r.x();
+ qreal y = r.y();
+ qreal w = r.width();
+ qreal h = r.height();
+ qreal sx = sr.x();
+ qreal sy = sr.y();
+ qreal sw = sr.width();
+ qreal sh = sr.height();
+
+ // Sanity-check clipping
+ if (sw <= 0)
+ sw = pm.width() - sx;
+
+ if (sh <= 0)
+ sh = pm.height() - sy;
+
+ if (w < 0)
+ w = sw;
+ if (h < 0)
+ h = sh;
+
+ if (sx < 0) {
+ qreal w_ratio = sx * w/sw;
+ x -= w_ratio;
+ w += w_ratio;
+ sw += sx;
+ sx = 0;
+ }
+
+ if (sy < 0) {
+ qreal h_ratio = sy * h/sh;
+ y -= h_ratio;
+ h += h_ratio;
+ sh += sy;
+ sy = 0;
+ }
+
+ if (sw + sx > pm.width()) {
+ qreal delta = sw - (pm.width() - sx);
+ qreal w_ratio = delta * w/sw;
+ sw -= delta;
+ w -= w_ratio;
+ }
+
+ if (sh + sy > pm.height()) {
+ qreal delta = sh - (pm.height() - sy);
+ qreal h_ratio = delta * h/sh;
+ sh -= delta;
+ h -= h_ratio;
+ }
+
+ if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
+ return;
+
+ if (d->extended) {
+ d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
+ return;
+ }
+
+ // Emulate opaque background for bitmaps
+ if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
+ fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
+
+ d->updateState(d->state);
+
+ if ((d->state->matrix.type() > QTransform::TxTranslate
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
+ || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
+ || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
+ || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
+ {
+ save();
+ // If there is no scaling or transformation involved we have to make sure we use the
+ // antialiased and not the aliased coordinate system by rounding the coordinates.
+ if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
+ x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
+ y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
+ sx = qRound(sx);
+ sy = qRound(sy);
+ sw = qRound(sw);
+ sh = qRound(sh);
+ }
+ translate(x, y);
+ scale(w / sw, h / sh);
+ setBackgroundMode(Qt::TransparentMode);
+ setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
+ QBrush brush(d->state->pen.color(), pm);
+ setBrush(brush);
+ setPen(Qt::NoPen);
+ setBrushOrigin(QPointF(-sx, -sy));
+
+ drawRect(QRectF(0, 0, sw, sh));
+ restore();
+ } else {
+ if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
+ x += d->state->matrix.dx();
+ y += d->state->matrix.dy();
+ }
+ d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
+ }
+}
+
+
+/*!
+ \fn void QPainter::drawPixmap(const QRect &target, const QPixmap &pixmap,
+ const QRect &source)
+ \overload
+
+ Draws the rectangular portion \a source of the given \a pixmap
+ into the given \a target in the paint device.
+
+ \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap,
+ const QRectF &source)
+ \overload
+
+ Draws the rectangular portion \a source of the given \a pixmap
+ with its origin at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap,
+ const QRect &source)
+
+ \overload
+
+ Draws the rectangular portion \a source of the given \a pixmap
+ with its origin at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap)
+ \overload
+
+ Draws the given \a pixmap with its origin at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap)
+ \overload
+
+ Draws the given \a pixmap with its origin at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap)
+
+ \overload
+
+ Draws the given \a pixmap at position (\a{x}, \a{y}).
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(const QRect &rectangle, const QPixmap &pixmap)
+ \overload
+
+ Draws the given \a pixmap into the given \a rectangle.
+
+ \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(int x, int y, int width, int height,
+ const QPixmap &pixmap)
+
+ \overload
+
+ Draws the \a pixmap into the rectangle at position (\a{x}, \a{y})
+ with the given \a width and \a height.
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(int x, int y, int w, int h, const QPixmap &pixmap,
+ int sx, int sy, int sw, int sh)
+
+ \overload
+
+ Draws the rectangular portion with the origin (\a{sx}, \a{sy}),
+ width \a sw and height \a sh, of the given \a pixmap , at the
+ point (\a{x}, \a{y}), with a width of \a w and a height of \a h.
+ If sw or sh are equal to zero the width/height of the pixmap
+ is used and adjusted by the offset sx/sy;
+*/
+
+/*!
+ \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap,
+ int sx, int sy, int sw, int sh)
+
+ \overload
+
+ Draws a pixmap at (\a{x}, \a{y}) by copying a part of the given \a
+ pixmap into the paint device.
+
+ (\a{x}, \a{y}) specifies the top-left point in the paint device that is
+ to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
+ pixmap that is to be drawn. The default is (0, 0).
+
+ (\a{sw}, \a{sh}) specifies the size of the pixmap that is to be drawn.
+ The default, (0, 0) (and negative) means all the way to the
+ bottom-right of the pixmap.
+*/
+
+void QPainter::drawImage(const QPointF &p, const QImage &image)
+{
+ Q_D(QPainter);
+
+ if (!d->engine || image.isNull())
+ return;
+
+ if (d->extended) {
+ d->extended->drawImage(p, image);
+ return;
+ }
+
+ qreal x = p.x();
+ qreal y = p.y();
+
+ int w = image.width();
+ int h = image.height();
+
+ d->updateState(d->state);
+
+ if (((d->state->matrix.type() > QTransform::TxTranslate)
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
+ || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
+ || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
+ {
+ save();
+ // If there is no scaling or transformation involved we have to make sure we use the
+ // antialiased and not the aliased coordinate system by rounding the coordinates.
+ if (d->state->matrix.type() <= QTransform::TxTranslate) {
+ x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
+ y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
+ }
+ translate(x, y);
+ setBackgroundMode(Qt::TransparentMode);
+ setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
+ QBrush brush(image);
+ setBrush(brush);
+ setPen(Qt::NoPen);
+ setBrushOrigin(QPointF(0, 0));
+
+ drawRect(image.rect());
+ restore();
+ return;
+ }
+
+ if (d->state->matrix.type() == QTransform::TxTranslate
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
+ x += d->state->matrix.dx();
+ y += d->state->matrix.dy();
+ }
+
+ d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(0, 0, w, h), Qt::AutoColor);
+}
+
+void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect,
+ Qt::ImageConversionFlags flags)
+{
+ Q_D(QPainter);
+
+ if (!d->engine || image.isNull())
+ return;
+
+ qreal x = targetRect.x();
+ qreal y = targetRect.y();
+ qreal w = targetRect.width();
+ qreal h = targetRect.height();
+ qreal sx = sourceRect.x();
+ qreal sy = sourceRect.y();
+ qreal sw = sourceRect.width();
+ qreal sh = sourceRect.height();
+
+ // Sanity-check clipping
+ if (sw <= 0)
+ sw = image.width() - sx;
+
+ if (sh <= 0)
+ sh = image.height() - sy;
+
+ if (w < 0)
+ w = sw;
+ if (h < 0)
+ h = sh;
+
+ if (sx < 0) {
+ qreal w_ratio = sx * w/sw;
+ x -= w_ratio;
+ w += w_ratio;
+ sw += sx;
+ sx = 0;
+ }
+
+ if (sy < 0) {
+ qreal h_ratio = sy * h/sh;
+ y -= h_ratio;
+ h += h_ratio;
+ sh += sy;
+ sy = 0;
+ }
+
+ if (sw + sx > image.width()) {
+ qreal delta = sw - (image.width() - sx);
+ qreal w_ratio = delta * w/sw;
+ sw -= delta;
+ w -= w_ratio;
+ }
+
+ if (sh + sy > image.height()) {
+ qreal delta = sh - (image.height() - sy);
+ qreal h_ratio = delta * h/sh;
+ sh -= delta;
+ h -= h_ratio;
+ }
+
+ if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
+ return;
+
+ if (d->extended) {
+ d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
+ return;
+ }
+
+ d->updateState(d->state);
+
+ if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
+ || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
+ || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
+ {
+ save();
+ // If there is no scaling or transformation involved we have to make sure we use the
+ // antialiased and not the aliased coordinate system by rounding the coordinates.
+ if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
+ x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
+ y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
+ sx = qRound(sx);
+ sy = qRound(sy);
+ sw = qRound(sw);
+ sh = qRound(sh);
+ }
+ translate(x, y);
+ scale(w / sw, h / sh);
+ setBackgroundMode(Qt::TransparentMode);
+ setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
+ QBrush brush(image);
+ setBrush(brush);
+ setPen(Qt::NoPen);
+ setBrushOrigin(QPointF(-sx, -sy));
+
+ drawRect(QRectF(0, 0, sw, sh));
+ restore();
+ return;
+ }
+
+ if (d->state->matrix.type() == QTransform::TxTranslate
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
+ x += d->state->matrix.dx();
+ y += d->state->matrix.dy();
+ }
+
+ d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
+}
+
+/*!
+ \fn void QPainter::drawText(const QPointF &position, const QString &text)
+
+ Draws the given \a text with the currently defined text direction,
+ beginning at the given \a position.
+
+ This function does not handle the newline character (\n), as it cannot
+ break text into multiple lines, and it cannot display the newline character.
+ Use the QPainter::drawText() overload that takes a rectangle instead
+ if you want to draw multiple lines of text with the newline character, or
+ if you want the text to be wrapped.
+
+ By default, QPainter draws text anti-aliased.
+
+ \note The y-position is used as the baseline of the font.
+*/
+
+void QPainter::drawText(const QPointF &p, const QString &str)
+{
+ drawText(p, str, 0, 0);
+}
+
+/*!
+ \internal
+*/
+void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
+ return;
+
+ QStackTextEngine engine(str, d->state->font);
+ engine.option.setTextDirection(d->state->layoutDirection);
+ if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
+ engine.ignoreBidi = true;
+ engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
+ }
+ engine.itemize();
+ QScriptLine line;
+ line.length = str.length();
+ engine.shapeLine(line);
+
+ int nItems = engine.layoutData->items.size();
+ QVarLengthArray<int> visualOrder(nItems);
+ QVarLengthArray<uchar> levels(nItems);
+ for (int i = 0; i < nItems; ++i)
+ levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
+ QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
+
+ if (justificationPadding > 0) {
+ engine.option.setAlignment(Qt::AlignJustify);
+ engine.forceJustification = true;
+ // this works because justify() is only interested in the difference between width and textWidth
+ line.width = justificationPadding;
+ engine.justify(line);
+ }
+ QFixed x = QFixed::fromReal(p.x());
+ QFixed ox = x;
+
+ for (int i = 0; i < nItems; ++i) {
+ int item = visualOrder[i];
+ const QScriptItem &si = engine.layoutData->items.at(item);
+ if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
+ x += si.width;
+ continue;
+ }
+ QFont f = engine.font(si);
+ QTextItemInt gf(si, &f);
+ gf.glyphs = engine.shapedGlyphs(&si);
+ gf.chars = engine.layoutData->string.unicode() + si.position;
+ gf.num_chars = engine.length(item);
+ gf.width = si.width;
+ gf.logClusters = engine.logClusters(&si);
+
+ drawTextItem(QPointF(x.toReal(), p.y()), gf);
+
+ x += si.width;
+ }
+}
+
+void QPainter::drawText(const QRect &r, int flags, const QString &str, QRect *br)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawText(), r=[%d,%d,%d,%d], flags=%d, str='%s'\n",
+ r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
+ return;
+
+ if (!d->extended)
+ d->updateState(d->state);
+
+ QRectF bounds;
+ qt_format_text(d->state->font, r, flags, 0, str, br ? &bounds : 0, 0, 0, 0, this);
+ if (br)
+ *br = bounds.toAlignedRect();
+}
+
+/*!
+ \fn void QPainter::drawText(const QPoint &position, const QString &text)
+
+ \overload
+
+ Draws the given \a text with the currently defined text direction,
+ beginning at the given \a position.
+
+ By default, QPainter draws text anti-aliased.
+
+ \note The y-position is used as the baseline of the font.
+
+*/
+
+/*!
+ \fn void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect)
+ \overload
+
+ Draws the given \a text within the provided \a rectangle.
+
+ \table 100%
+ \row
+ \o \inlineimage qpainter-text.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 17
+ \endtable
+
+ The \a boundingRect (if not null) is set to the what the bounding rectangle
+ should be in order to enclose the whole text. The \a flags argument is a bitwise
+ OR of the following flags:
+
+ \list
+ \o Qt::AlignLeft
+ \o Qt::AlignRight
+ \o Qt::AlignHCenter
+ \o Qt::AlignJustify
+ \o Qt::AlignTop
+ \o Qt::AlignBottom
+ \o Qt::AlignVCenter
+ \o Qt::AlignCenter
+ \o Qt::TextDontClip
+ \o Qt::TextSingleLine
+ \o Qt::TextExpandTabs
+ \o Qt::TextShowMnemonic
+ \o Qt::TextWordWrap
+ \o Qt::TextIncludeTrailingSpaces
+ \endlist
+
+ \sa Qt::AlignmentFlag, Qt::TextFlag, boundingRect(), layoutDirection()
+
+ By default, QPainter draws text anti-aliased.
+
+ \note The y-coordinate of \a rectangle is used as the top of the font.
+*/
+void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *br)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], flags=%d, str='%s'\n",
+ r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
+ return;
+
+ if (!d->extended)
+ d->updateState(d->state);
+
+ qt_format_text(d->state->font, r, flags, 0, str, br, 0, 0, 0, this);
+}
+
+/*!
+ \fn void QPainter::drawText(const QRect &rectangle, int flags, const QString &text, QRect *boundingRect)
+ \overload
+
+ Draws the given \a text within the provided \a rectangle according
+ to the specified \a flags. The \a boundingRect (if not null) is set to
+ the what the bounding rectangle should be in order to enclose the whole text.
+
+ By default, QPainter draws text anti-aliased.
+
+ \note The y-coordinate of \a rectangle is used as the top of the font.
+*/
+
+/*!
+ \fn void QPainter::drawText(int x, int y, const QString &text)
+
+ \overload
+
+ Draws the given \a text at position (\a{x}, \a{y}), using the painter's
+ currently defined text direction.
+
+ By default, QPainter draws text anti-aliased.
+
+ \note The y-position is used as the baseline of the font.
+
+*/
+
+/*!
+ \fn void QPainter::drawText(int x, int y, int width, int height, int flags,
+ const QString &text, QRect *boundingRect)
+
+ \overload
+
+ Draws the given \a text within the rectangle with origin (\a{x},
+ \a{y}), \a width and \a height.
+
+ The \a boundingRect (if not null) is set to the actual bounding
+ rectangle of the output. The \a flags argument is a bitwise OR of
+ the following flags:
+
+ \list
+ \o Qt::AlignLeft
+ \o Qt::AlignRight
+ \o Qt::AlignHCenter
+ \o Qt::AlignJustify
+ \o Qt::AlignTop
+ \o Qt::AlignBottom
+ \o Qt::AlignVCenter
+ \o Qt::AlignCenter
+ \o Qt::TextSingleLine
+ \o Qt::TextExpandTabs
+ \o Qt::TextShowMnemonic
+ \o Qt::TextWordWrap
+ \endlist
+
+ By default, QPainter draws text anti-aliased.
+
+ \note The y-position is used as the baseline of the font.
+
+ \sa Qt::AlignmentFlag, Qt::TextFlag
+*/
+
+/*!
+ \fn void QPainter::drawText(const QRectF &rectangle, const QString &text,
+ const QTextOption &option)
+ \overload
+
+ Draws the given \a text in the \a rectangle specified using the \a option
+ to control its positioning and orientation.
+
+ By default, QPainter draws text anti-aliased.
+
+ \note The y-coordinate of \a rectangle is used as the top of the font.
+*/
+void QPainter::drawText(const QRectF &r, const QString &text, const QTextOption &o)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], str='%s'\n",
+ r.x(), r.y(), r.width(), r.height(), text.toLatin1().constData());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine || text.length() == 0 || pen().style() == Qt::NoPen)
+ return;
+
+ if (!d->extended)
+ d->updateState(d->state);
+
+ qt_format_text(d->state->font, r, 0, &o, text, 0, 0, 0, 0, this);
+}
+
+/*!
+ \fn void QPainter::drawTextItem(int x, int y, const QTextItem &ti)
+
+ \internal
+ \overload
+*/
+
+/*!
+ \fn void QPainter::drawTextItem(const QPoint &p, const QTextItem &ti)
+
+ \internal
+ \overload
+
+ Draws the text item \a ti at position \a p.
+*/
+
+/*! \internal
+ Draws the text item \a ti at position \a p.
+
+ This method ignores the painters background mode and
+ color. drawText and qt_format_text have to do it themselves, as
+ only they know the extents of the complete string.
+
+ It ignores the font set on the painter as the text item has one of its own.
+
+ The underline and strikeout parameters of the text items font are
+ ignored aswell. You'll need to pass in the correct flags to get
+ underlining and strikeout.
+*/
+static QPainterPath generateWavyPath(qreal minWidth, qreal maxRadius, QPaintDevice *device)
+{
+ extern int qt_defaultDpi();
+ QPainterPath path;
+
+ bool up = true;
+ const qreal radius = qMax(qreal(.5), qMin(qreal(1.25 * device->logicalDpiY() / qt_defaultDpi()), maxRadius));
+ qreal xs, ys;
+ int i = 0;
+ path.moveTo(0, radius);
+ do {
+ xs = i*(2*radius);
+ ys = 0;
+
+ qreal remaining = minWidth - xs;
+ qreal angle = 180;
+
+ // cut-off at the last arc segment
+ if (remaining < 2 * radius)
+ angle = 180 * remaining / (2 * radius);
+
+ path.arcTo(xs, ys, 2*radius, 2*radius, 180, up ? angle : -angle);
+
+ up = !up;
+ ++i;
+ } while (xs + 2*radius < minWidth);
+
+ return path;
+}
+
+static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QTextItemInt &ti)
+{
+ QTextCharFormat::UnderlineStyle underlineStyle = ti.underlineStyle;
+ if (underlineStyle == QTextCharFormat::NoUnderline
+ && !(ti.flags & (QTextItem::StrikeOut | QTextItem::Overline)))
+ return;
+
+ QFontEngine *fe = ti.fontEngine;
+
+ const QPen oldPen = painter->pen();
+ const QBrush oldBrush = painter->brush();
+ painter->setBrush(Qt::NoBrush);
+ QPen pen = oldPen;
+ pen.setStyle(Qt::SolidLine);
+ pen.setWidthF(fe->lineThickness().toReal());
+ pen.setCapStyle(Qt::FlatCap);
+
+ QLineF line(pos.x(), pos.y(), pos.x() + ti.width.toReal(), pos.y());
+ // deliberately ceil the offset to avoid the underline coming too close to
+ // the text above it.
+ const qreal underlinePos = pos.y() + qCeil(fe->underlinePosition().toReal());
+
+ if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
+ underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle));
+ }
+
+ if (underlineStyle == QTextCharFormat::WaveUnderline) {
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->translate(pos.x(), underlinePos);
+
+ QColor uc = ti.charFormat.underlineColor();
+ if (uc.isValid())
+ painter->setPen(uc);
+
+ painter->drawPath(generateWavyPath(ti.width.toReal(),
+ fe->underlinePosition().toReal(),
+ painter->device()));
+ painter->restore();
+ } else if (underlineStyle != QTextCharFormat::NoUnderline) {
+ QLineF underLine(line.x1(), underlinePos, line.x2(), underlinePos);
+
+ QColor uc = ti.charFormat.underlineColor();
+ if (uc.isValid())
+ pen.setColor(uc);
+
+ pen.setStyle((Qt::PenStyle)(underlineStyle));
+ painter->setPen(pen);
+ painter->drawLine(underLine);
+ }
+
+ pen.setStyle(Qt::SolidLine);
+ pen.setColor(oldPen.color());
+
+ if (ti.flags & QTextItem::StrikeOut) {
+ QLineF strikeOutLine = line;
+ strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
+ painter->setPen(pen);
+ painter->drawLine(strikeOutLine);
+ }
+
+ if (ti.flags & QTextItem::Overline) {
+ QLineF overLine = line;
+ overLine.translate(0., - fe->ascent().toReal());
+ painter->setPen(pen);
+ painter->drawLine(overLine);
+ }
+
+ painter->setPen(oldPen);
+ painter->setBrush(oldBrush);
+}
+
+/*!
+ \internal
+ \since 4.1
+*/
+void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
+ p.x(), p.y(), qPrintable(_ti.text()));
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+#ifndef QT_NO_DEBUG
+ qt_painter_thread_test(d->device->devType(),
+ "text and fonts",
+ QFontDatabase::supportsThreadedFontRendering());
+#endif
+
+ QTextItemInt &ti = const_cast<QTextItemInt &>(static_cast<const QTextItemInt &>(_ti));
+
+ if (!d->extended && d->state->bgMode == Qt::OpaqueMode) {
+ QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal());
+ fillRect(rect, d->state->bgBrush);
+ }
+
+ if (pen().style() == Qt::NoPen)
+ return;
+
+ const RenderHints oldRenderHints = d->state->renderHints;
+ if (!d->state->renderHints & QPainter::Antialiasing && d->state->matrix.type() >= QTransform::TxScale) {
+ // draw antialias decoration (underline/overline/strikeout) with
+ // transformed text
+
+ bool aa = true;
+ const QTransform &m = d->state->matrix;
+ if (d->state->matrix.type() < QTransform::TxShear) {
+ bool isPlain90DegreeRotation =
+ (qFuzzyCompare(m.m11() + 1, qreal(1))
+ && qFuzzyCompare(m.m12(), qreal(1))
+ && qFuzzyCompare(m.m21(), qreal(-1))
+ && qFuzzyCompare(m.m22() + 1, qreal(1))
+ )
+ ||
+ (qFuzzyCompare(m.m11(), qreal(-1))
+ && qFuzzyCompare(m.m12() + 1, qreal(1))
+ && qFuzzyCompare(m.m21() + 1, qreal(1))
+ && qFuzzyCompare(m.m22(), qreal(-1))
+ )
+ ||
+ (qFuzzyCompare(m.m11() + 1, qreal(1))
+ && qFuzzyCompare(m.m12(), qreal(-1))
+ && qFuzzyCompare(m.m21(), qreal(1))
+ && qFuzzyCompare(m.m22() + 1, qreal(1))
+ )
+ ;
+ aa = !isPlain90DegreeRotation;
+ }
+ if (aa)
+ setRenderHint(QPainter::Antialiasing, true);
+ }
+
+ if (!d->extended)
+ d->updateState(d->state);
+
+ if (!ti.glyphs.numGlyphs) {
+ // nothing to do
+ } else if (ti.fontEngine->type() == QFontEngine::Multi) {
+ QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
+
+ const QGlyphLayout &glyphs = ti.glyphs;
+ int which = glyphs.glyphs[0] >> 24;
+
+ qreal x = p.x();
+ qreal y = p.y();
+
+ int start = 0;
+ int end, i;
+ for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
+ const int e = glyphs.glyphs[end] >> 24;
+ if (e == which)
+ continue;
+
+
+ QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
+ ti2.width = 0;
+ // set the high byte to zero and calc the width
+ for (i = start; i < end; ++i) {
+ glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
+ ti2.width += ti.glyphs.effectiveAdvance(i);
+ }
+
+ d->engine->drawTextItem(QPointF(x, y), ti2);
+
+ // reset the high byte for all glyphs and advance to the next sub-string
+ const int hi = which << 24;
+ for (i = start; i < end; ++i) {
+ glyphs.glyphs[i] = hi | glyphs.glyphs[i];
+ }
+ x += ti2.width.toReal();
+
+ // change engine
+ start = end;
+ which = e;
+ }
+
+ QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
+ ti2.width = 0;
+ // set the high byte to zero and calc the width
+ for (i = start; i < end; ++i) {
+ glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
+ ti2.width += ti.glyphs.effectiveAdvance(i);
+ }
+
+ if (d->extended)
+ d->extended->drawTextItem(QPointF(x, y), ti2);
+ else
+ d->engine->drawTextItem(QPointF(x,y), ti2);
+
+ // reset the high byte for all glyphs
+ const int hi = which << 24;
+ for (i = start; i < end; ++i)
+ glyphs.glyphs[i] = hi | glyphs.glyphs[i];
+
+ } else {
+ if (d->extended)
+ d->extended->drawTextItem(p, ti);
+ else
+ d->engine->drawTextItem(p, ti);
+ }
+ drawTextItemDecoration(this, p, ti);
+
+ if (d->state->renderHints != oldRenderHints) {
+ d->state->renderHints = oldRenderHints;
+ if (d->extended)
+ d->extended->renderHintsChanged();
+ else
+ d->state->dirtyFlags |= QPaintEngine::DirtyHints;
+ }
+}
+
+/*!
+ \fn QRectF QPainter::boundingRect(const QRectF &rectangle, int flags, const QString &text)
+
+ Returns the bounding rectangle of the \a text as it will appear
+ when drawn inside the given \a rectangle with the specified \a
+ flags using the currently set font(); i.e the function tells you
+ where the drawText() function will draw when given the same
+ arguments.
+
+ If the \a text does not fit within the given \a rectangle using
+ the specified \a flags, the function returns the required
+ rectangle.
+
+ The \a flags argument is a bitwise OR of the following flags:
+ \list
+ \o Qt::AlignLeft
+ \o Qt::AlignRight
+ \o Qt::AlignHCenter
+ \o Qt::AlignTop
+ \o Qt::AlignBottom
+ \o Qt::AlignVCenter
+ \o Qt::AlignCenter
+ \o Qt::TextSingleLine
+ \o Qt::TextExpandTabs
+ \o Qt::TextShowMnemonic
+ \o Qt::TextWordWrap
+ \o Qt::TextIncludeTrailingSpaces
+ \endlist
+ If several of the horizontal or several of the vertical alignment
+ flags are set, the resulting alignment is undefined.
+
+ \sa drawText(), Qt::Alignment, Qt::TextFlag
+*/
+
+/*!
+ \fn QRect QPainter::boundingRect(const QRect &rectangle, int flags,
+ const QString &text)
+
+ \overload
+
+ Returns the bounding rectangle of the \a text as it will appear
+ when drawn inside the given \a rectangle with the specified \a
+ flags using the currently set font().
+*/
+
+/*!
+ \fn QRect QPainter::boundingRect(int x, int y, int w, int h, int flags,
+ const QString &text);
+
+ \overload
+
+ Returns the bounding rectangle of the given \a text as it will
+ appear when drawn inside the rectangle beginning at the point
+ (\a{x}, \a{y}) with width \a w and height \a h.
+*/
+QRect QPainter::boundingRect(const QRect &rect, int flags, const QString &str)
+{
+ if (str.isEmpty())
+ return QRect(rect.x(),rect.y(), 0,0);
+ QRect brect;
+ drawText(rect, flags | Qt::TextDontPrint, str, &brect);
+ return brect;
+}
+
+
+
+QRectF QPainter::boundingRect(const QRectF &rect, int flags, const QString &str)
+{
+ if (str.isEmpty())
+ return QRectF(rect.x(),rect.y(), 0,0);
+ QRectF brect;
+ drawText(rect, flags | Qt::TextDontPrint, str, &brect);
+ return brect;
+}
+
+/*!
+ \fn QRectF QPainter::boundingRect(const QRectF &rectangle,
+ const QString &text, const QTextOption &option)
+
+ \overload
+
+ Instead of specifying flags as a bitwise OR of the
+ Qt::AlignmentFlag and Qt::TextFlag, this overloaded function takes
+ an \a option argument. The QTextOption class provides a
+ description of general rich text properties.
+
+ \sa QTextOption
+*/
+QRectF QPainter::boundingRect(const QRectF &r, const QString &text, const QTextOption &o)
+{
+ Q_D(QPainter);
+
+ if (!d->engine || text.length() == 0)
+ return QRectF(r.x(),r.y(), 0,0);
+
+ QRectF br;
+ qt_format_text(d->state->font, r, Qt::TextDontPrint, &o, text, &br, 0, 0, 0, this);
+ return br;
+}
+
+/*!
+ \fn void QPainter::drawTiledPixmap(const QRectF &rectangle, const QPixmap &pixmap, const QPointF &position)
+
+ Draws a tiled \a pixmap, inside the given \a rectangle with its
+ origin at the given \a position.
+
+ Calling drawTiledPixmap() is similar to calling drawPixmap()
+ several times to fill (tile) an area with a pixmap, but is
+ potentially much more efficient depending on the underlying window
+ system.
+
+ \sa drawPixmap()
+*/
+void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sp)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
+ r.x(), r.y(), r.width(), r.height(),
+ pixmap.width(), pixmap.height(),
+ sp.x(), sp.y());
+#endif
+
+ Q_D(QPainter);
+ if (!d->engine || pixmap.isNull() || r.isEmpty())
+ return;
+
+#ifndef QT_NO_DEBUG
+ qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()");
+#endif
+
+ qreal sw = pixmap.width();
+ qreal sh = pixmap.height();
+ qreal sx = sp.x();
+ qreal sy = sp.y();
+ if (sx < 0)
+ sx = qRound(sw) - qRound(-sx) % qRound(sw);
+ else
+ sx = qRound(sx) % qRound(sw);
+ if (sy < 0)
+ sy = qRound(sh) - -qRound(sy) % qRound(sh);
+ else
+ sy = qRound(sy) % qRound(sh);
+
+
+ if (d->extended) {
+ d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
+ return;
+ }
+
+ if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
+ fillRect(r, d->state->bgBrush);
+
+ d->updateState(d->state);
+ if ((d->state->matrix.type() > QTransform::TxTranslate
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
+ || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
+ {
+ save();
+ setBackgroundMode(Qt::TransparentMode);
+ setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
+ setBrush(QBrush(d->state->pen.color(), pixmap));
+ setPen(Qt::NoPen);
+
+ // If there is no scaling or transformation involved we have to make sure we use the
+ // antialiased and not the aliased coordinate system by rounding the coordinates.
+ if (d->state->matrix.type() <= QTransform::TxTranslate) {
+ qreal x = qRound(r.x() + d->state->matrix.dx()) - d->state->matrix.dx();
+ qreal y = qRound(r.y() + d->state->matrix.dy()) - d->state->matrix.dy();
+ qreal w = qRound(r.width());
+ qreal h = qRound(r.height());
+ sx = qRound(sx);
+ sy = qRound(sy);
+ setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
+ drawRect(QRectF(x, y, w, h));
+ } else {
+ setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
+ drawRect(r);
+ }
+ restore();
+ return;
+ }
+
+ qreal x = r.x();
+ qreal y = r.y();
+ if (d->state->matrix.type() == QTransform::TxTranslate
+ && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
+ x += d->state->matrix.dx();
+ y += d->state->matrix.dy();
+ }
+
+ d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
+}
+
+/*!
+ \fn QPainter::drawTiledPixmap(const QRect &rectangle, const QPixmap &pixmap,
+ const QPoint &position = QPoint())
+ \overload
+
+ Draws a tiled \a pixmap, inside the given \a rectangle with its
+ origin at the given \a position.
+*/
+
+/*!
+ \fn void QPainter::drawTiledPixmap(int x, int y, int width, int height, const
+ QPixmap &pixmap, int sx, int sy);
+ \overload
+
+ Draws a tiled \a pixmap in the specified rectangle.
+
+ (\a{x}, \a{y}) specifies the top-left point in the paint device
+ that is to be drawn onto; with the given \a width and \a
+ height. (\a{sx}, \a{sy}) specifies the top-left point in the \a
+ pixmap that is to be drawn; this defaults to (0, 0).
+*/
+
+#ifndef QT_NO_PICTURE
+
+/*!
+ \fn void QPainter::drawPicture(const QPointF &point, const QPicture &picture)
+
+ Replays the given \a picture at the given \a point.
+
+ The QPicture class is a paint device that records and replays
+ QPainter commands. A picture serializes the painter commands to an
+ IO device in a platform-independent format. Everything that can be
+ painted on a widget or pixmap can also be stored in a picture.
+
+ This function does exactly the same as QPicture::play() when
+ called with \a point = QPoint(0, 0).
+
+ \table 100%
+ \row
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 18
+ \endtable
+
+ \sa QPicture::play()
+*/
+
+void QPainter::drawPicture(const QPointF &p, const QPicture &picture)
+{
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (!d->extended)
+ d->updateState(d->state);
+
+ save();
+ translate(p);
+ const_cast<QPicture *>(&picture)->play(this);
+ restore();
+}
+
+/*!
+ \fn void QPainter::drawPicture(const QPoint &point, const QPicture &picture)
+ \overload
+
+ Replays the given \a picture at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawPicture(int x, int y, const QPicture &picture)
+ \overload
+
+ Draws the given \a picture at point (\a x, \a y).
+*/
+
+#endif // QT_NO_PICTURE
+
+/*!
+ \fn void QPainter::eraseRect(const QRectF &rectangle)
+
+ Erases the area inside the given \a rectangle. Equivalent to
+ calling
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 19
+
+ \sa fillRect()
+*/
+void QPainter::eraseRect(const QRectF &r)
+{
+ Q_D(QPainter);
+
+ fillRect(r, d->state->bgBrush);
+}
+
+static inline bool needsResolving(const QBrush &brush)
+{
+ Qt::BrushStyle s = brush.style();
+ return ((s == Qt::LinearGradientPattern || s == Qt::RadialGradientPattern ||
+ s == Qt::ConicalGradientPattern) &&
+ brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode);
+}
+
+/*!
+ \fn void QPainter::eraseRect(const QRect &rectangle)
+ \overload
+
+ Erases the area inside the given \a rectangle.
+*/
+
+/*!
+ \fn void QPainter::eraseRect(int x, int y, int width, int height)
+ \overload
+
+ Erases the area inside the rectangle beginning at (\a x, \a y)
+ with the given \a width and \a height.
+*/
+
+
+/*!
+ \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::BrushStyle style)
+ \overload
+
+ Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
+ width and \a height, using the brush \a style specified.
+
+ \since 4.5
+*/
+
+/*!
+ \fn void QPainter::fillRect(const QRect &rectangle, Qt::BrushStyle style)
+ \overload
+
+ Fills the given \a rectangle with the brush \a style specified.
+
+ \since 4.5
+*/
+
+/*!
+ \fn void QPainter::fillRect(const QRectF &rectangle, Qt::BrushStyle style)
+ \overload
+
+ Fills the given \a rectangle with the brush \a style specified.
+
+ \since 4.5
+*/
+
+/*!
+ \fn void QPainter::fillRect(const QRectF &rectangle, const QBrush &brush)
+
+ Fills the given \a rectangle with the \a brush specified.
+
+ Alternatively, you can specify a QColor instead of a QBrush; the
+ QBrush constructor (taking a QColor argument) will automatically
+ create a solid pattern brush.
+
+ \sa drawRect()
+*/
+void QPainter::fillRect(const QRectF &r, const QBrush &brush)
+{
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (d->extended) {
+ const QGradient *g = brush.gradient();
+ if (!g || g->coordinateMode() == QGradient::LogicalMode) {
+ d->extended->fillRect(r, brush);
+ return;
+ }
+ }
+
+ QPen oldPen = pen();
+ QBrush oldBrush = this->brush();
+ setPen(Qt::NoPen);
+ if (brush.style() == Qt::SolidPattern) {
+ d->colorBrush.setStyle(Qt::SolidPattern);
+ d->colorBrush.setColor(brush.color());
+ setBrush(d->colorBrush);
+ } else {
+ setBrush(brush);
+ }
+
+ drawRect(r);
+ setBrush(oldBrush);
+ setPen(oldPen);
+}
+
+/*!
+ \fn void QPainter::fillRect(const QRect &rectangle, const QBrush &brush)
+ \overload
+
+ Fills the given \a rectangle with the specified \a brush.
+*/
+
+void QPainter::fillRect(const QRect &r, const QBrush &brush)
+{
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (d->extended) {
+ const QGradient *g = brush.gradient();
+ if (!g || g->coordinateMode() == QGradient::LogicalMode) {
+ d->extended->fillRect(r, brush);
+ return;
+ }
+ }
+
+ QPen oldPen = pen();
+ QBrush oldBrush = this->brush();
+ setPen(Qt::NoPen);
+ if (brush.style() == Qt::SolidPattern) {
+ d->colorBrush.setStyle(Qt::SolidPattern);
+ d->colorBrush.setColor(brush.color());
+ setBrush(d->colorBrush);
+ } else {
+ setBrush(brush);
+ }
+
+ drawRect(r);
+ setBrush(oldBrush);
+ setPen(oldPen);
+}
+
+
+
+/*!
+ \fn void QPainter::fillRect(const QRect &rectangle, const QColor &color)
+ \overload
+
+ Fills the given \a rectangle with the \a color specified.
+
+ \since 4.5
+*/
+void QPainter::fillRect(const QRect &r, const QColor &color)
+{
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (d->extended) {
+ d->extended->fillRect(r, color);
+ return;
+ }
+
+ fillRect(r, QBrush(color));
+}
+
+
+/*!
+ \fn void QPainter::fillRect(const QRectF &rectangle, const QColor &color)
+ \overload
+
+ Fills the given \a rectangle with the \a color specified.
+
+ \since 4.5
+*/
+void QPainter::fillRect(const QRectF &r, const QColor &color)
+{
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if (d->extended) {
+ d->extended->fillRect(r, color);
+ return;
+ }
+
+ fillRect(r, QBrush(color));
+}
+
+/*!
+ \fn void QPainter::fillRect(int x, int y, int width, int height, const QBrush &brush)
+
+ \overload
+
+ Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
+ width and \a height, using the given \a brush.
+*/
+
+/*!
+ \fn void QPainter::fillRect(int x, int y, int width, int height, const QColor &color)
+
+ \overload
+
+ Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
+ width and \a height, using the given \a color.
+
+ \since 4.5
+*/
+
+/*!
+ \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::GlobalColor color)
+
+ \overload
+
+ Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
+ width and \a height, using the given \a color.
+
+ \since 4.5
+*/
+
+/*!
+ \fn void QPainter::fillRect(const QRect &rectangle, Qt::GlobalColor color);
+
+ \overload
+
+ Fills the given \a rectangle with the specified \a color.
+
+ \since 4.5
+*/
+
+/*!
+ \fn void QPainter::fillRect(const QRectF &rectangle, Qt::GlobalColor color);
+
+ \overload
+
+ Fills the given \a rectangle with the specified \a color.
+
+ \since 4.5
+*/
+
+/*!
+ Sets the given render \a hint on the painter if \a on is true;
+ otherwise clears the render hint.
+
+ \sa setRenderHints(), renderHints(), {QPainter#Rendering
+ Quality}{Rendering Quality}
+*/
+void QPainter::setRenderHint(RenderHint hint, bool on)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setRenderHint: hint=%x, %s\n", hint, on ? "on" : "off");
+#endif
+
+#ifndef QT_NO_DEBUG
+ static const bool antialiasingDisabled = qgetenv("QT_NO_ANTIALIASING").toInt();
+ if (hint == QPainter::Antialiasing && antialiasingDisabled)
+ return;
+#endif
+
+ setRenderHints(hint, on);
+}
+
+/*!
+ \since 4.2
+
+ Sets the given render \a hints on the painter if \a on is true;
+ otherwise clears the render hints.
+
+ \sa setRenderHint(), renderHints(), {QPainter#Rendering
+ Quality}{Rendering Quality}
+*/
+
+void QPainter::setRenderHints(RenderHints hints, bool on)
+{
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setRenderHint: Painter must be active to set rendering hints");
+ return;
+ }
+
+ if (on)
+ d->state->renderHints |= hints;
+ else
+ d->state->renderHints &= ~hints;
+
+ if (d->extended)
+ d->extended->renderHintsChanged();
+ else
+ d->state->dirtyFlags |= QPaintEngine::DirtyHints;
+}
+
+/*!
+ Returns a flag that specifies the rendering hints that are set for
+ this painter.
+
+ \sa testRenderHint(), {QPainter#Rendering Quality}{Rendering Quality}
+*/
+QPainter::RenderHints QPainter::renderHints() const
+{
+ Q_D(const QPainter);
+
+ if (!d->engine)
+ return 0;
+
+ return d->state->renderHints;
+}
+
+/*!
+ \fn bool QPainter::testRenderHint(RenderHint hint) const
+ \since 4.3
+
+ Returns true if \a hint is set; otherwise returns false.
+
+ \sa renderHints(), setRenderHint()
+*/
+
+/*!
+ Returns true if view transformation is enabled; otherwise returns
+ false.
+
+ \sa setViewTransformEnabled(), worldMatrix()
+*/
+
+bool QPainter::viewTransformEnabled() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::viewTransformEnabled: Painter not active");
+ return false;
+ }
+ return d->state->VxF;
+}
+
+/*!
+ \fn void QPainter::setWindow(const QRect &rectangle)
+
+ Sets the painter's window to the given \a rectangle, and enables
+ view transformations.
+
+ The window rectangle is part of the view transformation. The
+ window specifies the logical coordinate system. Its sister, the
+ viewport(), specifies the device coordinate system.
+
+ The default window rectangle is the same as the device's
+ rectangle.
+
+ \sa window(), viewTransformEnabled(), {The Coordinate
+ System#Window-Viewport Conversion}{Window-Viewport Conversion}
+*/
+
+/*!
+ \fn void QPainter::setWindow(int x, int y, int width, int height)
+ \overload
+
+ Sets the painter's window to the rectangle beginning at (\a x, \a
+ y) and the given \a width and \a height.
+*/
+
+void QPainter::setWindow(const QRect &r)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setWindow(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setWindow: Painter not active");
+ return;
+ }
+
+ d->state->wx = r.x();
+ d->state->wy = r.y();
+ d->state->ww = r.width();
+ d->state->wh = r.height();
+
+ d->state->VxF = true;
+ d->updateMatrix();
+}
+
+/*!
+ Returns the window rectangle.
+
+ \sa setWindow(), setViewTransformEnabled()
+*/
+
+QRect QPainter::window() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::window: Painter not active");
+ return QRect();
+ }
+ return QRect(d->state->wx, d->state->wy, d->state->ww, d->state->wh);
+}
+
+/*!
+ \fn void QPainter::setViewport(const QRect &rectangle)
+
+ Sets the painter's viewport rectangle to the given \a rectangle,
+ and enables view transformations.
+
+ The viewport rectangle is part of the view transformation. The
+ viewport specifies the device coordinate system. Its sister, the
+ window(), specifies the logical coordinate system.
+
+ The default viewport rectangle is the same as the device's
+ rectangle.
+
+ \sa viewport(), viewTransformEnabled() {The Coordinate
+ System#Window-Viewport Conversion}{Window-Viewport Conversion}
+*/
+
+/*!
+ \fn void QPainter::setViewport(int x, int y, int width, int height)
+ \overload
+
+ Sets the painter's viewport rectangle to be the rectangle
+ beginning at (\a x, \a y) with the given \a width and \a height.
+*/
+
+void QPainter::setViewport(const QRect &r)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setViewport(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setViewport: Painter not active");
+ return;
+ }
+
+ d->state->vx = r.x();
+ d->state->vy = r.y();
+ d->state->vw = r.width();
+ d->state->vh = r.height();
+
+ d->state->VxF = true;
+ d->updateMatrix();
+}
+
+/*!
+ Returns the viewport rectangle.
+
+ \sa setViewport(), setViewTransformEnabled()
+*/
+
+QRect QPainter::viewport() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::viewport: Painter not active");
+ return QRect();
+ }
+ return QRect(d->state->vx, d->state->vy, d->state->vw, d->state->vh);
+}
+
+/*! \fn bool QPainter::hasViewXForm() const
+ \compat
+
+ Use viewTransformEnabled() instead.
+*/
+
+/*! \fn bool QPainter::hasWorldXForm() const
+ \compat
+
+ Use worldMatrixEnabled() instead.
+*/
+
+/*! \fn void QPainter::resetXForm()
+ \compat
+
+ Use resetMatrix() instead.
+*/
+
+/*! \fn void QPainter::setViewXForm(bool enabled)
+ \compat
+
+ Use setViewTransformEnabled() instead.
+*/
+
+/*! \fn void QPainter::setWorldXForm(bool enabled)
+ \compat
+
+ Use setWorldMatrixEnabled() instead.
+*/
+/*!
+ Enables view transformations if \a enable is true, or disables
+ view transformations if \a enable is false.
+
+ \sa viewTransformEnabled(), {The Coordinate System#Window-Viewport
+ Conversion}{Window-Viewport Conversion}
+*/
+
+void QPainter::setViewTransformEnabled(bool enable)
+{
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::setViewTransformEnabled(), enable=%d\n", enable);
+#endif
+
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setViewTransformEnabled: Painter not active");
+ return;
+ }
+
+ if (enable == d->state->VxF)
+ return;
+
+ d->state->VxF = enable;
+ d->updateMatrix();
+}
+
+#ifdef QT3_SUPPORT
+
+/*!
+ Use the worldMatrix() combined with QMatrix::dx() instead.
+
+ \oldcode
+ QPainter painter(this);
+ qreal x = painter.translationX();
+ \newcode
+ QPainter painter(this);
+ qreal x = painter.worldMatrix().dx();
+ \endcode
+*/
+qreal QPainter::translationX() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::translationX: Painter not active");
+ return 0.0;
+ }
+ return d->state->worldMatrix.dx();
+}
+
+/*!
+ Use the worldMatrix() combined with QMatrix::dy() instead.
+
+ \oldcode
+ QPainter painter(this);
+ qreal y = painter.translationY();
+ \newcode
+ QPainter painter(this);
+ qreal y = painter.worldMatrix().dy();
+ \endcode
+*/
+qreal QPainter::translationY() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::translationY: Painter not active");
+ return 0.0;
+ }
+ return d->state->worldMatrix.dy();
+}
+
+/*!
+ \fn void QPainter::map(int x, int y, int *rx, int *ry) const
+
+ \internal
+
+ Sets (\a{rx}, \a{ry}) to the point that results from applying the
+ painter's current transformation on the point (\a{x}, \a{y}).
+*/
+void QPainter::map(int x, int y, int *rx, int *ry) const
+{
+ QPoint p(x, y);
+ p = p * combinedMatrix();
+ *rx = p.x();
+ *ry = p.y();
+}
+
+/*!
+ \fn QPoint QPainter::xForm(const QPoint &point) const
+
+ Use combinedTransform() instead.
+*/
+
+QPoint QPainter::xForm(const QPoint &p) const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::xForm: Painter not active");
+ return QPoint();
+ }
+ if (d->state->matrix.type() == QTransform::TxNone)
+ return p;
+ return p * combinedMatrix();
+}
+
+
+/*!
+ \fn QRect QPainter::xForm(const QRect &rectangle) const
+ \overload
+
+ Use combinedTransform() instead of this function and call
+ mapRect() on the result to obtain a QRect.
+*/
+
+QRect QPainter::xForm(const QRect &r) const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::xForm: Painter not active");
+ return QRect();
+ }
+ if (d->state->matrix.type() == QTransform::TxNone)
+ return r;
+ return combinedMatrix().mapRect(r);
+}
+
+/*!
+ \fn QPolygon QPainter::xForm(const QPolygon &polygon) const
+ \overload
+
+ Use combinedTransform() instead.
+*/
+
+QPolygon QPainter::xForm(const QPolygon &a) const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::xForm: Painter not active");
+ return QPolygon();
+ }
+ if (d->state->matrix.type() == QTransform::TxNone)
+ return a;
+ return a * combinedMatrix();
+}
+
+/*!
+ \fn QPolygon QPainter::xForm(const QPolygon &polygon, int index, int count) const
+ \overload
+
+ Use combinedTransform() combined with QPolygon::mid() instead.
+
+ \oldcode
+ QPainter painter(this);
+ QPolygon transformed = painter.xForm(polygon, index, count)
+ \newcode
+ QPainter painter(this);
+ QPolygon transformed = polygon.mid(index, count) * painter.combinedMatrix();
+ \endcode
+*/
+
+QPolygon QPainter::xForm(const QPolygon &av, int index, int npoints) const
+{
+ int lastPoint = npoints < 0 ? av.size() : index+npoints;
+ QPolygon a(lastPoint-index);
+ memcpy(a.data(), av.data()+index, (lastPoint-index)*sizeof(QPoint));
+ return a * combinedMatrix();
+}
+
+/*!
+ \fn QPoint QPainter::xFormDev(const QPoint &point) const
+ \overload
+
+ Use combinedTransform() combined with QMatrix::inverted() instead.
+
+ \oldcode
+ QPainter painter(this);
+ QPoint transformed = painter.xFormDev(point);
+ \newcode
+ QPainter painter(this);
+ QPoint transformed = point * painter.combinedMatrix().inverted();
+ \endcode
+*/
+
+QPoint QPainter::xFormDev(const QPoint &p) const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::xFormDev: Painter not active");
+ return QPoint();
+ }
+ if(d->state->matrix.type() == QTransform::TxNone)
+ return p;
+ return p * combinedMatrix().inverted();
+}
+
+/*!
+ \fn QRect QPainter::xFormDev(const QRect &rectangle) const
+ \overload
+
+ Use combineMatrix() combined with QMatrix::inverted() instead.
+
+ \oldcode
+ QPainter painter(this);
+ QRect transformed = painter.xFormDev(rectangle);
+ \newcode
+ QPainter painter(this);
+ QRect transformed = rectangle * painter.combinedMatrix().inverted();
+ \endcode
+*/
+
+QRect QPainter::xFormDev(const QRect &r) const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::xFormDev: Painter not active");
+ return QRect();
+ }
+ if (d->state->matrix.type() == QTransform::TxNone)
+ return r;
+ return combinedMatrix().inverted().mapRect(r);
+}
+
+/*!
+ \overload
+
+ \fn QPoint QPainter::xFormDev(const QPolygon &polygon) const
+ \overload
+
+ Use combinedMatrix() combined with QMatrix::inverted() instead.
+
+ \oldcode
+ QPainter painter(this);
+ QPolygon transformed = painter.xFormDev(rectangle);
+ \newcode
+ QPainter painter(this);
+ QPolygon transformed = polygon * painter.combinedMatrix().inverted();
+ \endcode
+*/
+
+QPolygon QPainter::xFormDev(const QPolygon &a) const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::xFormDev: Painter not active");
+ return QPolygon();
+ }
+ if (d->state->matrix.type() == QTransform::TxNone)
+ return a;
+ return a * combinedMatrix().inverted();
+}
+
+/*!
+ \fn QPolygon QPainter::xFormDev(const QPolygon &polygon, int index, int count) const
+ \overload
+
+ Use combinedMatrix() combined with QPolygon::mid() and QMatrix::inverted() instead.
+
+ \oldcode
+ QPainter painter(this);
+ QPolygon transformed = painter.xFormDev(polygon, index, count);
+ \newcode
+ QPainter painter(this);
+ QPolygon transformed = polygon.mid(index, count) * painter.combinedMatrix().inverted();
+ \endcode
+*/
+
+QPolygon QPainter::xFormDev(const QPolygon &ad, int index, int npoints) const
+{
+ Q_D(const QPainter);
+ int lastPoint = npoints < 0 ? ad.size() : index+npoints;
+ QPolygon a(lastPoint-index);
+ memcpy(a.data(), ad.data()+index, (lastPoint-index)*sizeof(QPoint));
+ if (d->state->matrix.type() == QTransform::TxNone)
+ return a;
+ return a * combinedMatrix().inverted();
+}
+
+/*!
+ \fn void QPainter::drawCubicBezier(const QPolygon &controlPoints, int index)
+
+ Draws a cubic Bezier curve defined by the \a controlPoints,
+ starting at \a{controlPoints}\e{[index]} (\a index defaults to 0).
+ Points after \a{controlPoints}\e{[index + 3]} are ignored. Nothing
+ happens if there aren't enough control points.
+
+ Use strokePath() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawCubicBezier(controlPoints, index)
+ \newcode
+ QPainterPath path;
+ path.moveTo(controlPoints.at(index));
+ path.cubicTo(controlPoints.at(index+1),
+ controlPoints.at(index+2),
+ controlPoints.at(index+3));
+
+ QPainter painter(this);
+ painter.strokePath(path, painter.pen());
+ \endcode
+*/
+void QPainter::drawCubicBezier(const QPolygon &a, int index)
+{
+ Q_D(QPainter);
+
+ if (!d->engine)
+ return;
+
+ if ((int)a.size() - index < 4) {
+ qWarning("QPainter::drawCubicBezier: Cubic Bezier needs 4 control "
+ "points");
+ return;
+ }
+
+ QPainterPath path;
+ path.moveTo(a.at(index));
+ path.cubicTo(a.at(index+1), a.at(index+2), a.at(index+3));
+ strokePath(path, d->state->pen);
+}
+#endif
+
+struct QPaintDeviceRedirection
+{
+ QPaintDeviceRedirection() : device(0), replacement(0), internalWidgetRedirectionIndex(-1) {}
+ QPaintDeviceRedirection(const QPaintDevice *device, QPaintDevice *replacement,
+ const QPoint& offset, int internalWidgetRedirectionIndex)
+ : device(device), replacement(replacement), offset(offset),
+ internalWidgetRedirectionIndex(internalWidgetRedirectionIndex) { }
+ const QPaintDevice *device;
+ QPaintDevice *replacement;
+ QPoint offset;
+ int internalWidgetRedirectionIndex;
+ bool operator==(const QPaintDevice *pdev) const { return device == pdev; }
+ Q_DUMMY_COMPARISON_OPERATOR(QPaintDeviceRedirection)
+};
+
+typedef QList<QPaintDeviceRedirection> QPaintDeviceRedirectionList;
+Q_GLOBAL_STATIC(QPaintDeviceRedirectionList, globalRedirections)
+Q_GLOBAL_STATIC(QMutex, globalRedirectionsMutex)
+
+/*!
+ \threadsafe
+
+ Redirects all paint commands for the given paint \a device, to the
+ \a replacement device. The optional point \a offset defines an
+ offset within the source device.
+
+ The redirection will not be effective until the begin() function
+ has been called; make sure to call end() for the given \a
+ device's painter (if any) before redirecting. Call
+ restoreRedirected() to restore the previous redirection.
+
+ In general, you'll probably find that calling
+ QPixmap::grabWidget() or QPixmap::grabWindow() is an easier
+ solution.
+
+ \sa redirected(), restoreRedirected()
+*/
+void QPainter::setRedirected(const QPaintDevice *device,
+ QPaintDevice *replacement,
+ const QPoint &offset)
+{
+ Q_ASSERT(device != 0);
+
+ bool hadInternalWidgetRedirection = false;
+ if (device->devType() == QInternal::Widget) {
+ const QWidgetPrivate *widgetPrivate = static_cast<const QWidget *>(device)->d_func();
+ // This is the case when the widget is in a paint event.
+ if (widgetPrivate->redirectDev) {
+ // Remove internal redirection and put it back into the global redirection list.
+ QPoint oldOffset;
+ QPaintDevice *oldReplacement = widgetPrivate->redirected(&oldOffset);
+ const_cast<QWidgetPrivate *>(widgetPrivate)->restoreRedirected();
+ setRedirected(device, oldReplacement, oldOffset);
+ hadInternalWidgetRedirection = true;
+ }
+ }
+
+ QPoint roffset;
+ QPaintDevice *rdev = redirected(replacement, &roffset);
+
+ QMutexLocker locker(globalRedirectionsMutex());
+ QPaintDeviceRedirectionList *redirections = globalRedirections();
+ Q_ASSERT(redirections != 0);
+ *redirections += QPaintDeviceRedirection(device, rdev ? rdev : replacement, offset + roffset,
+ hadInternalWidgetRedirection ? redirections->size() - 1 : -1);
+}
+
+/*!
+ \threadsafe
+
+ Restores the previous redirection for the given \a device after a
+ call to setRedirected().
+
+ \sa redirected()
+ */
+void QPainter::restoreRedirected(const QPaintDevice *device)
+{
+ Q_ASSERT(device != 0);
+ QMutexLocker locker(globalRedirectionsMutex());
+ QPaintDeviceRedirectionList *redirections = globalRedirections();
+ Q_ASSERT(redirections != 0);
+ for (int i = redirections->size()-1; i >= 0; --i) {
+ if (redirections->at(i) == device) {
+ const int internalWidgetRedirectionIndex = redirections->at(i).internalWidgetRedirectionIndex;
+ redirections->removeAt(i);
+ // Restore the internal widget redirection, i.e. remove it from the global
+ // redirection list and put it back into QWidgetPrivate. The index is only set when
+ // someone call QPainter::setRedirected in a widget's paint event and we internally
+ // have a redirection set (typically set in QWidgetPrivate::drawWidget).
+ if (internalWidgetRedirectionIndex >= 0) {
+ Q_ASSERT(internalWidgetRedirectionIndex < redirections->size());
+ const QPaintDeviceRedirection &redirectionDevice = redirections->at(internalWidgetRedirectionIndex);
+ QWidget *widget = static_cast<QWidget *>(const_cast<QPaintDevice *>(device));
+ widget->d_func()->setRedirected(redirectionDevice.replacement, redirectionDevice.offset);
+ redirections->removeAt(internalWidgetRedirectionIndex);
+ }
+ return;
+ }
+ }
+}
+
+/*!
+ \threadsafe
+
+ Returns the replacement for given \a device. The optional out
+ parameter \a offset returns the offset within the replaced device.
+
+ \sa setRedirected(), restoreRedirected()
+*/
+QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset)
+{
+ Q_ASSERT(device != 0);
+
+ if (device->devType() == QInternal::Widget) {
+ const QWidgetPrivate *widgetPrivate = static_cast<const QWidget *>(device)->d_func();
+ if (widgetPrivate->redirectDev)
+ return widgetPrivate->redirected(offset);
+ }
+
+ QMutexLocker locker(globalRedirectionsMutex());
+ QPaintDeviceRedirectionList *redirections = globalRedirections();
+ Q_ASSERT(redirections != 0);
+ for (int i = redirections->size()-1; i >= 0; --i)
+ if (redirections->at(i) == device) {
+ if (offset)
+ *offset = redirections->at(i).offset;
+ return redirections->at(i).replacement;
+ }
+ if (offset)
+ *offset = QPoint(0, 0);
+ return 0;
+}
+
+
+void qt_painter_removePaintDevice(QPaintDevice *dev)
+{
+ QMutexLocker locker(globalRedirectionsMutex());
+ if(QPaintDeviceRedirectionList *redirections = globalRedirections()) {
+ for (int i = 0; i < redirections->size(); ) {
+ if(redirections->at(i) == dev || redirections->at(i).replacement == dev)
+ redirections->removeAt(i);
+ else
+ ++i;
+ }
+ }
+}
+
+void qt_format_text(const QFont &fnt, const QRectF &_r,
+ int tf, const QString& str, QRectF *brect,
+ int tabstops, int *ta, int tabarraylen,
+ QPainter *painter)
+{
+ qt_format_text(fnt, _r,
+ tf, 0, str, brect,
+ tabstops, ta, tabarraylen,
+ painter);
+}
+void qt_format_text(const QFont &fnt, const QRectF &_r,
+ int tf, const QTextOption *option, const QString& str, QRectF *brect,
+ int tabstops, int *, int tabarraylen,
+ QPainter *painter)
+{
+
+ Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=0) ); // we either have an option or flags
+
+ if (option) {
+ tf |= option->alignment();
+ if (option->wrapMode() != QTextOption::NoWrap)
+ tf |= Qt::TextWordWrap;
+
+ if (option->flags() & QTextOption::IncludeTrailingSpaces)
+ tf |= Qt::TextIncludeTrailingSpaces;
+
+ if (option->tabStop() >= 0 || !option->tabArray().isEmpty())
+ tf |= Qt::TextExpandTabs;
+ }
+
+ // we need to copy r here to protect against the case (&r == brect).
+ QRectF r(_r);
+
+ bool dontclip = (tf & Qt::TextDontClip);
+ bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
+ bool singleline = (tf & Qt::TextSingleLine);
+ bool showmnemonic = (tf & Qt::TextShowMnemonic);
+ bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
+
+ Qt::LayoutDirection layout_direction;
+ if(option)
+ layout_direction = option->textDirection();
+ else if (painter)
+ layout_direction = painter->layoutDirection();
+ else
+ layout_direction = Qt::LeftToRight;
+
+ tf = QStyle::visualAlignment(layout_direction, QFlag(tf));
+
+ bool isRightToLeft = layout_direction == Qt::RightToLeft;
+ bool expandtabs = ((tf & Qt::TextExpandTabs) &&
+ (((tf & Qt::AlignLeft) && !isRightToLeft) ||
+ ((tf & Qt::AlignRight) && isRightToLeft)));
+
+ if (!painter)
+ tf |= Qt::TextDontPrint;
+
+ int maxUnderlines = 0;
+ int numUnderlines = 0;
+ int underlinePositionStack[32];
+ int *underlinePositions = underlinePositionStack;
+
+ QFontMetricsF fm(fnt);
+
+ QString text = str;
+ // compatible behaviour to the old implementation. Replace
+ // tabs by spaces
+ QChar *chr = text.data();
+ const QChar *end = chr + str.length();
+ bool has_tab = false;
+ while (chr != end) {
+ if (*chr == QLatin1Char('\r') || (singleline && *chr == QLatin1Char('\n'))) {
+ *chr = QLatin1Char(' ');
+ } else if (*chr == QLatin1Char('\n')) {
+ *chr = QChar::LineSeparator;
+ } else if (*chr == QLatin1Char('&')) {
+ ++maxUnderlines;
+ } else if (*chr == QLatin1Char('\t')) {
+ has_tab = true;
+ }
+ ++chr;
+ }
+ if (has_tab) {
+ if (!expandtabs) {
+ chr = text.data();
+ while (chr != end) {
+ if (*chr == QLatin1Char('\t'))
+ *chr = QLatin1Char(' ');
+ ++chr;
+ }
+ } else if (!tabarraylen && !tabstops) {
+ tabstops = qRound(fm.width(QLatin1Char('x'))*8);
+ }
+ }
+
+ if (hidemnmemonic || showmnemonic) {
+ if (maxUnderlines > 32)
+ underlinePositions = new int[maxUnderlines];
+ QChar *cout = text.data();
+ QChar *cin = cout;
+ int l = str.length();
+ while (l) {
+ if (*cin == QLatin1Char('&')) {
+ ++cin;
+ --l;
+ if (!l)
+ break;
+ if (*cin != QLatin1Char('&') && !hidemnmemonic)
+ underlinePositions[numUnderlines++] = cout - text.unicode();
+ }
+ *cout = *cin;
+ ++cout;
+ ++cin;
+ --l;
+ }
+ int newlen = cout - text.unicode();
+ if (newlen != text.length())
+ text.resize(newlen);
+ }
+
+ // no need to do extra work for underlines if we don't paint
+ if (tf & Qt::TextDontPrint)
+ numUnderlines = 0;
+
+ underlinePositions[numUnderlines] = -1;
+ qreal height = 0;
+ qreal width = 0;
+
+ QStackTextEngine engine(text, fnt);
+ if (option) {
+ engine.option = *option;
+ }
+
+
+
+ engine.option.setTextDirection(layout_direction);
+ if (tf & Qt::AlignJustify)
+ engine.option.setAlignment(Qt::AlignJustify);
+ else
+ engine.option.setAlignment(Qt::AlignLeft); // do not do alignment twice
+
+ if (!option && (tf & Qt::TextWrapAnywhere))
+ engine.option.setWrapMode(QTextOption::WrapAnywhere);
+
+ if (tf & Qt::TextJustificationForced)
+ engine.forceJustification = true;
+ QTextLayout textLayout(&engine);
+ textLayout.setCacheEnabled(true);
+ textLayout.engine()->underlinePositions = underlinePositions;
+
+ if (text.isEmpty()) {
+ height = fm.height();
+ width = 0;
+ tf |= Qt::TextDontPrint;
+ } else {
+ qreal lineWidth = 0x01000000;
+ if (wordwrap || (tf & Qt::TextJustificationForced))
+ lineWidth = qMax<qreal>(0, r.width());
+ if(!wordwrap)
+ tf |= Qt::TextIncludeTrailingSpaces;
+ textLayout.engine()->ignoreBidi = bool(tf & Qt::TextDontPrint);
+ textLayout.beginLayout();
+
+ qreal leading = fm.leading();
+ height = -leading;
+
+ while (1) {
+ QTextLine l = textLayout.createLine();
+ if (!l.isValid())
+ break;
+
+ l.setLineWidth(lineWidth);
+ height += leading;
+ l.setPosition(QPointF(0., height));
+ height += l.height();
+ width = qMax(width, l.naturalTextWidth());
+ if (!brect && height >= r.height())
+ break;
+ }
+ textLayout.endLayout();
+ }
+
+ qreal yoff = 0;
+ qreal xoff = 0;
+ if (tf & Qt::AlignBottom) {
+ yoff = r.height() - height;
+ } else if (tf & Qt::AlignVCenter) {
+ yoff = (r.height() - height)/2;
+ if (painter) {
+ QTransform::TransformationType type = painter->transform().type();
+ if (type <= QTransform::TxScale) {
+ // do the rounding manually to work around inconsistencies
+ // in the paint engines when drawing on floating point offsets
+ const qreal scale = painter->transform().m22();
+ if (scale != 0)
+ yoff = qRound(yoff * scale) / scale;
+ }
+ }
+ }
+ if (tf & Qt::AlignRight) {
+ xoff = r.width() - width;
+ } else if (tf & Qt::AlignHCenter) {
+ xoff = (r.width() - width)/2;
+ if (painter) {
+ QTransform::TransformationType type = painter->transform().type();
+ if (type <= QTransform::TxScale) {
+ // do the rounding manually to work around inconsistencies
+ // in the paint engines when drawing on floating point offsets
+ const qreal scale = painter->transform().m11();
+ if (scale != 0)
+ xoff = qRound(xoff * scale) / scale;
+ }
+ }
+ }
+ QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
+ if (brect)
+ *brect = bounds;
+
+ if (!(tf & Qt::TextDontPrint)) {
+ bool restore = false;
+ if (!dontclip && !r.contains(bounds)) {
+ restore = true;
+ painter->save();
+ painter->setClipRect(r, Qt::IntersectClip);
+ }
+
+ for (int i = 0; i < textLayout.lineCount(); i++) {
+ QTextLine line = textLayout.lineAt(i);
+
+ if (tf & Qt::AlignRight)
+ xoff = r.width() - line.naturalTextWidth();
+ else if (tf & Qt::AlignHCenter)
+ xoff = (r.width() - line.naturalTextWidth())/2;
+
+ line.draw(painter, QPointF(r.x() + xoff + line.x(), r.y() + yoff));
+ }
+
+ if (restore) {
+ painter->restore();
+ }
+ }
+
+ if (underlinePositions != underlinePositionStack)
+ delete [] underlinePositions;
+}
+
+/*!
+ Sets the layout direction used by the painter when drawing text,
+ to the specified \a direction.
+
+ \sa layoutDirection(), drawText(), {QPainter#Settings}{Settings}
+*/
+void QPainter::setLayoutDirection(Qt::LayoutDirection direction)
+{
+ Q_D(QPainter);
+ if (d->state)
+ d->state->layoutDirection = direction;
+}
+
+/*!
+ Returns the layout direction used by the painter when drawing text.
+
+ \sa setLayoutDirection(), drawText(), {QPainter#Settings}{Settings}
+*/
+Qt::LayoutDirection QPainter::layoutDirection() const
+{
+ Q_D(const QPainter);
+ return d->state ? d->state->layoutDirection : Qt::LeftToRight;
+}
+
+QPainterState::QPainterState(const QPainterState *s)
+ : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
+ pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
+ clipRegion(s->clipRegion), clipPath(s->clipPath),
+ clipOperation(s->clipOperation),
+ renderHints(s->renderHints), clipInfo(s->clipInfo),
+ worldMatrix(s->worldMatrix), matrix(s->matrix), redirection_offset(s->redirection_offset),
+ wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
+ vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
+ opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
+ clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
+ layoutDirection(s->layoutDirection),
+ composition_mode(s->composition_mode),
+ emulationSpecifier(s->emulationSpecifier), changeFlags(0)
+{
+ dirtyFlags = s->dirtyFlags;
+}
+
+QPainterState::QPainterState()
+ : brushOrigin(0, 0), bgBrush(Qt::white), clipOperation(Qt::NoClip),
+ renderHints(0),
+ wx(0), wy(0), ww(0), wh(0), vx(0), vy(0), vw(0), vh(0),
+ opacity(1), WxF(false), VxF(false), clipEnabled(true),
+ bgMode(Qt::TransparentMode), painter(0),
+ layoutDirection(QApplication::layoutDirection()),
+ composition_mode(QPainter::CompositionMode_SourceOver),
+ emulationSpecifier(0), changeFlags(0)
+{
+ dirtyFlags = 0;
+}
+
+QPainterState::~QPainterState()
+{
+}
+
+void QPainterState::init(QPainter *p) {
+ bgBrush = Qt::white;
+ bgMode = Qt::TransparentMode;
+ WxF = false;
+ VxF = false;
+ clipEnabled = true;
+ wx = wy = ww = wh = 0;
+ vx = vy = vw = vh = 0;
+ painter = p;
+ pen = QPen();
+ brushOrigin = QPointF(0, 0);
+ brush = QBrush();
+ font = deviceFont = QFont();
+ clipRegion = QRegion();
+ clipPath = QPainterPath();
+ clipOperation = Qt::NoClip;
+ clipInfo.clear();
+ worldMatrix.reset();
+ matrix.reset();
+ layoutDirection = QApplication::layoutDirection();
+ composition_mode = QPainter::CompositionMode_SourceOver;
+ emulationSpecifier = 0;
+ dirtyFlags = 0;
+ changeFlags = 0;
+ renderHints = 0;
+ opacity = 1;
+}
+
+#ifdef QT3_SUPPORT
+static void bitBlt_helper(QPaintDevice *dst, const QPoint &dp,
+ const QPaintDevice *src, const QRect &sr, bool)
+{
+ Q_ASSERT(dst);
+ Q_ASSERT(src);
+
+ if (src->devType() == QInternal::Pixmap) {
+ const QPixmap *pixmap = static_cast<const QPixmap *>(src);
+ QPainter pt(dst);
+ pt.drawPixmap(dp, *pixmap, sr);
+
+ } else {
+ qWarning("QPainter: bitBlt only works when source is of type pixmap");
+ }
+}
+
+void bitBlt(QPaintDevice *dst, int dx, int dy,
+ const QPaintDevice *src, int sx, int sy, int sw, int sh,
+ bool ignoreMask )
+{
+ bitBlt_helper(dst, QPoint(dx, dy), src, QRect(sx, sy, sw, sh), ignoreMask);
+}
+
+void bitBlt(QPaintDevice *dst, const QPoint &dp, const QPaintDevice *src, const QRect &sr, bool ignoreMask)
+{
+ bitBlt_helper(dst, dp, src, sr, ignoreMask);
+}
+
+void bitBlt(QPaintDevice *dst, int dx, int dy,
+ const QImage *src, int sx, int sy, int sw, int sh, int fl)
+{
+ Qt::ImageConversionFlags flags(fl);
+ QPixmap srcPixmap = QPixmap::fromImage(*src, flags);
+ bitBlt_helper(dst, QPoint(dx, dy), &srcPixmap, QRect(sx, sy, sw, sh), false);
+}
+
+#endif // QT3_SUPPORT
+
+/*!
+ \fn void QPainter::setBackgroundColor(const QColor &color)
+
+ Use setBackground() instead.
+*/
+
+/*!
+ \fn const QColor &QPainter::backgroundColor() const
+
+ Use background() and QBrush::color() instead.
+
+ \oldcode
+ QColor myColor = backgroundColor();
+ \newcode
+ QColor myColor = background().color();
+ \endcode
+
+ Note that the background can be a complex brush such as a texture
+ or a gradient.
+*/
+
+/*!
+ \fn void QPainter::drawText(int x, int y, const QString &text, int pos, int length)
+ \compat
+
+ Use drawText() combined with QString::mid() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawText(x, y, text, pos, length);
+ \newcode
+ QPainter painter(this);
+ painter.drawText(x, y, text.mid(pos, length));
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawText(const QPoint &point, const QString &text, int pos, int length)
+ \compat
+
+ Use drawText() combined with QString::mid() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawText(point, text, pos, length);
+ \newcode
+ QPainter painter(this);
+ painter.drawText(point, text.mid(pos, length));
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawText(int x, int y, const QString &text, int length)
+ \compat
+
+ Use drawText() combined with QString::left() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawText(x, y, text, length);
+ \newcode
+ QPainter painter(this);
+ painter.drawText(x, y, text.left(length));
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawText(const QPoint &point, const QString &text, int length)
+ \compat
+
+ Use drawText() combined with QString::left() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawText(point, text, length);
+ \newcode
+ QPainter painter(this);
+ painter.drawText(point, text.left(length));
+ \endcode
+*/
+
+/*!
+ \fn bool QPainter::begin(QPaintDevice *device, const QWidget *init)
+ \compat
+
+ Use begin() instead.
+
+ If the paint \a device is a QWidget, QPainter is initialized after
+ the widget's settings automatically. Otherwise, you must call the
+ initFrom() function to initialize the painters pen, background and
+ font to the same as any given widget.
+
+ \oldcode
+ QPainter painter(this);
+ painter.begin(device, init);
+ \newcode
+ QPainter painter(this);
+ painter.begin(device);
+ painter.initFrom(init);
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QRectF &target, const QImage &image, const QRectF &source,
+ Qt::ImageConversionFlags flags)
+
+ Draws the rectangular portion \a source of the given \a image
+ into the \a target rectangle in the paint device.
+
+ \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
+
+ If the image needs to be modified to fit in a lower-resolution
+ result (e.g. converting from 32-bit to 8-bit), use the \a flags to
+ specify how you would prefer this to happen.
+
+ \table 100%
+ \row
+ \o
+ \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 20
+ \endtable
+
+ \sa drawPixmap()
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QRect &target, const QImage &image, const QRect &source,
+ Qt::ImageConversionFlags flags)
+ \overload
+
+ Draws the rectangular portion \a source of the given \a image
+ into the \a target rectangle in the paint device.
+
+ \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QPointF &point, const QImage &image)
+
+ \overload
+
+ Draws the given \a image at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QPoint &point, const QImage &image)
+
+ \overload
+
+ Draws the given \a image at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QPointF &point, const QImage &image, const QRectF &source,
+ Qt::ImageConversionFlags flags = 0)
+
+ \overload
+
+ Draws the rectangular portion \a source of the given \a image with
+ its origin at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QPoint &point, const QImage &image, const QRect &source,
+ Qt::ImageConversionFlags flags = 0)
+ \overload
+
+ Draws the rectangular portion \a source of the given \a image with
+ its origin at the given \a point.
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QRectF &rectangle, const QImage &image)
+
+ \overload
+
+ Draws the given \a image into the given \a rectangle.
+
+ \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
+*/
+
+/*!
+ \fn void QPainter::drawImage(const QRect &rectangle, const QImage &image)
+
+ \overload
+
+ Draws the given \a image into the given \a rectangle.
+
+ \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
+*/
+
+/*!
+ \fn void QPainter::drawImage(int x, int y, const QImage &image,
+ int sx, int sy, int sw, int sh,
+ Qt::ImageConversionFlags flags)
+ \overload
+
+ Draws an image at (\a{x}, \a{y}) by copying a part of \a image into
+ the paint device.
+
+ (\a{x}, \a{y}) specifies the top-left point in the paint device that is
+ to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
+ image that is to be drawn. The default is (0, 0).
+
+ (\a{sw}, \a{sh}) specifies the size of the image that is to be drawn.
+ The default, (0, 0) (and negative) means all the way to the
+ bottom-right of the image.
+*/
+
+/*!
+ \fn void QPainter::redirect(QPaintDevice *pdev, QPaintDevice *replacement)
+
+ Use setRedirected() instead.
+*/
+
+/*!
+ \fn QPaintDevice *QPainter::redirect(QPaintDevice *pdev)
+
+ Use redirected() instead.
+*/
+
+/*!
+ \fn QRect QPainter::boundingRect(const QRect &rectangle, int flags,
+ const QString &text, int length)
+ \compat
+
+ Returns the bounding rectangle for the given \a length of the \a
+ text constrained by the provided \a rectangle.
+
+ Use boundingRect() combined with QString::left() instead.
+
+ \oldcode
+ QRect rectangle = boundingRect(rect, flags, text, length);
+ \newcode
+ QRect rectangle = boundingRect(rect, flags, text.left(length));
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawText(const QRect &rectangle, int flags, const QString &text,
+ int length, QRect *br)
+ \compat
+
+ Use drawText() combined with QString::left() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawText(rectangle, flags, text, length, br );
+ \newcode
+ QPainter painter(this);
+ painter.drawText(rectangle, flags, text.left(length), br );
+ \endcode
+*/
+
+/*!
+ \fn QRect QPainter::boundingRect(int x, int y, int width, int height, int flags,
+ const QString &text, int length);
+
+ \compat
+
+ Returns the bounding rectangle for the given \a length of the \a
+ text constrained by the rectangle that begins at point (\a{x},
+ \a{y}) with the given \a width and \a height.
+
+ Use boundingRect() combined with QString::left() instead.
+
+ \oldcode
+ QRect rectangle = boundingRect(x, y, width, height, flags, text, length);
+ \newcode
+ QRect rectangle = boundingRect(x, y, width, height, flags, text.left(length));
+ \endcode
+*/
+
+/*!
+ \fn void QPainter::drawText(int x, int y, int width, int height, int flags,
+ const QString &text, int length, QRect *br)
+
+ \compat
+
+ Use drawText() combined with QString::left() instead.
+
+ \oldcode
+ QPainter painter(this);
+ painter.drawText(x, y, width, height, flags, text, length, br );
+ \newcode
+ QPainter painter(this);
+ painter.drawText(x, y, width, height, flags, text.left(length), br );
+ \endcode
+*/
+
+
+/*!
+ \class QPaintEngineState
+ \since 4.1
+
+ \brief The QPaintEngineState class provides information about the
+ active paint engine's current state.
+ \reentrant
+
+ QPaintEngineState records which properties that have changed since
+ the last time the paint engine was updated, as well as their
+ current value.
+
+ Which properties that have changed can at any time be retrieved
+ using the state() function. This function returns an instance of
+ the QPaintEngine::DirtyFlags type which stores an OR combination
+ of QPaintEngine::DirtyFlag values. The QPaintEngine::DirtyFlag
+ enum defines whether a property has changed since the last update
+ or not.
+
+ If a property is marked with a dirty flag, its current value can
+ be retrieved using the corresponding get function:
+
+ \target GetFunction
+
+ \table
+ \header \o Property Flag \o Current Property Value
+ \row \o QPaintEngine::DirtyBackground \o backgroundBrush()
+ \row \o QPaintEngine::DirtyBackgroundMode \o backgroundMode()
+ \row \o QPaintEngine::DirtyBrush \o brush()
+ \row \o QPaintEngine::DirtyBrushOrigin \o brushOrigin()
+ \row \o QPaintEngine::DirtyClipRegion \e or QPaintEngine::DirtyClipPath
+ \o clipOperation()
+ \row \o QPaintEngine::DirtyClipPath \o clipPath()
+ \row \o QPaintEngine::DirtyClipRegion \o clipRegion()
+ \row \o QPaintEngine::DirtyCompositionMode \o compositionMode()
+ \row \o QPaintEngine::DirtyFont \o font()
+ \row \o QPaintEngine::DirtyTransform \o matrix()
+ \row \o QPaintEngine::DirtyClipEnabled \o isClipEnabled()
+ \row \o QPaintEngine::DirtyPen \o pen()
+ \row \o QPaintEngine::DirtyHints \o renderHints()
+ \endtable
+
+ The QPaintEngineState class also provide the painter() function
+ which returns a pointer to the painter that is currently updating
+ the paint engine.
+
+ An instance of this class, representing the current state of the
+ active paint engine, is passed as argument to the
+ QPaintEngine::updateState() function. The only situation in which
+ you will have to use this class directly is when implementing your
+ own paint engine.
+
+ \sa QPaintEngine
+*/
+
+
+/*!
+ \fn QPaintEngine::DirtyFlags QPaintEngineState::state() const
+
+ Returns a combination of flags identifying the set of properties
+ that need to be updated when updating the paint engine's state
+ (i.e. during a call to the QPaintEngine::updateState() function).
+
+ \sa QPaintEngine::updateState()
+*/
+
+
+/*!
+ Returns the pen in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyPen flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QPen QPaintEngineState::pen() const
+{
+ return static_cast<const QPainterState *>(this)->pen;
+}
+
+/*!
+ Returns the brush in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyBrush flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QBrush QPaintEngineState::brush() const
+{
+ return static_cast<const QPainterState *>(this)->brush;
+}
+
+/*!
+ Returns the brush origin in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyBrushOrigin flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QPointF QPaintEngineState::brushOrigin() const
+{
+ return static_cast<const QPainterState *>(this)->brushOrigin;
+}
+
+/*!
+ Returns the background brush in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyBackground flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QBrush QPaintEngineState::backgroundBrush() const
+{
+ return static_cast<const QPainterState *>(this)->bgBrush;
+}
+
+/*!
+ Returns the background mode in the current paint engine
+ state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyBackgroundMode flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+Qt::BGMode QPaintEngineState::backgroundMode() const
+{
+ return static_cast<const QPainterState *>(this)->bgMode;
+}
+
+/*!
+ Returns the font in the current paint engine
+ state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyFont flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QFont QPaintEngineState::font() const
+{
+ return static_cast<const QPainterState *>(this)->font;
+}
+
+/*!
+ \since 4.2
+
+ Returns the matrix in the current paint engine
+ state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyTransform flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QMatrix QPaintEngineState::matrix() const
+{
+ const QPainterState *st = static_cast<const QPainterState *>(this);
+
+ return st->matrix.toAffine();
+}
+
+/*!
+ \since 4.3
+
+ Returns the matrix in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyTransform flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+
+QTransform QPaintEngineState::transform() const
+{
+ const QPainterState *st = static_cast<const QPainterState *>(this);
+
+ return st->matrix;
+}
+
+
+/*!
+ Returns the clip operation in the current paint engine
+ state.
+
+ This variable should only be used when the state() returns a
+ combination which includes either the QPaintEngine::DirtyClipPath
+ or the QPaintEngine::DirtyClipRegion flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+Qt::ClipOperation QPaintEngineState::clipOperation() const
+{
+ return static_cast<const QPainterState *>(this)->clipOperation;
+}
+
+/*!
+ \since 4.3
+
+ Returns whether the coordinate of the fill have been specified
+ as bounded by the current rendering operation and have to be
+ resolved (about the currently rendered primitive).
+*/
+bool QPaintEngineState::brushNeedsResolving() const
+{
+ const QBrush &brush = static_cast<const QPainterState *>(this)->brush;
+ return needsResolving(brush);
+}
+
+
+/*!
+ \since 4.3
+
+ Returns whether the coordinate of the stroke have been specified
+ as bounded by the current rendering operation and have to be
+ resolved (about the currently rendered primitive).
+*/
+bool QPaintEngineState::penNeedsResolving() const
+{
+ const QPen &pen = static_cast<const QPainterState *>(this)->pen;
+ return needsResolving(pen.brush());
+}
+
+/*!
+ Returns the clip region in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyClipRegion flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QRegion QPaintEngineState::clipRegion() const
+{
+ return static_cast<const QPainterState *>(this)->clipRegion;
+}
+
+/*!
+ Returns the clip path in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyClipPath flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QPainterPath QPaintEngineState::clipPath() const
+{
+ return static_cast<const QPainterState *>(this)->clipPath;
+}
+
+/*!
+ Returns wether clipping is enabled or not in the current paint
+ engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyClipEnabled
+ flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+bool QPaintEngineState::isClipEnabled() const
+{
+ return static_cast<const QPainterState *>(this)->clipEnabled;
+}
+
+/*!
+ Returns the render hints in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyHints
+ flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QPainter::RenderHints QPaintEngineState::renderHints() const
+{
+ return static_cast<const QPainterState *>(this)->renderHints;
+}
+
+/*!
+ Returns the composition mode in the current paint engine state.
+
+ This variable should only be used when the state() returns a
+ combination which includes the QPaintEngine::DirtyCompositionMode
+ flag.
+
+ \sa state(), QPaintEngine::updateState()
+*/
+
+QPainter::CompositionMode QPaintEngineState::compositionMode() const
+{
+ return static_cast<const QPainterState *>(this)->composition_mode;
+}
+
+
+/*!
+ Returns a pointer to the painter currently updating the paint
+ engine.
+*/
+
+QPainter *QPaintEngineState::painter() const
+{
+ return static_cast<const QPainterState *>(this)->painter;
+}
+
+
+/*!
+ \since 4.2
+
+ Returns the opacity in the current paint engine state.
+*/
+
+qreal QPaintEngineState::opacity() const
+{
+ return static_cast<const QPainterState *>(this)->opacity;
+}
+
+/*!
+ \since 4.3
+
+ Sets the world transformation matrix.
+ If \a combine is true, the specified \a transform is combined with
+ the current matrix; otherwise it replaces the current matrix.
+
+ This function has been added for compatibility with setMatrix(),
+ but as with setMatrix() the preferred method of setting a
+ transformation on the painter is through setWorldTransform().
+
+ \sa transform()
+*/
+
+void QPainter::setTransform(const QTransform &transform, bool combine )
+{
+ setWorldTransform(transform, combine);
+}
+
+/*!
+ Returns the world transformation matrix.
+*/
+
+const QTransform & QPainter::transform() const
+{
+ return worldTransform();
+}
+
+
+/*!
+ Returns the matrix that transforms from logical coordinates to
+ device coordinates of the platform dependent paint device.
+
+ This function is \e only needed when using platform painting
+ commands on the platform dependent handle (Qt::HANDLE), and the
+ platform does not do transformations nativly.
+
+ The QPaintEngine::PaintEngineFeature enum can be queried to
+ determine whether the platform performs the transformations or
+ not.
+
+ \sa worldTransform(), QPaintEngine::hasFeature(),
+*/
+
+const QTransform & QPainter::deviceTransform() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::deviceTransform: Painter not active");
+ return d->fakeState()->transform;
+ }
+ return d->state->matrix;
+}
+
+
+/*!
+ Resets any transformations that were made using translate(),
+ scale(), shear(), rotate(), setWorldTransform(), setViewport()
+ and setWindow().
+
+ \sa {Coordinate Transformations}
+*/
+
+void QPainter::resetTransform()
+{
+ Q_D(QPainter);
+#ifdef QT_DEBUG_DRAW
+ if (qt_show_painter_debug_output)
+ printf("QPainter::resetMatrix()\n");
+#endif
+ if (!d->engine) {
+ qWarning("QPainter::resetMatrix: Painter not active");
+ return;
+ }
+
+ d->state->wx = d->state->wy = d->state->vx = d->state->vy = 0; // default view origins
+ d->state->ww = d->state->vw = d->device->metric(QPaintDevice::PdmWidth);
+ d->state->wh = d->state->vh = d->device->metric(QPaintDevice::PdmHeight);
+ d->state->worldMatrix = QTransform();
+ setMatrixEnabled(false);
+ setViewTransformEnabled(false);
+ if (d->extended)
+ d->extended->transformChanged();
+ else
+ d->state->dirtyFlags |= QPaintEngine::DirtyTransform;
+}
+
+/*!
+ Sets the world transformation matrix.
+ If \a combine is true, the specified \a matrix is combined with the current matrix;
+ otherwise it replaces the current matrix.
+
+ \sa transform(), setTransform()
+*/
+
+void QPainter::setWorldTransform(const QTransform &matrix, bool combine )
+{
+ Q_D(QPainter);
+
+ if (!d->engine) {
+ qWarning("QPainter::setWorldTransform: Painter not active");
+ return;
+ }
+
+ if (combine)
+ d->state->worldMatrix = matrix * d->state->worldMatrix; // combines
+ else
+ d->state->worldMatrix = matrix; // set new matrix
+
+ d->state->WxF = true;
+ d->updateMatrix();
+}
+
+/*!
+ Returns the world transformation matrix.
+*/
+
+const QTransform & QPainter::worldTransform() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::worldTransform: Painter not active");
+ return d->fakeState()->transform;
+ }
+ return d->state->worldMatrix;
+}
+
+/*!
+ Returns the transformation matrix combining the current
+ window/viewport and world transformation.
+
+ \sa setWorldMatrix(), setWindow(), setViewport()
+*/
+
+QTransform QPainter::combinedTransform() const
+{
+ Q_D(const QPainter);
+ if (!d->engine) {
+ qWarning("QPainter::combinedTransform: Painter not active");
+ return QTransform();
+ }
+ return d->state->worldMatrix * d->viewTransform();
+}
+
+void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
+{
+ p->draw_helper(path, operation);
+}
+
+QT_END_NAMESPACE