10#include "qwt_graphic.h" 
   11#include "qwt_painter_command.h" 
   16#include <qpaintengine.h> 
   19#include <qpainterpath.h> 
   21#if QT_VERSION >= 0x050000 
   23#include <qguiapplication.h> 
   25static inline qreal qwtDevicePixelRatio()
 
   27    return qGuiApp ? qGuiApp->devicePixelRatio() : 1.0;
 
   32static bool qwtHasScalablePen( 
const QPainter* painter )
 
   34    const QPen pen = painter->pen();
 
   36    bool scalablePen = 
false;
 
   38    if ( pen.style() != Qt::NoPen && pen.brush().style() != Qt::NoBrush )
 
   40        scalablePen = !pen.isCosmetic();
 
   41#if QT_VERSION < 0x050000 
   42        if ( !scalablePen && pen.widthF() == 0.0 )
 
   44            const QPainter::RenderHints hints = painter->renderHints();
 
   45            if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) )
 
   54static QRectF qwtStrokedPathRect(
 
   55    const QPainter* painter, 
const QPainterPath& path )
 
   57    QPainterPathStroker stroker;
 
   58    stroker.setWidth( painter->pen().widthF() );
 
   59    stroker.setCapStyle( painter->pen().capStyle() );
 
   60    stroker.setJoinStyle( painter->pen().joinStyle() );
 
   61    stroker.setMiterLimit( painter->pen().miterLimit() );
 
   64    if ( qwtHasScalablePen( painter ) )
 
   66        QPainterPath stroke = stroker.createStroke( path );
 
   67        rect = painter->transform().map( stroke ).boundingRect();
 
   71        QPainterPath mappedPath = painter->transform().map( path );
 
   72        mappedPath = stroker.createStroke( mappedPath );
 
   74        rect = mappedPath.boundingRect();
 
   80static inline void qwtExecCommand(
 
   83    const QTransform& transform,
 
   84    const QTransform* initialTransform )
 
   92            if ( painter->transform().isScaling() )
 
   94                bool isCosmetic = painter->pen().isCosmetic();
 
   95#if QT_VERSION < 0x050000 
   96                if ( isCosmetic && painter->pen().widthF() == 0.0 )
 
   98                    QPainter::RenderHints hints = painter->renderHints();
 
   99                    if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) )
 
  109                    doMap = painter->paintEngine()->type() == QPaintEngine::OpenGL2;
 
  119                const QTransform tr = painter->transform();
 
  121                painter->resetTransform();
 
  123                QPainterPath path = tr.map( *cmd.
path() );
 
  124                if ( initialTransform )
 
  126                    painter->setTransform( *initialTransform );
 
  127                    path = initialTransform->inverted().map( path );
 
  130                painter->drawPath( path );
 
  132                painter->setTransform( tr );
 
  136                painter->drawPath( *cmd.
path() );
 
  142            const QwtPainterCommand::PixmapData* data = cmd.
pixmapData();
 
  143            painter->drawPixmap( data->rect, data->pixmap, data->subRect );
 
  148            const QwtPainterCommand::ImageData* data = cmd.
imageData();
 
  149            painter->drawImage( data->rect, data->image,
 
  150                data->subRect, data->flags );
 
  155            const QwtPainterCommand::StateData* data = cmd.
stateData();
 
  157            if ( data->flags & QPaintEngine::DirtyPen )
 
  158                painter->setPen( data->pen );
 
  160            if ( data->flags & QPaintEngine::DirtyBrush )
 
  161                painter->setBrush( data->brush );
 
  163            if ( data->flags & QPaintEngine::DirtyBrushOrigin )
 
  164                painter->setBrushOrigin( data->brushOrigin );
 
  166            if ( data->flags & QPaintEngine::DirtyFont )
 
  167                painter->setFont( data->font );
 
  169            if ( data->flags & QPaintEngine::DirtyBackground )
 
  171                painter->setBackgroundMode( data->backgroundMode );
 
  172                painter->setBackground( data->backgroundBrush );
 
  175            if ( data->flags & QPaintEngine::DirtyTransform )
 
  177                painter->setTransform( data->transform * transform );
 
  180            if ( data->flags & QPaintEngine::DirtyClipEnabled )
 
  181                painter->setClipping( data->isClipEnabled );
 
  183            if ( data->flags & QPaintEngine::DirtyClipRegion )
 
  185                painter->setClipRegion( data->clipRegion,
 
  186                    data->clipOperation );
 
  189            if ( data->flags & QPaintEngine::DirtyClipPath )
 
  191                painter->setClipPath( data->clipPath, data->clipOperation );
 
  194            if ( data->flags & QPaintEngine::DirtyHints )
 
  196                for ( 
int i = 0; i < 8; i++ )
 
  198                    const QPainter::RenderHint hint = 
static_cast< QPainter::RenderHint 
>( 1 << i );
 
  199                    painter->setRenderHint( hint, data->renderHints.testFlag( hint ) );
 
  203            if ( data->flags & QPaintEngine::DirtyCompositionMode )
 
  204                painter->setCompositionMode( data->compositionMode );
 
  206            if ( data->flags & QPaintEngine::DirtyOpacity )
 
  207                painter->setOpacity( data->opacity );
 
  216class QwtGraphic::PathInfo
 
  220        : m_scalablePen( false )
 
  225    PathInfo( 
const QRectF& pointRect,
 
  227        : m_pointRect( pointRect )
 
  229        , m_scalablePen( scalablePen )
 
  233    inline QRectF scaledBoundingRect( qreal sx, qreal sy, 
bool scalePens )
 const 
  235        if ( sx == 1.0 && sy == 1.0 )
 
  236            return m_boundingRect;
 
  238        QTransform transform;
 
  239        transform.scale( sx, sy );
 
  242        if ( scalePens && m_scalablePen )
 
  244            rect = transform.mapRect( m_boundingRect );
 
  248            rect = transform.mapRect( m_pointRect );
 
  250            const qreal l = qAbs( m_pointRect.left() - m_boundingRect.left() );
 
  251            const qreal r = qAbs( m_pointRect.right() - m_boundingRect.right() );
 
  252            const qreal t = qAbs( m_pointRect.top() - m_boundingRect.top() );
 
  253            const qreal b = qAbs( m_pointRect.bottom() - m_boundingRect.bottom() );
 
  255            rect.adjust( -l, -t, r, b );
 
  261    inline double scaleFactorX( 
const QRectF& pathRect,
 
  262        const QRectF& targetRect, 
bool scalePens )
 const 
  264        if ( pathRect.width() <= 0.0 )
 
  267        const QPointF p0 = m_pointRect.center();
 
  269        const qreal l = qAbs( pathRect.left() - p0.x() );
 
  270        const qreal r = qAbs( pathRect.right() - p0.x() );
 
  272        const double w = 2.0 * qwtMinF( l, r )
 
  273            * targetRect.width() / pathRect.width();
 
  276        if ( scalePens && m_scalablePen )
 
  278            sx = w / m_boundingRect.width();
 
  282            const qreal pw = qwtMaxF(
 
  283                qAbs( m_boundingRect.left() - m_pointRect.left() ),
 
  284                qAbs( m_boundingRect.right() - m_pointRect.right() ) );
 
  286            sx = ( w - 2 * pw ) / m_pointRect.width();
 
  292    inline double scaleFactorY( 
const QRectF& pathRect,
 
  293        const QRectF& targetRect, 
bool scalePens )
 const 
  295        if ( pathRect.height() <= 0.0 )
 
  298        const QPointF p0 = m_pointRect.center();
 
  300        const qreal t = qAbs( pathRect.top() - p0.y() );
 
  301        const qreal b = qAbs( pathRect.bottom() - p0.y() );
 
  303        const qreal h = 2.0 * qwtMinF( t, b )
 
  304            * targetRect.height() / pathRect.height();
 
  307        if ( scalePens && m_scalablePen )
 
  309            sy = h / m_boundingRect.height();
 
  313            const qreal pw = qwtMaxF(
 
  314                qAbs( m_boundingRect.top() - m_pointRect.top() ),
 
  315                qAbs( m_boundingRect.bottom() - m_pointRect.bottom() ) );
 
  317            sy = ( h - 2 * pw ) / m_pointRect.height();
 
  325    QRectF m_boundingRect;
 
  329class QwtGraphic::PrivateData
 
  333        : boundingRect( 0.0, 0.0, -1.0, -1.0 )
 
  334        , pointRect( 0.0, 0.0, -1.0, -1.0 )
 
  358    m_data = 
new PrivateData;
 
 
  370    m_data = 
new PrivateData( *other.m_data );
 
 
  388    *m_data = *other.m_data;
 
 
  399    m_data->commands.clear();
 
  400    m_data->pathInfos.clear();
 
  404    m_data->boundingRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
 
  405    m_data->pointRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
 
  406    m_data->defaultSize = QSizeF();
 
 
  415    return m_data->commands.isEmpty();
 
 
  424    return m_data->boundingRect.isEmpty();
 
 
  432    return m_data->commandTypes;
 
 
  446        m_data->renderHints |= hint;
 
  448        m_data->renderHints &= ~hint;
 
 
  460    return m_data->renderHints.testFlag( hint );
 
 
  466    return m_data->renderHints;
 
 
  479    if ( m_data->boundingRect.width() < 0 )
 
  482    return m_data->boundingRect;
 
 
  495    if ( m_data->pointRect.width() < 0 )
 
  498    return m_data->pointRect;
 
 
  516    if ( sx == 1.0 && sy == 1.0 )
 
  517        return m_data->boundingRect;
 
  521    QTransform transform;
 
  522    transform.scale( sx, sy );
 
  524    QRectF rect = transform.mapRect( m_data->pointRect );
 
  526    for ( 
int i = 0; i < m_data->pathInfos.size(); i++ )
 
  527        rect |= m_data->pathInfos[i].scaledBoundingRect( sx, sy, scalePens );
 
 
  536    return QSize( qwtCeil( sz.width() ), qwtCeil( sz.height() ) );
 
 
  555    const double w = qwtMaxF( 0.0, size.width() );
 
  556    const double h = qwtMaxF( 0.0, size.height() );
 
  558    m_data->defaultSize = QSizeF( w, h );
 
 
  576    if ( !m_data->defaultSize.isEmpty() )
 
  577        return m_data->defaultSize;
 
 
  598    return sz.height() * width / sz.width();
 
 
  617    return sz.width() * height / sz.height();
 
 
  626    renderGraphic( painter, NULL );
 
 
  629void QwtGraphic::renderGraphic( QPainter* painter, QTransform* initialTransform )
 const 
  634    const int numCommands = m_data->commands.size();
 
  637    const QTransform transform = painter->transform();
 
  641    for ( 
int i = 0; i < numCommands; i++ )
 
  643        qwtExecCommand( painter, 
commands[i],
 
  644            m_data->renderHints, transform, initialTransform );
 
  661    Qt::AspectRatioMode aspectRatioMode )
 const 
  663    const QRectF r( 0.0, 0.0, size.width(), size.height() );
 
  664    render( painter, r, aspectRatioMode );
 
 
  677    Qt::AspectRatioMode aspectRatioMode )
 const 
  679    if ( 
isEmpty() || rect.isEmpty() )
 
  685    if ( m_data->pointRect.width() > 0.0 )
 
  686        sx = rect.width() / m_data->pointRect.width();
 
  688    if ( m_data->pointRect.height() > 0.0 )
 
  689        sy = rect.height() / m_data->pointRect.height();
 
  693    for ( 
int i = 0; i < m_data->pathInfos.size(); i++ )
 
  695        const PathInfo& info = m_data->pathInfos[i];
 
  697        const double ssx = info.scaleFactorX(
 
  698            m_data->pointRect, rect, scalePens );
 
  701            sx = qwtMinF( sx, ssx );
 
  703        const double ssy = info.scaleFactorY(
 
  704            m_data->pointRect, rect, scalePens );
 
  707            sy = qwtMinF( sy, ssy );
 
  710    if ( aspectRatioMode == Qt::KeepAspectRatio )
 
  712        const qreal s = qwtMinF( sx, sy );
 
  716    else if ( aspectRatioMode == Qt::KeepAspectRatioByExpanding )
 
  718        const qreal s = qwtMaxF( sx, sy );
 
  724    tr.translate( rect.center().x() - 0.5 * sx * m_data->pointRect.width(),
 
  725        rect.center().y() - 0.5 * sy * m_data->pointRect.height() );
 
  727    tr.translate( -m_data->pointRect.x(), -m_data->pointRect.y() );
 
  729    const QTransform transform = painter->transform();
 
  731    painter->setTransform( tr, 
true );
 
  733    if ( !scalePens && transform.isScaling() )
 
  739        QTransform initialTransform;
 
  740        initialTransform.scale( transform.m11(), transform.m22() );
 
  742        renderGraphic( painter, &initialTransform );
 
  746        renderGraphic( painter, NULL );
 
  749    painter->setTransform( transform );
 
 
  763    const QPointF& pos, Qt::Alignment alignment )
 const 
  767    if ( alignment & Qt::AlignLeft )
 
  769        r.moveLeft( pos.x() );
 
  771    else if ( alignment & Qt::AlignHCenter )
 
  773        r.moveCenter( QPointF( pos.x(), r.center().y() ) );
 
  775    else if ( alignment & Qt::AlignRight )
 
  777        r.moveRight( pos.x() );
 
  780    if ( alignment & Qt::AlignTop )
 
  782        r.moveTop( pos.y() );
 
  784    else if ( alignment & Qt::AlignVCenter )
 
  786        r.moveCenter( QPointF( r.center().x(), pos.y() ) );
 
  788    else if ( alignment & Qt::AlignBottom )
 
  790        r.moveBottom( pos.y() );
 
 
  819#if QT_VERSION >= 0x050000 
  820    if ( devicePixelRatio <= 0.0 )
 
  821        devicePixelRatio = qwtDevicePixelRatio();
 
  823    const int w = qwtCeil( sz.width() * devicePixelRatio );
 
  824    const int h = qwtCeil( sz.height() * devicePixelRatio );
 
  826    QPixmap pixmap( w, h );
 
  827    pixmap.setDevicePixelRatio( devicePixelRatio );
 
  829    Q_UNUSED( devicePixelRatio )
 
  831    const int w = qwtCeil( sz.width() );
 
  832    const int h = qwtCeil( sz.height() );
 
  834    QPixmap pixmap( w, h );
 
  837    pixmap.fill( Qt::transparent );
 
  839    const QRectF r( 0.0, 0.0, sz.width(), sz.height() );
 
  841    QPainter painter( &pixmap );
 
  842    render( &painter, r, Qt::KeepAspectRatio );
 
 
  864    Qt::AspectRatioMode aspectRatioMode, qreal devicePixelRatio )
 const 
  866#if QT_VERSION >= 0x050000 
  867    if ( devicePixelRatio <= 0.0 )
 
  868        devicePixelRatio = qwtDevicePixelRatio();
 
  870    const int w = qwtCeil( size.width() * devicePixelRatio );
 
  871    const int h = qwtCeil( size.height() * devicePixelRatio );
 
  873    QPixmap pixmap( w, h );
 
  874    pixmap.setDevicePixelRatio( devicePixelRatio );
 
  876    Q_UNUSED( devicePixelRatio )
 
  877    QPixmap pixmap( size );
 
  879    pixmap.fill( Qt::transparent );
 
  881    const QRect r( 0, 0, size.width(), size.height() );
 
  883    QPainter painter( &pixmap );
 
  884    render( &painter, r, aspectRatioMode );
 
 
  908    Qt::AspectRatioMode aspectRatioMode, qreal devicePixelRatio  )
 const 
  910#if QT_VERSION >= 0x050000 
  911    if ( devicePixelRatio <= 0.0 )
 
  912        devicePixelRatio = qwtDevicePixelRatio();
 
  914    const int w = qwtCeil( size.width() * devicePixelRatio );
 
  915    const int h = qwtCeil( size.height() * devicePixelRatio );
 
  917    QImage image( w, h, QImage::Format_ARGB32_Premultiplied );
 
  918    image.setDevicePixelRatio( devicePixelRatio );
 
  920    Q_UNUSED( devicePixelRatio )
 
  921    QImage image( size, QImage::Format_ARGB32_Premultiplied );
 
  926    const QRect r( 0, 0, size.width(), size.height() );
 
  928    QPainter painter( &image );
 
  929    render( &painter, r, aspectRatioMode );
 
 
  960#if QT_VERSION >= 0x050000 
  961    if ( devicePixelRatio <= 0.0 )
 
  962        devicePixelRatio = qwtDevicePixelRatio();
 
  964    const int w = qwtCeil( sz.width() * devicePixelRatio );
 
  965    const int h = qwtCeil( sz.height() * devicePixelRatio );
 
  967    QImage image( w, h, QImage::Format_ARGB32 );
 
  968    image.setDevicePixelRatio( devicePixelRatio );
 
  970    Q_UNUSED( devicePixelRatio )
 
  972    const int w = qwtCeil( sz.width() );
 
  973    const int h = qwtCeil( sz.height() );
 
  975    QImage image( w, h, QImage::Format_ARGB32 );
 
  980    const QRect r( 0, 0, sz.width(), sz.height() );
 
  982    QPainter painter( &image );
 
  983    render( &painter, r, Qt::KeepAspectRatio );
 
 
  997    const QPainter* painter = 
paintEngine()->painter();
 
  998    if ( painter == NULL )
 
 1004    if ( !path.isEmpty() )
 
 1006        const QPainterPath scaledPath = painter->transform().map( path );
 
 1008        QRectF pointRect = scaledPath.boundingRect();
 
 1011        if ( painter->pen().style() != Qt::NoPen
 
 1012            && painter->pen().brush().style() != Qt::NoBrush )
 
 1017        updateControlPointRect( pointRect );
 
 1020        m_data->pathInfos += PathInfo( pointRect,
 
 
 1035    const QPixmap& pixmap, 
const QRectF& subRect )
 
 1037    const QPainter* painter = 
paintEngine()->painter();
 
 1038    if ( painter == NULL )
 
 1044    const QRectF r = painter->transform().mapRect( rect );
 
 1045    updateControlPointRect( r );
 
 1046    updateBoundingRect( r );
 
 
 1060    const QRectF& subRect, Qt::ImageConversionFlags flags )
 
 1062    const QPainter* painter = 
paintEngine()->painter();
 
 1063    if ( painter == NULL )
 
 1069    const QRectF r = painter->transform().mapRect( rect );
 
 1071    updateControlPointRect( r );
 
 1072    updateBoundingRect( r );
 
 
 1085    if ( state.state() & QPaintEngine::DirtyTransform )
 
 1094            if ( state.transform().isScaling() )
 
 
 1100void QwtGraphic::updateBoundingRect( 
const QRectF& rect )
 
 1104    const QPainter* painter = 
paintEngine()->painter();
 
 1105    if ( painter && painter->hasClipping() )
 
 1107        QRectF cr = painter->clipRegion().boundingRect();
 
 1108        cr = painter->transform().mapRect( cr );
 
 1113    if ( m_data->boundingRect.width() < 0 )
 
 1114        m_data->boundingRect = br;
 
 1116        m_data->boundingRect |= br;
 
 1119void QwtGraphic::updateControlPointRect( 
const QRectF& rect )
 
 1121    if ( m_data->pointRect.width() < 0.0 )
 
 1122        m_data->pointRect = rect;
 
 1124        m_data->pointRect |= rect;
 
 1133    return m_data->commands;
 
 
 1146    const int numCommands = 
commands.size();
 
 1147    if ( numCommands <= 0 )
 
 1155    const QTransform noTransform;
 
 1158    QPainter painter( 
this );
 
 1159    for ( 
int i = 0; i < numCommands; i++ )
 
 1160        qwtExecCommand( &painter, cmds[i], noRenderHints, noTransform, NULL );
 
 
A paint device for scalable graphics.
qreal heightForWidth(qreal width) const
virtual ~QwtGraphic()
Destructor.
virtual void updateState(const QPaintEngineState &) override
Store a state command in the command list.
bool testRenderHint(RenderHint) const
void reset()
Clear all stored commands.
void setRenderHint(RenderHint, bool on=true)
QwtGraphic & operator=(const QwtGraphic &)
Assignment operator.
QImage toImage(qreal devicePixelRatio=0.0) const
Convert the graphic to a QImage.
QPixmap toPixmap(qreal devicePixelRatio=0.0) const
Convert the graphic to a QPixmap.
qreal widthForHeight(qreal height) const
QFlags< RenderHint > RenderHints
QFlags< CommandType > CommandTypes
QRectF controlPointRect() const
virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) override
Store a pixmap command in the command list.
CommandTypes commandTypes() const
@ VectorData
The graphic contains scalable vector data.
@ Transformation
The graphic contains transformations beyond simple translations.
@ RasterData
The graphic contains raster data ( QPixmap or QImage )
QSizeF defaultSize() const
Default size.
virtual QSize sizeMetrics() const override
void setDefaultSize(const QSizeF &)
Set a default size.
void setCommands(const QVector< QwtPainterCommand > &)
Append paint commands.
const QVector< QwtPainterCommand > & commands() const
virtual void drawPath(const QPainterPath &) override
QRectF scaledBoundingRect(qreal sx, qreal sy) const
Calculate the target rectangle for scaling the graphic.
RenderHints renderHints() const
QRectF boundingRect() const
void render(QPainter *) const
Replay all recorded painter commands.
virtual void drawImage(const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags) override
Store a image command in the command list.
virtual QPaintEngine * paintEngine() const override
See QPaintDevice::paintEngine()
@ Path
Draw a QPainterPath.
@ State
QPainter state change.
PixmapData * pixmapData()