From b72d41cf30f82c74c10c31808907cc990c86efe6 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 3 Nov 2009 08:23:18 +1000 Subject: Protect the OpenVG engine from null QPixmapData objects Reviewed-by: Sarah Smith --- src/openvg/qpaintengine_vg.cpp | 10 ++++++++++ src/openvg/qpixmapdata_vg.cpp | 2 ++ src/openvg/qpixmapfilter_vg.cpp | 12 ++++++++++++ 3 files changed, 24 insertions(+) diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 8a485a0..047d9d8 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -1178,6 +1178,8 @@ VGPaintType QVGPaintEnginePrivate::setBrush case Qt::TexturePattern: { // The brush is a texture specified by a QPixmap/QImage. QPixmapData *pd = brush.texture().pixmapData(); + if (!pd) + break; // null QPixmap VGImage vgImg; bool deref = false; if (pd->pixelType() == QPixmapData::BitmapType) { @@ -2893,6 +2895,8 @@ void qt_vg_drawVGImageStencil void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { QPixmapData *pd = pm.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { Q_D(QVGPaintEngine); QVGPixmapData *vgpd = static_cast(pd); @@ -2910,6 +2914,8 @@ void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) { QPixmapData *pd = pm.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { Q_D(QVGPaintEngine); QVGPixmapData *vgpd = static_cast(pd); @@ -2985,6 +2991,8 @@ void QVGPaintEngine::drawPixmaps // If the pixmap is not VG, or the transformation is projective, // then fall back to the default implementation. QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() != QPixmapData::OpenVGClass || !d->simpleTransform) { QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); return; @@ -3581,6 +3589,8 @@ void QVGCompositionHelper::drawCursorPixmap // Fetch the VGImage from the pixmap if possible. QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast(pd); if (vgpd->isValid()) diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index f86e116..3254aa3 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -369,6 +369,8 @@ QImage::Format QVGPixmapData::sourceFormat() const Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap) { QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return VG_INVALID_HANDLE; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast(pd); if (vgpd->isValid()) diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp index 8e104db..e17c728 100644 --- a/src/openvg/qpixmapfilter_vg.cpp +++ b/src/openvg/qpixmapfilter_vg.cpp @@ -65,6 +65,9 @@ void QVGPixmapConvolutionFilter::draw (QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default convolution filter implementation. @@ -135,6 +138,9 @@ QVGPixmapColorizeFilter::~QVGPixmapColorizeFilter() void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default colorize filter implementation. @@ -225,6 +231,9 @@ QVGPixmapDropShadowFilter::~QVGPixmapDropShadowFilter() void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default drop shadow filter implementation. @@ -290,6 +299,9 @@ QVGPixmapBlurFilter::~QVGPixmapBlurFilter() void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default blur filter implementation. -- cgit v0.12 From 4eff66941486568cd25dc9aaa372f9d36b84dad8 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 3 Nov 2009 10:05:11 +0100 Subject: doc: Polish documentation for state machine framework Fix some examples and wording, and add some clarification based on comments in documentation review session. Reviewed-by: Kent Hansen --- doc/src/frameworks-technologies/statemachine.qdoc | 104 +++++++++++----------- doc/src/snippets/statemachine/main2.cpp | 11 +-- doc/src/snippets/statemachine/main5.cpp | 44 +++++++-- 3 files changed, 93 insertions(+), 66 deletions(-) diff --git a/doc/src/frameworks-technologies/statemachine.qdoc b/doc/src/frameworks-technologies/statemachine.qdoc index ed8bc85..ac10314 100644 --- a/doc/src/frameworks-technologies/statemachine.qdoc +++ b/doc/src/frameworks-technologies/statemachine.qdoc @@ -75,6 +75,11 @@ states can be configured to set properties and invoke methods on QObjects. Qt's event system is used to drive the state machines. + The state graph in the State Machine framework is hierarchical. States can be nested inside of + other states, and the current configuration of the state machine consists of the set of states + which are currently active. All the states in a valid configuration of the state machine will + have a common ancestor. + \section1 Classes in the State Machine Framework These classes are provided by qt for creating event-driven state machines. @@ -269,9 +274,17 @@ When a parallel state group is entered, all its child states will be simultaneously entered. Transitions within the individual child states - operate normally. However, any of the child states may take a transition - outside the parent state. When this happens, the parent state and all of its - child states are exited. + operate normally. However, any of the child states may take a transition which exits the parent + state. When this happens, the parent state and all of its child states are exited. + + The parallelism in the State Machine framework follows an interleaved semantics. All parallel + operations will be executed in a single, atomic step of the event processing, so no event can + interrupt the parallel operations. However, events will still be processed sequentially, since + the machine itself is single threaded. As an example: Consider the situation where there are two + transitions that exit the same parallel state group, and their conditions become true + simultaneously. In this case, the event that is processed last of the two will not have any + effect, since the first event will already have caused the machine to exit from the parallel + state. \section1 Detecting that a Composite State has Finished @@ -414,16 +427,7 @@ Take the following code: \code - QStateMachine machine; - machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); - - QState *s1 = new QState(); - s1->assignProperty(object, "fooBar", 1.0); - machine.addState(s1); - machine.setInitialState(s1); - - QState *s2 = new QState(); - machine.addState(s2); + \snippet doc/src/snippets/statemachine/main5.cpp 0 \endcode Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state @@ -434,19 +438,7 @@ If we are using nested states, the parent defines a value for the property which is inherited by all descendants that do not explicitly assign a value to the property. \code - QStateMachine machine; - machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); - - QState *s1 = new QState(); - s1->assignProperty(object, "fooBar", 1.0); - machine.addState(s1); - machine.setInitialState(s1); - - QState *s2 = new QState(s1); - s2->assignProperty(object, "fooBar", 2.0); - s1->setInitialState(s2); - - QState *s3 = new QState(s1); + \snippet doc/src/snippets/statemachine/main5.cpp 2 \endcode Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar @@ -461,13 +453,7 @@ Say we have the following code: \code - QState *s1 = new QState(); - QState *s2 = new QState(); - - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); - s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); - - s1->addTransition(button, SIGNAL(clicked()), s2); + \snippet doc/src/snippets/statemachine/main5.cpp 3 \endcode Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2 @@ -477,14 +463,7 @@ object. \code - QState *s1 = new QState(); - QState *s2 = new QState(); - - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); - s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); - - QSignalTransition *transition = s1->addTransition(button, SIGNAL(clicked()), s2); - transition->addAnimation(new QPropertyAnimation(button, "geometry")); + \snippet doc/src/snippets/statemachine/main5.cpp 4 \endcode Adding an animation for the property in question means that the property assignment will no @@ -504,28 +483,45 @@ property can potentially have any value, depending on the animation. In some cases, it can be useful to be able to detect when the property has actually been assigned - the value defined by a state. For this, we can use the state's polished() signal. + the value defined by a state. + + Say we have the following code: \code - QState *s1 = new QState(); - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + \snippet doc/src/snippets/statemachine/main5.cpp 5 + \endcode - QState *s2 = new QState(); + When \c button is clicked, the machine will transition into state \c s2, which will set the + geometry of the button, and then pop up a message box to alert the user that the geometry has + been changed. + + In the normal case, where animations are not used, this will operate as expected. However, if + an animation for the \c geometry of \c button is set on the transition between \c s1 and \c s2, + the animation will be started when \c s2 is entered, but the \c geometry property will not + actually reach its defined value before the animation is finished running. In this case, the + message box will pop up before the geometry of the button has actually been set. - s1->addTransition(s1, SIGNAL(polished()), s2); + To ensure that the message box does not pop up until the geometry actually reaches its final + value, we can use the state's polished() signal. The polished() signal will be emitted when the + the property is assigned its final value, whether this is done immediately or after the animation + has finished playing. + \code + \snippet doc/src/snippets/statemachine/main5.cpp 6 \endcode - The machine will be in state \c s1 until the \c geometry property has been set. Then it will - immediately transition into \c s2. If the transition into \c s1 has an animation for the \c - geometry property, then the machine will stay in \c s1 until the animation has finished. If there - is no animation, it will simply set the property and immediately enter state \c s2. + In this example, when \c button is clicked, the machine will enter \c s2. It will remain in state + \c s2 until the \c geometry property has been set to \c QRect(0, 0, 50, 50). Then it will + transition into \c s3. When \c s3 is entered, the message box will pop up. If the transition into + \c s2 has an animation for the \c geometry property, then the machine will stay in \c s2 until the + animation has finished playing. If there is no such animation, it will simply set the property and + immediately enter state \c s3. - Either way, when the machine is in state \c s2, the property \c geometry has been assigned the - defined value. + Either way, when the machine is in state \c s3, you are guaranteed that the property \c geometry + has been assigned the defined value. If the global restore policy is set to QStateMachine::RestoreProperties, the state will not emit the polished() signal until these have been executed as well. - \section1 What happens if a state is exited before the animation has finished + \section1 What Happens If A State Is Exited Before The Animation Has Finished If a state has property assignments, and the transition into the state has animations for the properties, the state can potentially be exited before the properties have been assigned to the @@ -545,7 +541,7 @@ If the target state does not assign any value to the property, there are two options: By default, the property will be assigned the value defined by the state it is leaving - (the value it would have been assigned if the animation had been permitted to finish playing.) If + (the value it would have been assigned if the animation had been permitted to finish playing). If a global restore policy is set, however, this will take precedence, and the property will be restored as usual. diff --git a/doc/src/snippets/statemachine/main2.cpp b/doc/src/snippets/statemachine/main2.cpp index 2419dc2..9a2890f 100644 --- a/doc/src/snippets/statemachine/main2.cpp +++ b/doc/src/snippets/statemachine/main2.cpp @@ -69,17 +69,18 @@ int main(int argv, char **args) //![1] QButton *interruptButton = new QPushButton("Interrupt Button"); + QWidget *mainWindow = new QWidget(); //![3] QHistoryState *s1h = new QHistoryState(s1); QState *s3 = new QState(); s3->assignProperty(label, "text", "In s3"); - QMessageBox mbox; - mbox.addButton(QMessageBox::Ok); - mbox.setText("Interrupted!"); - mbox.setIcon(QMessageBox::Information); - QObject::connect(s3, SIGNAL(entered()), &mbox, SLOT(exec())); + QMessageBox *mbox = new QMessageBox(mainWindow); + mbox->addButton(QMessageBox::Ok); + mbox->setText("Interrupted!"); + mbox->setIcon(QMessageBox::Information); + QObject::connect(s3, SIGNAL(entered()), mbox, SLOT(exec())); s3->addTransition(s1h); machine.addState(s3); diff --git a/doc/src/snippets/statemachine/main5.cpp b/doc/src/snippets/statemachine/main5.cpp index a9d4091..346cbce 100644 --- a/doc/src/snippets/statemachine/main5.cpp +++ b/doc/src/snippets/statemachine/main5.cpp @@ -44,14 +44,13 @@ int main(int argv, char **args) { QApplication app(argv, args); + QWidget *button; { //![0] QStateMachine machine; machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); -//![0] -//![1] QState *s1 = new QState(); s1->assignProperty(object, "fooBar", 1.0); machine.addState(s1); @@ -59,7 +58,7 @@ int main(int argv, char **args) QState *s2 = new QState(); machine.addState(s2); -//![1] +//![0] } { @@ -110,21 +109,50 @@ int main(int argv, char **args) } { + QMainWindow *mainWindow = 0; //![5] + QMessageBox *messageBox = new QMessageBox(mainWindow); + messageBox->addButton(QMessageBox::Ok); + messageBox->setText("Button geometry has been set!"); + messageBox->setIcon(QMessageBox::Information); + QState *s1 = new QState(); - s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); QState *s2 = new QState(); + s2->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + connect(s2, SIGNAL(entered()), messageBox, SLOT(exec())); - s1->addTransition(s1, SIGNAL(polished()), s2); + s1->addTransition(button, SIGNAL(clicked()), s2); //![5] - } { + QMainWindow *mainWindow = 0; + +//![6] + QMessageBox *messageBox = new QMessageBox(mainWindow); + messageBox->addButton(QMessageBox::Ok); + messageBox->setText("Button geometry has been set!"); + messageBox->setIcon(QMessageBox::Information); + + QState *s1 = new QState(); + + QState *s2 = new QState(); + s2->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + + QState *s3 = new QState(); + connect(s3, SIGNAL(entered()), messageBox, SLOT(exec())); + s1->addTransition(button, SIGNAL(clicked()), s2); + s2->addTransition(s2, SIGNAL(polished()), s3); //![6] + + } + + { + +//![7] QState *s1 = new QState(); QState *s2 = new QState(); @@ -134,10 +162,12 @@ int main(int argv, char **args) QStateMachine machine; machine.setInitialState(s1); machine.addDefaultAnimation(new QPropertyAnimation(object, "fooBar")); -//![6] +//![7] } + + return app.exec(); } -- cgit v0.12 From 1fd46b4495241ed03371fb5c86965b788791b363 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 3 Nov 2009 11:45:16 +0100 Subject: Embed code examples in state machine overview If you put \snippet inside \code tags, it's interpreted as code, not as a tag. Reviewed-by: Trust me --- doc/src/frameworks-technologies/statemachine.qdoc | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/doc/src/frameworks-technologies/statemachine.qdoc b/doc/src/frameworks-technologies/statemachine.qdoc index ac10314..9614dd3 100644 --- a/doc/src/frameworks-technologies/statemachine.qdoc +++ b/doc/src/frameworks-technologies/statemachine.qdoc @@ -426,9 +426,8 @@ value of the property before any property assignments in states were executed.) Take the following code: - \code - \snippet doc/src/snippets/statemachine/main5.cpp 0 - \endcode + + \snippet doc/src/snippets/statemachine/main5.cpp 0 Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state \c s1, the property will be 1.0, since the state explicitly assigns this value to it. When the @@ -437,9 +436,8 @@ If we are using nested states, the parent defines a value for the property which is inherited by all descendants that do not explicitly assign a value to the property. - \code + \snippet doc/src/snippets/statemachine/main5.cpp 2 - \endcode Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar will have the value 2.0, since this is explicitly defined for the state. When the machine is in @@ -452,9 +450,8 @@ properties as they are assigned in states. Say we have the following code: - \code + \snippet doc/src/snippets/statemachine/main5.cpp 3 - \endcode Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2 it is bigger. If we click the button to transition from \c s1 to \c s2, the geometry of the button @@ -462,9 +459,7 @@ smooth, however, all we need to do is make a QPropertyAnimation and add this to the transition object. - \code \snippet doc/src/snippets/statemachine/main5.cpp 4 - \endcode Adding an animation for the property in question means that the property assignment will no longer take immediate effect when the state has been entered. Instead, the animation will start @@ -486,9 +481,8 @@ the value defined by a state. Say we have the following code: - \code + \snippet doc/src/snippets/statemachine/main5.cpp 5 - \endcode When \c button is clicked, the machine will transition into state \c s2, which will set the geometry of the button, and then pop up a message box to alert the user that the geometry has @@ -504,9 +498,8 @@ value, we can use the state's polished() signal. The polished() signal will be emitted when the the property is assigned its final value, whether this is done immediately or after the animation has finished playing. - \code + \snippet doc/src/snippets/statemachine/main5.cpp 6 - \endcode In this example, when \c button is clicked, the machine will enter \c s2. It will remain in state \c s2 until the \c geometry property has been set to \c QRect(0, 0, 50, 50). Then it will -- cgit v0.12 From 68be6457f6732437b485812ab2db11c147a24b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 3 Nov 2009 12:15:53 +0100 Subject: Removed usage of CompositionMode_Source in QGraphicsView for X11. Due to the rendering model in XRender ((src IN mask) OP dest) we can't support the PorterDuff composition modes natively under X11. They just behave differently than what we've defined them to do in QPainter, and there is no apparent workaround. Task-number: QTBUG-4829 Reviewed-by: Gunnar --- src/gui/graphicsview/qgraphicsview.cpp | 8 +++++++- src/gui/painting/qpainter.cpp | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 710c745..8945f51 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -281,6 +281,7 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < #include #include #ifdef Q_WS_X11 +#include #include #endif @@ -3294,7 +3295,12 @@ void QGraphicsView::paintEvent(QPaintEvent *event) backgroundPainter.setClipRegion(d->backgroundPixmapExposed, Qt::ReplaceClip); if (viewTransformed) backgroundPainter.setTransform(viewTransform); - backgroundPainter.setCompositionMode(QPainter::CompositionMode_Source); +#ifdef Q_WS_X11 +#undef X11 + if (backgroundPainter.paintEngine()->type() != QPaintEngine::X11) +#define X11 qt_x11Data +#endif + backgroundPainter.setCompositionMode(QPainter::CompositionMode_Source); drawBackground(&backgroundPainter, exposedSceneRect); d->backgroundPixmapExposed = QRegion(); } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index cddad7d..8d6cad3 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -2275,8 +2275,9 @@ void QPainter::setBrushOrigin(const QPointF &p) /*! 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. + \warning Only a QPainter operating on a QImage fully supports all + composition modes. The RasterOp modes are supported for X11 as + described in compositionMode(). \sa compositionMode() */ -- cgit v0.12