diff options
-rw-r--r-- | src/corelib/kernel/qabstracteventdispatcher.cpp | 52 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_s60.cpp | 7 | ||||
-rw-r--r-- | src/gui/kernel/qwidget_s60.cpp | 4 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 52 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qapplication/test/test.pro | 2 | ||||
-rw-r--r-- | tests/auto/qwidget/tst_qwidget.cpp | 32 |
7 files changed, 107 insertions, 44 deletions
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index bcf4477..bf675a7 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -77,10 +77,14 @@ Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction) static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1); +static const int TimerIdMask = 0x00ffffff; +static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; +static const int TimerSerialCounter = TimerIdMask + 1; + // avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number static inline int prepareNewValueWithSerialNumber(int oldId, int newId) { - return (newId & 0x00FFFFFF) | ((oldId + 0x01000000) & 0x7f000000); + return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask); } static inline int bucketOffset(int timerId) @@ -120,17 +124,32 @@ void QAbstractEventDispatcherPrivate::init() } } +// Timer IDs are implemented using a free-list; +// there's a vector initialized with: +// X[i] = i + 1 +// and nextFreeTimerId starts with 1. +// +// Allocating a timer ID involves taking the ID from +// X[nextFreeTimerId] +// updating nextFreeTimerId to this value and returning the old value +// +// When the timer ID is allocated, its cell in the vector is unused (it's a +// free list). As an added protection, we use the cell to store an invalid +// (negative) value that we can later check for integrity. +// +// (continues below). int QAbstractEventDispatcherPrivate::allocateTimerId() { int timerId, newTimerId; + int at, *b; do { - timerId = nextFreeTimerId; + timerId = nextFreeTimerId; //.loadAcquire(); // ### FIXME Proper memory ordering semantics // which bucket are we looking in? - int which = timerId & 0x00ffffff; + int which = timerId & TimerIdMask; int bucket = bucketOffset(which); - int at = bucketIndex(bucket, which); - int *b = timerIds[bucket]; + at = bucketIndex(bucket, which); + b = timerIds[bucket]; if (!b) { // allocate a new bucket @@ -142,23 +161,38 @@ int QAbstractEventDispatcherPrivate::allocateTimerId() } } - newTimerId = b[at]; + newTimerId = prepareNewValueWithSerialNumber(timerId, b[at]); } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId)); + b[at] = -timerId; + return timerId; } +// Releasing a timer ID requires putting the current ID back in the vector; +// we do it by setting: +// X[timerId] = nextFreeTimerId; +// then we update nextFreeTimerId to the timer we've just released +// +// The extra code in allocateTimerId and releaseTimerId are ABA prevention +// and bucket memory. The buckets are simply to make sure we allocate only +// the necessary number of timers. See above. +// +// ABA prevention simply adds a value to 7 of the top 8 bits when resetting +// nextFreeTimerId. void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) { - int which = timerId & 0x00ffffff; + int which = timerId & TimerIdMask; int bucket = bucketOffset(which); int at = bucketIndex(bucket, which); int *b = timerIds[bucket]; + Q_ASSERT(b[at] == -timerId); + int freeId, newTimerId; do { - freeId = nextFreeTimerId; - b[at] = freeId & 0x00ffffff; + freeId = nextFreeTimerId;//.loadAcquire(); // ### FIXME Proper memory ordering semantics + b[at] = freeId & TimerIdMask; newTimerId = prepareNewValueWithSerialNumber(freeId, timerId); } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId)); diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 8596563..81fa4e6 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1633,6 +1633,13 @@ void qt_cleanup() //Change mouse pointer back S60->wsSession().SetPointerCursorMode(EPointerCursorNone); +#ifdef Q_WS_S60 + // Clear CBA + CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(0); + delete S60->buttonGroupContainer(); + S60->setButtonGroupContainer(0); +#endif + if (S60->qtOwnsS60Environment) { // Restore the S60 framework trap handler. See qt_init(). User::SetTrapHandler(S60->s60InstalledTrapHandler); diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 609307c..d6ad3c3 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -504,7 +504,7 @@ void QWidgetPrivate::show_sys() CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba, CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS); - CEikButtonGroupContainer *oldCba = CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(cba); + CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba); Q_ASSERT(!oldCba); S60->setButtonGroupContainer(cba); @@ -513,7 +513,7 @@ void QWidgetPrivate::show_sys() menuBar->SetMenuType(CEikMenuBar::EMenuOptions); S60->appUi()->AddToStackL(menuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus); - CEikMenuBar *oldMenu = CEikonEnv::Static()->AppUiFactory()->SwapMenuBar(menuBar); + CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar); Q_ASSERT(!oldMenu); ) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 4a64f39..668a3f0 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -163,6 +163,8 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush) Q_ASSERT(newStyle != Qt::NoBrush); currentBrush = brush; + if (!currentBrushPixmap.isNull()) + currentBrushPixmap = QPixmap(); brushUniformsDirty = true; // All brushes have at least one uniform if (newStyle > Qt::SolidPattern) @@ -221,10 +223,14 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform); } else if (style == Qt::TexturePattern) { - const QPixmap& texPixmap = currentBrush.texture(); + currentBrushPixmap = currentBrush.texture(); + + int max_texture_size = ctx->d_func()->maxTextureSize(); + if (currentBrushPixmap.width() > max_texture_size || currentBrushPixmap.height() > max_texture_size) + currentBrushPixmap = currentBrushPixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); - QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, + QGLTexture *tex = ctx->d_func()->bindTexture(currentBrushPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption | QGLContext::CanFlipNativePixmapBindOption); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); @@ -1305,13 +1311,30 @@ void QGL2PaintEngineEx::transformChanged() } +static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy) +{ + return QRectF(r.x() * sx, r.y() * sy, r.width() * sx, r.height() * sy); +} + void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src) { Q_D(QGL2PaintEngineEx); + QGLContext *ctx = d->ctx; + + int max_texture_size = ctx->d_func()->maxTextureSize(); + if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) { + QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + + const qreal sx = scaled.width() / qreal(pixmap.width()); + const qreal sy = scaled.height() / qreal(pixmap.height()); + + drawPixmap(dest, scaled, scaleRect(src, sx, sy)); + return; + } + ensureActive(); d->transferMode(ImageDrawingMode); - QGLContext *ctx = d->ctx; glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, @@ -1334,11 +1357,24 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const Qt::ImageConversionFlags) { Q_D(QGL2PaintEngineEx); + QGLContext *ctx = d->ctx; + + int max_texture_size = ctx->d_func()->maxTextureSize(); + if (image.width() > max_texture_size || image.height() > max_texture_size) { + QImage scaled = image.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + + const qreal sx = scaled.width() / qreal(image.width()); + const qreal sy = scaled.height() / qreal(image.height()); + + drawImage(dest, scaled, scaleRect(src, sx, sy)); + return; + } + ensureActive(); d->transferMode(ImageDrawingMode); - QGLContext *ctx = d->ctx; glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); GLuint id = texture->id; @@ -1737,7 +1773,13 @@ void QGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *frag } ensureActive(); - d->drawPixmapFragments(fragments, fragmentCount, pixmap, hints); + int max_texture_size = d->ctx->d_func()->maxTextureSize(); + if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) { + QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + d->drawPixmapFragments(fragments, fragmentCount, scaled, hints); + } else { + d->drawPixmapFragments(fragments, fragmentCount, pixmap, hints); + } } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index b255e75..02b737b 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -274,6 +274,8 @@ public: QBrush currentBrush; // May not be the state's brush! const QBrush noBrush; + QPixmap currentBrushPixmap; + QGL2PEXVertexArray vertexCoordinateArray; QGL2PEXVertexArray textureCoordinateArray; QVector<GLushort> elementIndices; diff --git a/tests/auto/qapplication/test/test.pro b/tests/auto/qapplication/test/test.pro index 2c54c37..d946e7e 100644 --- a/tests/auto/qapplication/test/test.pro +++ b/tests/auto/qapplication/test/test.pro @@ -17,7 +17,7 @@ symbian: { someTest.sources = test.pro someTest.path = test windowIcon.sources = ../heart.svg - DEPLOYMENT = additional deploy someTest windowIcon + DEPLOYMENT += additional deploy someTest windowIcon LIBS += -lcone -lavkon } diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index 6069383..d611225 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -10029,28 +10029,6 @@ void tst_QWidget::openModal_taskQTBUG_5804() } #ifdef Q_OS_SYMBIAN - -static CEikButtonGroupContainer* cba() -{ - CEikButtonGroupContainer *oldCba = NULL; - - // Due to convoluted/buggy implementation of MEikAppUiFactory interface in Symbian, - // the only way to get the correct cba is to use SwapButtonGroup function. - // Calling SwapButtonGroup doesn't trigger anything, it only changes the value of iToolbar - // member variable, so this double switching should not cause any interference for test. - QT_TRAP_THROWING( - CEikButtonGroupContainer *dummyCba = CEikButtonGroupContainer::NewL( - CEikButtonGroupContainer::ECba, CEikButtonGroupContainer::EHorizontal, NULL, 0); - - oldCba = CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(dummyCba); - CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(oldCba); - - delete dummyCba; - ) - - return oldCba; -} - void tst_QWidget::cbaVisibility() { // Test case for task 261048 @@ -10083,7 +10061,7 @@ void tst_QWidget::cbaVisibility() // Verify window decorations i.e. status pane and CBA are visible. CEikStatusPane* statusPane = CEikonEnv::Static()->AppUiFactory()->StatusPane(); QVERIFY(statusPane->IsVisible()); - CEikButtonGroupContainer* buttonGroup = cba(); + CEikButtonGroupContainer* buttonGroup = CEikButtonGroupContainer::Current(); QVERIFY(buttonGroup->IsVisible()); } @@ -10100,7 +10078,7 @@ void tst_QWidget::fullScreenWindowModeTransitions() const QRect fullScreenGeometry = qApp->desktop()->screenGeometry(&widget); const QRect maximumScreenGeometry = qApp->desktop()->availableGeometry(&widget); CEikStatusPane *statusPane = CEikonEnv::Static()->AppUiFactory()->StatusPane(); - CEikButtonGroupContainer *buttonGroup = cba(); + CEikButtonGroupContainer *buttonGroup = CEikButtonGroupContainer::Current(); //Enter widget.showNormal(); @@ -10154,7 +10132,7 @@ void tst_QWidget::maximizedWindowModeTransitions() const QRect fullScreenGeometry = qApp->desktop()->screenGeometry(&widget); const QRect maximumScreenGeometry = qApp->desktop()->availableGeometry(&widget); CEikStatusPane *statusPane = CEikonEnv::Static()->AppUiFactory()->StatusPane(); - CEikButtonGroupContainer *buttonGroup = cba(); + CEikButtonGroupContainer *buttonGroup = CEikButtonGroupContainer::Current(); //Enter widget.showNormal(); @@ -10210,7 +10188,7 @@ void tst_QWidget::minimizedWindowModeTransitions() const QRect fullScreenGeometry = qApp->desktop()->screenGeometry(&widget); const QRect maximumScreenGeometry = qApp->desktop()->availableGeometry(&widget); CEikStatusPane *statusPane = CEikonEnv::Static()->AppUiFactory()->StatusPane(); - CEikButtonGroupContainer *buttonGroup = cba(); + CEikButtonGroupContainer *buttonGroup = CEikButtonGroupContainer::Current(); //Enter widget.showNormal(); @@ -10266,7 +10244,7 @@ void tst_QWidget::normalWindowModeTransitions() const QRect fullScreenGeometry = qApp->desktop()->screenGeometry(&widget); const QRect maximumScreenGeometry = qApp->desktop()->availableGeometry(&widget); CEikStatusPane *statusPane = CEikonEnv::Static()->AppUiFactory()->StatusPane(); - CEikButtonGroupContainer *buttonGroup = cba(); + CEikButtonGroupContainer *buttonGroup = CEikButtonGroupContainer::Current(); //Enter widget.showMaximized(); |