/**************************************************************************** ** ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** This file may be used under the terms of the GNU General Public ** License version 2.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 GNU ** General Public Licensing requirements will be met: ** http://trolltech.com/products/qt/licenses/licensing/opensource/ ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://trolltech.com/products/qt/licenses/licensing/licensingoverview ** or contact the sales department at sales@trolltech.com. ** ** In addition, as a special exception, Trolltech gives you certain ** additional rights. These rights are described in the Trolltech GPL ** Exception version 1.0, which can be found at ** http://www.trolltech.com/products/qt/gplexception/ and in the file ** GPL_EXCEPTION.txt in this package. ** ** In addition, as a special exception, Trolltech, as the sole copyright ** holder for Qt Designer, grants users of the Qt/Eclipse Integration ** plug-in the right for the Qt/Eclipse Integration to link to ** functionality provided by Qt Designer and its related libraries. ** ** Trolltech reserves all rights not expressly granted herein. ** ** Trolltech ASA (c) 2007 ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #include "qpaintengine.h" #include "qpaintengine_p.h" #include "qpainter_p.h" #include "qpolygon.h" #include "qbitmap.h" #include "qapplication.h" #include #include #include #include /*! \class QTextItem \internal */ qreal QTextItem::descent() const { const QTextItemInt *ti = static_cast(this); return ti->descent.toReal(); } qreal QTextItem::ascent() const { const QTextItemInt *ti = static_cast(this); return ti->ascent.toReal(); } qreal QTextItem::width() const { const QTextItemInt *ti = static_cast(this); return ti->width.toReal(); } QTextItem::RenderFlags QTextItem::renderFlags() const { const QTextItemInt *ti = static_cast(this); return ti->flags; } QString QTextItem::text() const { const QTextItemInt *ti = static_cast(this); return QString(ti->chars, ti->num_chars); } QFont QTextItem::font() const { const QTextItemInt *ti = static_cast(this); return ti->f ? *ti->f : QApplication::font(); } #include /*! \class QPaintEngine \ingroup multimedia \brief The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a given platform. Qt 4.0 provides several premade implementations of QPaintEngine for the different painter backends we support. We provide one paint engine for each window system and painting framework we support. This includes X11 on Unix/Linux and CoreGraphics on Mac OS X. In addition we provide QPaintEngine implementations for OpenGL (accessible through QGLWidget) and PostScript (accessible through QPSPrinter on X11). Additionally there is a raster-based paint engine that is a fallback for when an engine does not support a certain capability. If one wants to use QPainter to draw to a different backend, one must subclass QPaintEngine and reimplement all its virtual functions. The QPaintEngine implementation is then made available by subclassing QPaintDevice and reimplementing the virtual function QPaintDevice::paintEngine(). QPaintEngine is created and owned by the QPaintDevice that created it. The big advantage of the QPaintEngine approach opposed to Qt 3's QPainter/QPaintDevice::cmd() approach is that it is now possible to adapt to multiple technologies on each platform and take advantage of each to the fullest. \sa QPainter, QPaintDevice::paintEngine(), {The Paint System} */ /*! \enum QPaintEngine::PaintEngineFeature This enum is used to describe the features or capabilities that the paint engine has. If a feature is not supported by the engine, QPainter will do a best effort to emulate that feature through other means and pass on an alpha blended QImage to the engine with the emulated results. Some features cannot be emulated: AlphaBlend and PorterDuff. \value AlphaBlend The engine can alpha blend primitives. \value Antialiasing The engine can use antialising to improve the appearance of rendered primitives. \value BlendModes The engine supports blending modes. \value BrushStroke The engine supports drawing strokes that contain brushes as fills, not just solid colors (e.g. a dashed gradient line of width 2). \value ConicalGradientFill The engine supports conical gradient fills. \value ConstantOpacity The engine supports the feature provided by QPainter::setOpacity(). \value LinearGradientFill The engine supports linear gradient fills. \value MaskedBrush The engine is capable of rendering brushes that has a texture with an alpha channel or a mask. \value PainterPaths The engine has path support. \value PaintOutsidePaintEvent The engine is capable of painting outside of paint events. \value PatternBrush The engine is capable of rendering brushes with the brush patterns specified in Qt::BrushStyle. \value PatternTransform The engine has support for transforming brush patterns. \value PerspectiveTransform The engine has support for performing perspective transformations on primitives. \value PixmapTransform The engine can transform pixmaps, including rotation and shearing. \value PorterDuff The engine supports Porter-Duff operations \value PrimitiveTransform The engine has support for transforming drawing primitives. \value RadialGradientFill The engine supports radial gradient fills. \value AllFeatures All of the above features. This enum value is usually used as a bit mask. */ /*! \enum QPaintEngine::PolygonDrawMode \value OddEvenMode The polygon should be drawn using OddEven fill rule. \value WindingMode The polygon should be drawn using Winding fill rule. \value ConvexMode The polygon is a convex polygon and can be drawn using specialized algorithms where available. \value PolylineMode Only the outline of the polygon should be drawn. */ /*! \enum QPaintEngine::DirtyFlag \value DirtyPen The pen is dirty and needs to be updated. \value DirtyBrush The brush is dirty and needs to be updated. \value DirtyBrushOrigin The brush origin is dirty and needs to updated. \value DirtyFont The font is dirty and needs to be updated. \value DirtyBackground The background is dirty and needs to be updated. \value DirtyBackgroundMode The background mode is dirty and needs to be updated. \value DirtyTransform The transform is dirty and needs to be updated. \value DirtyClipRegion The clip region is dirty and needs to be updated. \value DirtyClipPath The clip path is dirty and needs to be updated. \value DirtyHints The render hints is dirty and needs to be updated. \value DirtyCompositionMode The composition mode is dirty and needs to be updated. \value DirtyClipEnabled Whether clipping is enabled or not is dirty and needs to be updated. \value DirtyOpacity The constant opacity has changed and needs to be updated as part of the state change in QPaintEngine::updateState(). \value AllDirty Convenience enum used internally. These types are used by QPainter to trigger lazy updates of the various states in the QPaintEngine using QPaintEngine::updateState(). A paint engine must update every dirty state. */ /*! \fn void QPaintEngine::syncState() \internal Updates all dirty states in this engine. This function should ONLY be used when drawing with native handles directly and immediate sync from QPainters state to the native state is required. */ static QPaintEngine *qt_polygon_recursion = 0; struct QT_Point { int x; int y; }; /*! \fn void QPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) Reimplement this virtual function to draw the polygon defined by the \a pointCount first points in \a points, using mode \a mode. The default implementation of this function will try to use drawPath if the engine supports the feature QPaintEngine::PainterPaths or try the float based drawPolygon() implementation if not. */ void QPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) { Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon", "At least one drawPolygon function must be implemented"); qt_polygon_recursion = this; Q_ASSERT(sizeof(QT_Point) == sizeof(QPoint)); QVarLengthArray p(pointCount); for (int i = 0; i < pointCount; ++i) { p[i].x = qRound(points[i].x()); p[i].y = qRound(points[i].y()); } drawPolygon((QPoint *)p.data(), pointCount, mode); qt_polygon_recursion = 0; } struct QT_PointF { qreal x; qreal y; }; /*! \overload Reimplement this virtual function to draw the polygon defined by the \a pointCount first points in \a points, using mode \a mode. The default implementation of this function will try to use drawPath() if the engine supports the feature QPaintEngine::PainterPaths or try the int based drawPolygon() implementation if not. */ void QPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) { Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon", "At least one drawPolygon function must be implemented"); qt_polygon_recursion = this; Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF)); QVarLengthArray p(pointCount); for (int i=0; iwidth()) { p.drawPixmap(x, 0, *tile, 0, 0, x, pixmap.height()); x *= 2; } int y = pixmap.height(); while (y < tile->height()) { p.drawPixmap(0, y, *tile, 0, 0, tile->width(), y); y *= 2; } } void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h, const QPixmap &pixmap, qreal xOffset, qreal yOffset) { qreal yPos, xPos, drawH, drawW, yOff, xOff; yPos = y; yOff = yOffset; while(yPos < y + h) { drawH = pixmap.height() - yOff; // Cropping first row if (yPos + drawH > y + h) // Cropping last row drawH = y + h - yPos; xPos = x; xOff = xOffset; while(xPos < x + w) { drawW = pixmap.width() - xOff; // Cropping first column if (xPos + drawW > x + w) // Cropping last column drawW = x + w - xPos; if (drawW > 0 && drawH > 0) gc->drawPixmap(QRectF(xPos, yPos, drawW, drawH), pixmap, QRectF(xOff, yOff, drawW, drawH)); xPos += drawW; xOff = 0; } yPos += drawH; yOff = 0; } } /*! Reimplement this function to draw the \a pixmap in the given \a rect, starting at the given \a p. The pixmap will be drawn repeatedly until the \a rect is filled. */ void QPaintEngine::drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p) { int sw = pixmap.width(); int sh = pixmap.height(); if (sw*sh < 8192 && sw*sh < 16*rect.width()*rect.height()) { int tw = sw, th = sh; while (tw*th < 32678 && tw < rect.width()/2) tw *= 2; while (tw*th < 32678 && th < rect.height()/2) th *= 2; QPixmap tile; if (pixmap.depth() == 1) { tile = QBitmap(tw, th); } else { tile = QPixmap(tw, th); if (pixmap.hasAlphaChannel()) tile.fill(Qt::transparent); } qt_fill_tile(&tile, pixmap); qt_draw_tile(this, rect.x(), rect.y(), rect.width(), rect.height(), tile, p.x(), p.y()); } else { qt_draw_tile(this, rect.x(), rect.y(), rect.width(), rect.height(), pixmap, p.x(), p.y()); } } /*! \fn void QPaintEngine::drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags) Reimplement this function to draw the part of the \a image specified by the \a sr rectangle in the given \a rectangle using the given conversion flags \a flags, to convert it to a pixmap. */ void QPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags) { QRectF baseSize(0, 0, image.width(), image.height()); QImage im = image; if (baseSize != sr) im = im.copy(qFloor(sr.x()), qFloor(sr.y()), qCeil(sr.width()), qCeil(sr.height())); if (im.depth() == 1) im = im.convertToFormat(QImage::Format_RGB32); QPixmap pm = QPixmap::fromImage(im, flags); drawPixmap(r, pm, QRectF(QPointF(0, 0), pm.size())); } /*! \fn Type QPaintEngine::type() const Reimplement this function to return the paint engine \l{Type}. */ /*! \fn void QPaintEngine::fix_neg_rect(int *x, int *y, int *w, int *h); \internal */ /*! \fn bool QPaintEngine::testDirty(DirtyFlags df) \internal */ /*! \fn void QPaintEngine::clearDirty(DirtyFlags df) \internal */ /*! \fn void QPaintEngine::setDirty(DirtyFlags df) \internal */ /*! \fn bool QPaintEngine::hasFeature(PaintEngineFeatures feature) const Returns true if the paint engine supports the specified \a feature; otherwise returns false. */ /*! \fn void QPaintEngine::updateState(const QPaintEngineState &state) Reimplement this function to update the state of a paint engine. When implemented, this function is responsible for checking the paint engine's current \a state and update the properties that are changed. Use the QPaintEngineState::state() function to find out which properties that must be updated, then use the corresponding \l {GetFunction}{get function} to retrieve the current values for the given properties. \sa QPaintEngineState */ /*! Creates a paint engine with the featureset specified by \a caps. */ QPaintEngine::QPaintEngine(PaintEngineFeatures caps) : state(0), gccaps(caps), active(0), selfDestruct(false), d_ptr(new QPaintEnginePrivate) { d_ptr->q_ptr = this; } /*! \internal */ QPaintEngine::QPaintEngine(QPaintEnginePrivate &dptr, PaintEngineFeatures caps) : state(0), gccaps(caps), active(0), selfDestruct(false), d_ptr(&dptr) { d_ptr->q_ptr = this; } /*! Destroys the paint engine. */ QPaintEngine::~QPaintEngine() { delete d_ptr; } /*! Returns the paint engine's painter. */ QPainter *QPaintEngine::painter() const { return state ? state->painter() : 0; } /*! The default implementation ignores the \a path and does nothing. */ void QPaintEngine::drawPath(const QPainterPath &) { if (hasFeature(PainterPaths)) { qWarning("QPaintEngine::drawPath: Must be implemented when feature PainterPaths is set"); } } /*! This function draws the text item \a textItem at position \a p. The default implementation of this function converts the text to a QPainterPath and paints the resulting path. */ void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) { const QTextItemInt &ti = static_cast(textItem); QPainterPath path; #ifndef Q_WS_MAC path.setFillRule(Qt::WindingFill); #endif if (ti.num_glyphs) ti.fontEngine->addOutlineToPath(p.x(), p.y(), ti.glyphs, ti.num_glyphs, &path, ti.flags); if (!path.isEmpty()) { painter()->save(); painter()->setRenderHint(QPainter::Antialiasing, bool((painter()->renderHints() & QPainter::TextAntialiasing) && !(painter()->font().styleStrategy() & QFont::NoAntialias))); painter()->setBrush(state->pen().brush()); painter()->setPen(Qt::NoPen); painter()->drawPath(path); painter()->restore(); } } /*! The default implementation splits the list of lines in \a lines into \a lineCount separate calls to drawPath() or drawPolygon() depending on the feature set of the paint engine. */ void QPaintEngine::drawLines(const QLineF *lines, int lineCount) { for (int i=0; ipenNeedsResolving() && !state->brushNeedsResolving()) { for (int i=0; ipdev = device; } /*! Returns the device that this engine is painting on, if painting is active; otherwise returns 0. */ QPaintDevice *QPaintEngine::paintDevice() const { return d_func()->pdev; } #ifdef Q_WS_WIN /*! \internal Empty default implementation. */ HDC QPaintEngine::getDC() const { return 0; } /*! \internal Empty default implementation. */ void QPaintEngine::releaseDC(HDC) const { } #endif /*! \internal Returns the offset from the painters origo to the engines origo. This value is used by QPainter for engines who have internal double buffering. This function only makes sense when the engine is active. */ QPoint QPaintEngine::coordinateOffset() const { return QPoint(); } /*! \internal Sets the system clip for this engine. The system clip defines the basis area that the engine has to draw in. All clips that are set must be an intersection with the system clip. Reset the systemclip to no clip by setting an empty region. */ void QPaintEngine::setSystemClip(const QRegion ®ion) { if (isActive()) { qWarning("QPaintEngine::setSystemClip: Should not be changed while engine is active"); return; } d_func()->systemClip = region; } /*! \internal Returns the system clip. The system clip is read only while the painter is active. An empty region indicates that system clip is not in use. */ QRegion QPaintEngine::systemClip() const { return d_func()->systemClip; } /*! \internal Sets the target rect for drawing within the backing store. This function should ONLY be used by the backing store. */ void QPaintEngine::setSystemRect(const QRect &rect) { if (isActive()) { qWarning("QPaintEngine::setSystemRect: Should not be changed while engine is active"); return; } d_func()->systemRect = rect; } /*! \internal Retreives the rect for drawing within the backing store. This function should ONLY be used by the backing store. */ QRect QPaintEngine::systemRect() const { return d_func()->systemRect; }