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> 
   25 static inline qreal qwtDevicePixelRatio()
 
   27     return qGuiApp ? qGuiApp->devicePixelRatio() : 1.0;
 
   32 static 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 ) )
 
   54 static 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();
 
   80 static 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 );
 
  216 class QwtGraphic::PathInfo
 
  220         : m_scalablePen( false )
 
  225     PathInfo( 
const QRectF& pointRect,
 
  227         : m_pointRect( pointRect )
 
  229         , m_scalablePen( scalablePen )
 
  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;
 
  329 class QwtGraphic::PrivateData
 
  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 );
 
  629 void 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     const int w = qwtCeil( sz.width() );
 
  820     const int h = qwtCeil( sz.height() );
 
  822     QPixmap pixmap( w, h );
 
  824 #if QT_VERSION >= 0x050000 
  825     if ( devicePixelRatio <= 0.0 )
 
  826         devicePixelRatio = qwtDevicePixelRatio();
 
  828     pixmap.setDevicePixelRatio( devicePixelRatio );
 
  830     Q_UNUSED( devicePixelRatio )
 
  833     pixmap.fill( Qt::transparent );
 
  835     const QRectF r( 0.0, 0.0, sz.width(), sz.height() );
 
  837     QPainter painter( &pixmap );
 
  838     render( &painter, r, Qt::KeepAspectRatio );
 
  860     Qt::AspectRatioMode aspectRatioMode, qreal devicePixelRatio )
 const 
  862     QPixmap pixmap( size );
 
  864 #if QT_VERSION >= 0x050000 
  865     if ( devicePixelRatio <= 0.0 )
 
  866         devicePixelRatio = qwtDevicePixelRatio();
 
  868     pixmap.setDevicePixelRatio( devicePixelRatio );
 
  870     Q_UNUSED( devicePixelRatio )
 
  872     pixmap.fill( Qt::transparent );
 
  874     const QRect r( 0, 0, size.width(), size.height() );
 
  876     QPainter painter( &pixmap );
 
  877     render( &painter, r, aspectRatioMode );
 
  901     Qt::AspectRatioMode aspectRatioMode, qreal devicePixelRatio  )
 const 
  903 #if QT_VERSION >= 0x050000 
  904     if ( devicePixelRatio <= 0.0 )
 
  905         devicePixelRatio = qwtDevicePixelRatio();
 
  907     QImage image( size* devicePixelRatio, QImage::Format_ARGB32_Premultiplied );
 
  908     image.setDevicePixelRatio( devicePixelRatio );
 
  910     Q_UNUSED( devicePixelRatio )
 
  911     QImage image( size, QImage::Format_ARGB32_Premultiplied );
 
  916     const QRect r( 0, 0, size.width(), size.height() );
 
  918     QPainter painter( &image );
 
  919     render( &painter, r, aspectRatioMode );
 
  950     int w = qwtCeil( sz.width() );
 
  951     int h = qwtCeil( sz.height() );
 
  953 #if QT_VERSION >= 0x050000 
  954     if ( devicePixelRatio <= 0.0 )
 
  955         devicePixelRatio = qwtDevicePixelRatio();
 
  957     w *= devicePixelRatio;
 
  958     h *= devicePixelRatio;
 
  960     QImage image( w, h, QImage::Format_ARGB32 );
 
  961     image.setDevicePixelRatio( devicePixelRatio );
 
  963     Q_UNUSED( devicePixelRatio )
 
  964     QImage image( w, h, QImage::Format_ARGB32 );
 
  969     const QRect r( 0, 0, sz.width(), sz.height() );
 
  971     QPainter painter( &image );
 
  972     render( &painter, r, Qt::KeepAspectRatio );
 
  986     const QPainter* painter = 
paintEngine()->painter();
 
  987     if ( painter == NULL )
 
  993     if ( !path.isEmpty() )
 
  995         const QPainterPath scaledPath = painter->transform().map( path );
 
  997         QRectF pointRect = scaledPath.boundingRect();
 
 1000         if ( painter->pen().style() != Qt::NoPen
 
 1001             && painter->pen().brush().style() != Qt::NoBrush )
 
 1006         updateControlPointRect( pointRect );
 
 1009         m_data->pathInfos += PathInfo( pointRect,
 
 1024     const QPixmap& pixmap, 
const QRectF& subRect )
 
 1026     const QPainter* painter = 
paintEngine()->painter();
 
 1027     if ( painter == NULL )
 
 1033     const QRectF r = painter->transform().mapRect( rect );
 
 1034     updateControlPointRect( r );
 
 1035     updateBoundingRect( r );
 
 1049     const QRectF& subRect, Qt::ImageConversionFlags flags )
 
 1051     const QPainter* painter = 
paintEngine()->painter();
 
 1052     if ( painter == NULL )
 
 1058     const QRectF r = painter->transform().mapRect( rect );
 
 1060     updateControlPointRect( r );
 
 1061     updateBoundingRect( r );
 
 1074     if ( state.state() & QPaintEngine::DirtyTransform )
 
 1083             if ( state.transform().isScaling() )
 
 1089 void QwtGraphic::updateBoundingRect( 
const QRectF& rect )
 
 1093     const QPainter* painter = 
paintEngine()->painter();
 
 1094     if ( painter && painter->hasClipping() )
 
 1096         QRectF cr = painter->clipRegion().boundingRect();
 
 1097         cr = painter->transform().mapRect( cr );
 
 1102     if ( m_data->boundingRect.width() < 0 )
 
 1103         m_data->boundingRect = br;
 
 1105         m_data->boundingRect |= br;
 
 1108 void QwtGraphic::updateControlPointRect( 
const QRectF& rect )
 
 1110     if ( m_data->pointRect.width() < 0.0 )
 
 1111         m_data->pointRect = rect;
 
 1113         m_data->pointRect |= rect;
 
 1122     return m_data->commands;
 
 1135     const int numCommands = 
commands.size();
 
 1136     if ( numCommands <= 0 )
 
 1144     const QTransform noTransform;
 
 1147     QPainter painter( 
this );
 
 1148     for ( 
int i = 0; i < numCommands; i++ )
 
 1149         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()