From 2e27c5a11488d5b7aa6831ba30a8c11bf71fb07a Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Wed, 23 Sep 2009 09:11:56 +0200 Subject: Fix a warning about an unused variable. Reviewed-by: TrustMe --- src/corelib/kernel/qcoreapplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index c575509..9a93685 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -345,7 +345,7 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) } #elif defined(Q_OS_SYMBIAN) && defined (QT_NO_DEBUG) // no implementation in release builds, but keep the symbol present -void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) +void QCoreApplicationPrivate::checkReceiverThread(QObject * /* receiver */) { } #endif -- cgit v0.12 From 5e11ae8dc8594f648105f8a62baf1b82c909fd2a Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 11 Aug 2009 08:39:12 +0200 Subject: Implement Qt::WA_AcceptTouchEvents on S60 Turning this attribute ends up calling RWindow::EnabledAdvancedPointers(), which tells Symbian to send us multiple pointer events with extended info. Reviewed-by: Jason Barron --- src/gui/kernel/qwidget.cpp | 2 +- src/gui/kernel/qwidget_p.h | 1 + src/gui/kernel/qwidget_s60.cpp | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 6f5781c..53ef682 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -10397,7 +10397,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) break; case Qt::WA_AcceptTouchEvents: -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) if (on) d->registerTouchWindow(); #endif diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 5a9c48c..296c5b1 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -693,6 +693,7 @@ public: static QWidget *keyboardGrabber; void s60UpdateIsOpaque(); void reparentChildren(); + void registerTouchWindow(); #endif }; diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 4fef020..2e6139b 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -299,6 +299,9 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); CBase::Delete(destroyw); } + + if (q->testAttribute(Qt::WA_AcceptTouchEvents)) + registerTouchWindow(); } @@ -800,6 +803,15 @@ void QWidgetPrivate::setMask_sys(const QRegion& /* region */) } +void QWidgetPrivate::registerTouchWindow() +{ + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) { + RWindow *rwindow = static_cast(q->effectiveWinId()->DrawableWindow()); + rwindow->EnableAdvancedPointers(); + } +} + int QWidget::metric(PaintDeviceMetric m) const { Q_D(const QWidget); -- cgit v0.12 From 48d0f84958fdc2dcffab75f33842a9dbc3d4d7b1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 11 Aug 2009 09:39:26 +0200 Subject: Implement advanced pointer handling on S60 Since we only get one pointer event at a time, we need to keep a list of all known touch points in QApplicationPrivate (otherwise the QTouchEvent won't contain enough points). The QApplication machinery can handle having inactive touch-points in the list, so at the moment we don't clear the list. We treat PointerNumber zero as the primary touch point, and only send regular mouse events for that pointer, never for the others. Reviewed-by: Jason Barron --- src/gui/kernel/qapplication_p.h | 5 +++ src/gui/kernel/qapplication_s60.cpp | 76 ++++++++++++++++++++++++++++++++++++- src/gui/kernel/qt_s60_p.h | 1 + 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 707caaa..aec21fd 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -576,6 +576,11 @@ public: void _q_readRX71MultiTouchEvents(); #endif +#if defined(Q_WS_S60) + int maxTouchPressure; + QList appAllTouchPoints; +#endif + private: #ifdef Q_WS_QWS QMap maxWindowRects; diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index a5d07fd..58aca83 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -368,8 +368,77 @@ void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, cons m_previousEventLongTap = true; } +void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event) +{ + QApplicationPrivate *d = QApplicationPrivate::instance(); + + QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget); + + while (d->appAllTouchPoints.count() <= event->PointerNumber()) + d->appAllTouchPoints.append(QTouchEvent::TouchPoint(d->appAllTouchPoints.count())); + + Qt::TouchPointStates allStates = 0; + for (int i = 0; i < d->appAllTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint &touchPoint = d->appAllTouchPoints[i]; + + if (touchPoint.id() == event->PointerNumber()) { + Qt::TouchPointStates state; + switch (event->iType) { + case TPointerEvent::EButton1Down: + case TPointerEvent::EEnterHighPressure: + state = Qt::TouchPointPressed; + break; + case TPointerEvent::EButton1Up: + case TPointerEvent::EExitCloseProximity: + state = Qt::TouchPointReleased; + break; + case TPointerEvent::EDrag: + state = Qt::TouchPointMoved; + break; + default: + // how likely is this to happen? + state = Qt::TouchPointStationary; + break; + } + if (event->PointerNumber() == 0) + state |= Qt::TouchPointPrimary; + touchPoint.setState(state); + + QPointF screenPos = QPointF(event->iPosition.iX, event->iPosition.iY); + touchPoint.setScreenPos(screenPos); + touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(), + screenPos.y() / screenGeometry.height())); + + touchPoint.setPressure(event->Pressure() / qreal(d->maxTouchPressure)); + } else if (touchPoint.state() != Qt::TouchPointReleased) { + // all other active touch points should be marked as stationary + touchPoint.setState(Qt::TouchPointStationary); + } + + allStates |= touchPoint.state(); + } + + if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) { + // all touch points released + d->appAllTouchPoints.clear(); + } + + QApplicationPrivate::translateRawTouchEvent(qwidget, + QTouchEvent::TouchScreen, + d->appAllTouchPoints); +} + void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) { + if (pEvent.IsAdvancedPointerEvent()) { + const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent(); + translateAdvancedPointerEvent(advancedPointerEvent); + if (advancedPointerEvent->PointerNumber() != 0) { + // only send mouse events for the first touch point + return; + } + } + m_longTapDetector->PointerEventL(pEvent); QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); } @@ -1441,9 +1510,12 @@ TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym) } } - void QApplicationPrivate::initializeMultitouch_sys() -{ } +{ + if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone) + maxTouchPressure = KMaxTInt; +} + void QApplicationPrivate::cleanupMultitouch_sys() { } diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index aa39f9d..9939f2c 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -167,6 +167,7 @@ private: TKeyResponse sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent); bool sendMouseEvent(QWidget *widget, QMouseEvent *mEvent); void HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ); + void translateAdvancedPointerEvent(const TAdvancedPointerEvent *event); private: QWidget *qwidget; -- cgit v0.12 From 7dcf984f85a3a75ce4c078cc931bd9d2304bc235 Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Wed, 23 Sep 2009 08:31:23 +0200 Subject: Modify functions for native pixmap data conversion on Symbian. We need a way to support converion to and from multiple native pixmap types from multiple pixmap backends. Instead of adding more virtual functions to QPixmapData, make the existing one more generic but pass an opaque pointer and a type and do some internal casting. Currently this function is Symbian only, but could easily be extended to work on other platforms. Reviewed-by: Aleksandar Babic Reviewed-by: Jani Hautakangas --- src/gui/image/qpixmap.h | 6 +- src/gui/image/qpixmap_s60.cpp | 410 +++++++++++++++++++++--------------------- src/gui/image/qpixmap_s60_p.h | 21 ++- src/gui/image/qpixmapdata.cpp | 5 +- src/gui/image/qpixmapdata_p.h | 15 +- src/openvg/qpixmapdata_vg.cpp | 266 ++++++++++++++------------- src/openvg/qpixmapdata_vg_p.h | 4 +- 7 files changed, 376 insertions(+), 351 deletions(-) diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 2ed65ea..a891637 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -161,10 +161,8 @@ public: #endif #if defined(Q_OS_SYMBIAN) - enum ConversionMode { CopyData, DuplicateHandle }; - - CFbsBitmap *toSymbianCFbsBitmap(ConversionMode mode = DuplicateHandle) const; - static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode = DuplicateHandle); + CFbsBitmap *toSymbianCFbsBitmap() const; + static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap); RSgImage* toSymbianRSgImage() const; static QPixmap fromSymbianRSgImage(RSgImage *sgImage); #endif diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index 303e923..cab6116 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -297,231 +297,55 @@ QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h) } /*! - \enum QPixmap::ConversionMode - - \bold{Symbian only:} This enum defines how the conversion between \c - CFbsBitmap and QPixmap is performed. - - \warning This enum is only available on Symbian. - - \value CopyData Copied CFbsBitmap data. - - \value DuplicateHandle Duplicates CFbsBitmap handle. This also means - that pixmap data will be explicitly shared. - - \sa fromSymbianCFbsBitmap(), toSymbianCFbsBitmap() -*/ - - -/*! - \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode) + \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap() \since 4.6 - Creates \c CFbsBitmap that is equivalent to the QPixmap, based on - the given \a mode. If the creation then this function returns 0. + Creates a \c CFbsBitmap that is equivalent to the QPixmap. Internally this + function will try to duplicate the handle instead of copying the data, + however in scenarios where this is not possible the data will be copied. + If the creation fails or the pixmap is null, then this function returns 0. It is the caller's responsibility to release the \c CFbsBitmap data after use either by deleting the bitmap or calling \c Reset(). - \warning On S60 3.1 and S60 3.2 conversion mode will always be CopyData - if QPixmap pixels have alpha values. + \warning On S60 3.1 and S60 3.2, semi-transparent pixmaps are always copied + and not duplicated. \warning This function is only available on Symbian OS. \sa fromSymbianCFbsBitmap() */ -CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode) const +CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const { - QS60PixmapData *s60data = static_cast(data.data()); - - if (isNull() || !s60data->cfbsBitmap) + QPixmapData *data = pixmapData(); + if (data->isNull()) return 0; - bool convertToArgb32 = false; - - QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); - if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) { - // Convert argb32_premultiplied to argb32 since Symbian 9.2 and Symbian 9.3 do - // not support premultipied format. - - if (s60data->image.format() == QImage::Format_ARGB32_Premultiplied) { - mode = CopyData; - convertToArgb32 = true; - } - } - - CFbsBitmap *bitmap = 0; - - TDisplayMode displayMode = s60data->cfbsBitmap->DisplayMode(); - - if(displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - s60data->image.invertPixels(); - mode = CopyData; - } - - if (mode == CopyData) { - QImage source; - - if (convertToArgb32) { - source = s60data->image.convertToFormat(QImage::Format_ARGB32); - displayMode = EColor16MA; - } else { - source = s60data->image; - } - - CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode); - const uchar *sptr = source.bits(); - s60data->symbianBitmapDataAccess->beginDataAccess(newBitmap); - - uchar *dptr = (uchar*)newBitmap->DataAddress(); - Mem::Copy(dptr, sptr, source.numBytes()); - - s60data->symbianBitmapDataAccess->endDataAccess(newBitmap); - - bitmap = newBitmap; - } else { - - QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap); - - TInt err = bitmap->Duplicate(s60data->cfbsBitmap->Handle()); - if (err != KErrNone) { - qWarning("Could not duplicate CFbsBitmap"); - delete bitmap; - bitmap = 0; - } - } - - if(displayMode == EGray2) { - // restore pixels - s60data->image.invertPixels(); - } - - return bitmap; + return reinterpret_cast(data->toNativeType(QPixmapData::FbsBitmap)); } /*! - \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode) + \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) \since 4.6 - Creates a QPixmap from native \c CFbsBitmap \a bitmap. The conversion - is based on the specified \a mode. Conversion mode is always QPixmap::CopyData - if given \a bitmap does not have display mode of TDisplayMode::EGray2, - \c TDisplayMode::EColor16MU or \c TDisplayMode::EColor16MAP. - + Creates a QPixmap from a \c CFbsBitmap \a bitmap. Internally this function + will try to duplicate the bitmap handle instead of copying the data, however + in scenarios where this is not possible the data will be copied. + To be sure that QPixmap does not modify your original instance, you should + make a copy of your \c CFbsBitmap before calling this function. If the CFbsBitmap is not valid this function will return a null QPixmap. \warning This function is only available on Symbian OS. \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} */ -QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode) +QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) { - if (bitmap) { - - bool deleteSourceBitmap = false; - -#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE - - // Rasterize extended bitmaps - - TUid extendedBitmapType = bitmap->ExtendedBitmapType(); - if (extendedBitmapType != KNullUid) { - CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA); - - CFbsBitmapDevice *rasterBitmapDev = 0; - QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap)); - - CFbsBitGc *rasterBitmapGc = 0; - TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc); - if (err != KErrNone) { - delete rasterBitmap; - delete rasterBitmapDev; - rasterBitmapDev = 0; - return QPixmap(); - } - - rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap); - - bitmap = rasterBitmap; - - delete rasterBitmapDev; - delete rasterBitmapGc; - - rasterBitmapDev = 0; - rasterBitmapGc = 0; - - deleteSourceBitmap = true; - } -#endif - - - deleteSourceBitmap = bitmap->IsCompressedInRAM(); - CFbsBitmap *sourceBitmap = uncompress(bitmap); - - TDisplayMode displayMode = sourceBitmap->DisplayMode(); - QImage::Format format = qt_TDisplayMode2Format(displayMode); - - QImage::Format opaqueFormat = QNativeImage::systemFormat(); - QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; - - if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB) - mode = CopyData; - - - QPixmapData::PixelType type = (format!=QImage::Format_MonoLSB) - ? QPixmapData::PixmapType - : QPixmapData::BitmapType; - - QS60PixmapData *pixmapData = 0; - - if (mode == CopyData) { - - TSize size = sourceBitmap->SizeInPixels(); - - QSymbianBitmapDataAccess da; - da.beginDataAccess(sourceBitmap); - uchar *bytes = (uchar*)sourceBitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, format); - da.endDataAccess(sourceBitmap); - - pixmapData = new QS60PixmapData(type); - pixmapData->fromImage(img, Qt::AutoColor); - - if(deleteSourceBitmap) - delete sourceBitmap; - - if(displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - pixmapData->image.invertPixels(); - } - } else { - CFbsBitmap* duplicate = 0; - QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap); - - TInt err = duplicate->Duplicate(sourceBitmap->Handle()); - if (err != KErrNone) { - qWarning("Could not duplicate CFbsBitmap"); - - if(deleteSourceBitmap) - delete sourceBitmap; - - delete duplicate; - return QPixmap(); - } - - pixmapData = new QS60PixmapData(type); - pixmapData->fromSymbianBitmap(duplicate); - - if(deleteSourceBitmap) - delete sourceBitmap; - } - - return QPixmap(pixmapData); - } + if (!bitmap) + return QPixmap(); - return QPixmap(); + QPixmap pixmap; + pixmap.pixmapData()->fromNativeType(reinterpret_cast(bitmap), QPixmapData::FbsBitmap); + return pixmap; } QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), @@ -921,7 +745,7 @@ QPixmap QPixmap::fromSymbianRSgImage(RSgImage *sgImage) return QPixmap(); QPixmap pixmap; - pixmap.pixmapData()->fromRSgImage(sgImage); + pixmap.pixmapData()->fromNativeType(reinterpret_cast(sgImage), QPixmapData::SgImage); return pixmap; } @@ -949,9 +773,193 @@ RSgImage *QPixmap::toSymbianRSgImage() const if (isNull()) return 0; - RSgImage *sgImage = pixmapData()->toRSgImage(); + RSgImage *sgImage = reinterpret_cast(pixmapData()->toNativeType(QPixmapData::SgImage)); return sgImage; } +void* QS60PixmapData::toNativeType(NativeType type) +{ + if (type == QPixmapData::SgImage) { + return 0; + } else if (type == QPixmapData::FbsBitmap) { + + if (isNull() || !cfbsBitmap) + return 0; + + bool convertToArgb32 = false; + bool needsCopy = false; + + QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); + if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) { + // Convert argb32_premultiplied to argb32 since Symbian 9.2 and Symbian 9.3 do + // not support premultipied format. + + if (image.format() == QImage::Format_ARGB32_Premultiplied) { + needsCopy = true; + convertToArgb32 = true; + } + } + + CFbsBitmap *bitmap = 0; + + TDisplayMode displayMode = cfbsBitmap->DisplayMode(); + + if(displayMode == EGray2) { + //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid + //So invert mono bitmaps so that masks work correctly. + image.invertPixels(); + needsCopy = true; + } + + if (needsCopy) { + QImage source; + + if (convertToArgb32) { + source = image.convertToFormat(QImage::Format_ARGB32); + displayMode = EColor16MA; + } else { + source = image; + } + + CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode); + const uchar *sptr = source.bits(); + symbianBitmapDataAccess->beginDataAccess(newBitmap); + + uchar *dptr = (uchar*)newBitmap->DataAddress(); + Mem::Copy(dptr, sptr, source.numBytes()); + + symbianBitmapDataAccess->endDataAccess(newBitmap); + + bitmap = newBitmap; + } else { + + QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap); + + TInt err = bitmap->Duplicate(cfbsBitmap->Handle()); + if (err != KErrNone) { + qWarning("Could not duplicate CFbsBitmap"); + delete bitmap; + bitmap = 0; + } + } + + if(displayMode == EGray2) { + // restore pixels + image.invertPixels(); + } + + return reinterpret_cast(bitmap); + + } + + return 0; +} + +void QS60PixmapData::fromNativeType(void* pixmap, NativeType nativeType) +{ + if (nativeType == QPixmapData::SgImage) { + return; + } else if (nativeType == QPixmapData::FbsBitmap && pixmap) { + + CFbsBitmap *bitmap = reinterpret_cast(pixmap); + + bool deleteSourceBitmap = false; + bool needsCopy = false; + +#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE + + // Rasterize extended bitmaps + + TUid extendedBitmapType = bitmap->ExtendedBitmapType(); + if (extendedBitmapType != KNullUid) { + CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA); + + CFbsBitmapDevice *rasterBitmapDev = 0; + QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap)); + + CFbsBitGc *rasterBitmapGc = 0; + TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc); + if (err != KErrNone) { + delete rasterBitmap; + delete rasterBitmapDev; + rasterBitmapDev = 0; + return; + } + + rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap); + + bitmap = rasterBitmap; + + delete rasterBitmapDev; + delete rasterBitmapGc; + + rasterBitmapDev = 0; + rasterBitmapGc = 0; + + deleteSourceBitmap = true; + } +#endif + + + deleteSourceBitmap = bitmap->IsCompressedInRAM(); + CFbsBitmap *sourceBitmap = uncompress(bitmap); + + TDisplayMode displayMode = sourceBitmap->DisplayMode(); + QImage::Format format = qt_TDisplayMode2Format(displayMode); + + QImage::Format opaqueFormat = QNativeImage::systemFormat(); + QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; + + if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB) + needsCopy = true; + + + type = (format != QImage::Format_MonoLSB) + ? QPixmapData::PixmapType + : QPixmapData::BitmapType; + + if (needsCopy) { + + TSize size = sourceBitmap->SizeInPixels(); + + QSymbianBitmapDataAccess da; + da.beginDataAccess(sourceBitmap); + uchar *bytes = (uchar*)sourceBitmap->DataAddress(); + QImage img = QImage(bytes, size.iWidth, size.iHeight, format); + da.endDataAccess(sourceBitmap); + + fromImage(img, Qt::AutoColor); + + if(deleteSourceBitmap) + delete sourceBitmap; + + if(displayMode == EGray2) { + //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid + //So invert mono bitmaps so that masks work correctly. + image.invertPixels(); + } + } else { + CFbsBitmap* duplicate = 0; + QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap); + + TInt err = duplicate->Duplicate(sourceBitmap->Handle()); + if (err != KErrNone) { + qWarning("Could not duplicate CFbsBitmap"); + + if(deleteSourceBitmap) + delete sourceBitmap; + + delete duplicate; + return; + } + + fromSymbianBitmap(duplicate); + + if(deleteSourceBitmap) + delete sourceBitmap; + } + } +} + QT_END_NAMESPACE diff --git a/src/gui/image/qpixmap_s60_p.h b/src/gui/image/qpixmap_s60_p.h index 21f1bb3..4498c05 100644 --- a/src/gui/image/qpixmap_s60_p.h +++ b/src/gui/image/qpixmap_s60_p.h @@ -66,17 +66,17 @@ class QSymbianBitmapDataAccess; class QSymbianFbsHeapLock { public: - + enum LockAction { Unlock }; - + explicit QSymbianFbsHeapLock(LockAction a); ~QSymbianFbsHeapLock(); - void relock(); - + void relock(); + private: - + LockAction action; bool wasLocked; }; @@ -102,13 +102,16 @@ public: void beginDataAccess(); void endDataAccess(bool readOnly=false) const; + void* toNativeType(NativeType type); + void fromNativeType(void* pixmap, NativeType type); + private: - void release(); - void fromSymbianBitmap(CFbsBitmap* bitmap); - bool initSymbianBitmapContext(); + void release(); + void fromSymbianBitmap(CFbsBitmap* bitmap); + bool initSymbianBitmapContext(); QSymbianBitmapDataAccess *symbianBitmapDataAccess; - + CFbsBitmap *cfbsBitmap; CFbsBitmapDevice *bitmapDevice; CBitmapContext *bitmapContext; diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp index 65899a4..93fc2eb 100644 --- a/src/gui/image/qpixmapdata.cpp +++ b/src/gui/image/qpixmapdata.cpp @@ -224,14 +224,15 @@ QImage* QPixmapData::buffer() } #if defined(Q_OS_SYMBIAN) -RSgImage* QPixmapData::toRSgImage() +void* QPixmapData::toNativeType(NativeType /* type */) { return 0; } -void QPixmapData::fromRSgImage(RSgImage* rsgImage) +void QPixmapData::fromNativeType(void* /* pixmap */, NativeType /* typre */) { return; } #endif + QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index 5920a06..3e85236 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -56,10 +56,6 @@ #include #include -#if defined(Q_OS_SYMBIAN) -class RSgImage; -#endif - QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QPixmapData @@ -70,6 +66,12 @@ public: // Must match QPixmap::Type PixmapType, BitmapType }; +#if defined(Q_OS_SYMBIAN) + enum NativeType { + FbsBitmap, + SgImage + }; +#endif enum ClassId { RasterClass, X11Class, MacClass, DirectFBClass, OpenGLClass, OpenVGClass, CustomClass = 1024 }; @@ -114,8 +116,8 @@ public: inline bool isNull() const { return is_null; } #if defined(Q_OS_SYMBIAN) - virtual RSgImage* toRSgImage(); - virtual void fromRSgImage(RSgImage* rsgImage); + virtual void* toNativeType(NativeType type); + virtual void fromNativeType(void* pixmap, NativeType type); #endif protected: @@ -129,6 +131,7 @@ private: friend class QPixmap; friend class QGLContextPrivate; friend class QX11PixmapData; + friend class QS60PixmapData; friend class QGLTextureCache; //Needs to check the reference count friend class QExplicitlySharedDataPointer; diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 53975d7..38a89e6 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -381,167 +381,179 @@ void QVGPixmapData::cleanup() source = QImage(); } -void QVGPixmapData::fromRSgImage(RSgImage* sgImage) +void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) { - Q_UNUSED(sgImage); #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) - // when "0" used as argument then - // default display, context are used - if (!context) - context = qt_vg_create_context(0); + if (type == QPixmapData::SgImage && pixmap) { + RSgImage *sgImage = reinterpret_cast(pixmap); + // when "0" used as argument then + // default display, context are used + if (!context) + context = qt_vg_create_context(0); - if (vgImage != VG_INVALID_HANDLE) { - vgDestroyImage(vgImage); - vgImage = VG_INVALID_HANDLE; - } - if (vgImageOpacity != VG_INVALID_HANDLE) { - vgDestroyImage(vgImageOpacity); - vgImageOpacity = VG_INVALID_HANDLE; - } + if (vgImage != VG_INVALID_HANDLE) { + vgDestroyImage(vgImage); + vgImage = VG_INVALID_HANDLE; + } + if (vgImageOpacity != VG_INVALID_HANDLE) { + vgDestroyImage(vgImageOpacity); + vgImageOpacity = VG_INVALID_HANDLE; + } - TInt err = 0; + TInt err = 0; - err = SgDriver::Open(); - if(err != KErrNone) { - cleanup(); - return; - } + err = SgDriver::Open(); + if(err != KErrNone) { + cleanup(); + return; + } - if(sgImage->IsNull()) { - cleanup(); - SgDriver::Close(); - return; - } + if(sgImage->IsNull()) { + cleanup(); + SgDriver::Close(); + return; + } - TSgImageInfo sgImageInfo; - err = sgImage->GetInfo(sgImageInfo); - if(err != KErrNone) { - cleanup(); - SgDriver::Close(); - return; - } + TSgImageInfo sgImageInfo; + err = sgImage->GetInfo(sgImageInfo); + if(err != KErrNone) { + cleanup(); + SgDriver::Close(); + return; + } - pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); - pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); - pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); + pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); + pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); + pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); - if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { - cleanup(); - SgDriver::Close(); - return; - } + if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { + cleanup(); + SgDriver::Close(); + return; + } - const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; - EGLImageKHR eglImage = eglCreateImageKHR(context->display(), - EGL_NO_CONTEXT, - EGL_NATIVE_PIXMAP_KHR, - (EGLClientBuffer)sgImage, - (EGLint*)KEglImageAttribs); + const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; + EGLImageKHR eglImage = eglCreateImageKHR(context->display(), + EGL_NO_CONTEXT, + EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer)sgImage, + (EGLint*)KEglImageAttribs); + + if(eglGetError() != EGL_SUCCESS) { + cleanup(); + SgDriver::Close(); + return; + } - if(eglGetError() != EGL_SUCCESS) { - cleanup(); - SgDriver::Close(); - return; - } + vgImage = vgCreateEGLImageTargetKHR(eglImage); + if(vgGetError() != VG_NO_ERROR) { + cleanup(); + eglDestroyImageKHR(context->display(), eglImage); + SgDriver::Close(); + return; + } - vgImage = vgCreateEGLImageTargetKHR(eglImage); - if(vgGetError() != VG_NO_ERROR) { - cleanup(); + w = sgImageInfo.iSizeInPixels.iWidth; + h = sgImageInfo.iSizeInPixels.iHeight; + d = 32; // We always use ARGB_Premultiplied for VG pixmaps. + is_null = (w <= 0 || h <= 0); + source = QImage(); + recreate = false; + setSerialNumber(++qt_vg_pixmap_serial); + // release stuff eglDestroyImageKHR(context->display(), eglImage); SgDriver::Close(); - return; - } + } else if (type == QPixmapData::FbsBitmap) { - w = sgImageInfo.iSizeInPixels.iWidth; - h = sgImageInfo.iSizeInPixels.iHeight; - d = 32; // We always use ARGB_Premultiplied for VG pixmaps. - is_null = (w <= 0 || h <= 0); - source = QImage(); - recreate = false; - setSerialNumber(++qt_vg_pixmap_serial); - // release stuff - eglDestroyImageKHR(context->display(), eglImage); - SgDriver::Close(); + } #else + Q_UNUSED(pixmap); + Q_UNUSED(type); #endif } -RSgImage* QVGPixmapData::toRSgImage() +void* QVGPixmapData::toNativeType(NativeType type) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) - toVGImage(); - - if(!isValid() || vgImage == VG_INVALID_HANDLE) - return 0; - - TInt err = 0; + if (type == QPixmapData::SgImage) { + toVGImage(); + + if(!isValid() || vgImage == VG_INVALID_HANDLE) + return 0; + + TInt err = 0; + + err = SgDriver::Open(); + if(err != KErrNone) + return 0; + + TSgImageInfo sgInfo; + sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE; + sgInfo.iSizeInPixels.SetSize(w, h); + sgInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget; + sgInfo.iShareable = ETrue; + sgInfo.iCpuAccess = ESgCpuAccessNone; + sgInfo.iScreenId = KSgScreenIdMain; //KSgScreenIdAny; + sgInfo.iUserAttributes = NULL; + sgInfo.iUserAttributeCount = 0; + + RSgImage *sgImage = q_check_ptr(new RSgImage()); + err = sgImage->Create(sgInfo, NULL, NULL); + if(err != KErrNone) { + SgDriver::Close(); + return 0; + } - err = SgDriver::Open(); - if(err != KErrNone) - return 0; + pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); + pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); + pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); - TSgImageInfo sgInfo; - sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE; - sgInfo.iSizeInPixels.SetSize(w, h); - sgInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget; - sgInfo.iShareable = ETrue; - sgInfo.iCpuAccess = ESgCpuAccessNone; - sgInfo.iScreenId = KSgScreenIdMain; //KSgScreenIdAny; - sgInfo.iUserAttributes = NULL; - sgInfo.iUserAttributeCount = 0; - - RSgImage *sgImage = q_check_ptr(new RSgImage()); - err = sgImage->Create(sgInfo, NULL, NULL); - if(err != KErrNone) { - SgDriver::Close(); - return 0; - } + if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { + SgDriver::Close(); + return 0; + } - pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); - pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); - pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR"); + const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; + EGLImageKHR eglImage = eglCreateImageKHR(context->display(), + EGL_NO_CONTEXT, + EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer)sgImage, + (EGLint*)KEglImageAttribs); + if(eglGetError() != EGL_SUCCESS) { + sgImage->Close(); + SgDriver::Close(); + return 0; + } - if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) { - SgDriver::Close(); - return 0; - } + VGImage dstVgImage = vgCreateEGLImageTargetKHR(eglImage); + if(vgGetError() != VG_NO_ERROR) { + eglDestroyImageKHR(context->display(), eglImage); + sgImage->Close(); + SgDriver::Close(); + return 0; + } - const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; - EGLImageKHR eglImage = eglCreateImageKHR(context->display(), - EGL_NO_CONTEXT, - EGL_NATIVE_PIXMAP_KHR, - (EGLClientBuffer)sgImage, - (EGLint*)KEglImageAttribs); - if(eglGetError() != EGL_SUCCESS) { - sgImage->Close(); - SgDriver::Close(); - return 0; - } + vgCopyImage(dstVgImage, 0, 0, + vgImage, 0, 0, + w, h, VG_FALSE); - VGImage dstVgImage = vgCreateEGLImageTargetKHR(eglImage); - if(vgGetError() != VG_NO_ERROR) { + if(vgGetError() != VG_NO_ERROR) { + sgImage->Close(); + sgImage = 0; + } + // release stuff + vgDestroyImage(dstVgImage); eglDestroyImageKHR(context->display(), eglImage); - sgImage->Close(); SgDriver::Close(); + return reinterpret_cast(sgImage); + } else if (type == QPixmapData::FbsBitmap) { return 0; } - - vgCopyImage(dstVgImage, 0, 0, - vgImage, 0, 0, - w, h, VG_FALSE); - - if(vgGetError() != VG_NO_ERROR) { - sgImage->Close(); - sgImage = 0; - } - // release stuff - vgDestroyImage(dstVgImage); - eglDestroyImageKHR(context->display(), eglImage); - SgDriver::Close(); - return sgImage; #else + Q_UNUSED(type); return 0; #endif } #endif //Q_OS_SYMBIAN + QT_END_NAMESPACE diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index 122f596..99115df 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -95,8 +95,8 @@ public: QSize size() const { return QSize(w, h); } #if defined(Q_OS_SYMBIAN) - RSgImage* toRSgImage(); - void fromRSgImage(RSgImage* sgImage); + void* toNativeType(NativeType type); + void fromNativeType(void* pixmap, NativeType type); #endif protected: -- cgit v0.12 From 2966b2a95b0d7d161a6dc1a6edab3d6aa6edf004 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 22 Sep 2009 14:26:21 +0200 Subject: When using style sheets, the focus flag was not propagated to the children of complex widgets. Reviewed-by: Olivier --- src/gui/styles/qstylesheetstyle.cpp | 2 +- .../auto/qstylesheetstyle/tst_qstylesheetstyle.cpp | 55 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index e33b255..def82ae 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -1759,7 +1759,7 @@ QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, const QStyleOption *o QStyle::SubControl subControl = knownPseudoElements[pseudoElement].subControl; if (!(complex->activeSubControls & subControl)) - state = QStyle::State(state & (QStyle::State_Enabled | QStyle::State_Horizontal)); + state &= (QStyle::State_Enabled | QStyle::State_Horizontal | QStyle::State_HasFocus); } switch (pseudoElement) { diff --git a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp index e7d804a..e8fbd86 100644 --- a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -95,6 +95,7 @@ private slots: void embeddedFonts(); void opaquePaintEvent_data(); void opaquePaintEvent(); + void complexWidgetFocus(); void task188195_baseBackground(); void task232085_spinBoxLineEditBg(); @@ -1447,6 +1448,60 @@ void tst_QStyleSheetStyle::opaquePaintEvent() QCOMPARE(cl.autoFillBackground(), !styled ); } +void tst_QStyleSheetStyle::complexWidgetFocus() +{ + // This test is a simplified version of the focusColors() test above. + + // Tests if colors can be changed by altering the focus of the widget. + // To avoid messy pixel-by-pixel comparison, we assume that the goal + // is reached if at least ten pixels of the right color can be found in + // the image. + // For this reason, we use unusual and extremely ugly colors! :-) + + QDialog frame; + // We only want to test the buttons colors. + frame.setStyleSheet("*:focus { background: black; color: black } " + "QSpinBox::up-button:focus, QSpinBox::down-button:focus { width: 15px; height: 15px; background: #e8ff66; color: #ff0084 } " + "QSpinBox::up-arrow:focus, QSpinBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 } " + "QComboBox::drop-down:focus { background: #e8ff66; color: #ff0084 } " + "QComboBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084; color: #e8ff66 }"); + + QList widgets; + widgets << new QSpinBox; + widgets << new QComboBox; + + QLayout* layout = new QGridLayout; + layout->addWidget(new QLineEdit); // Avoids initial focus. + foreach (QWidget *widget, widgets) + layout->addWidget(widget); + frame.setLayout(layout); + + frame.show(); + QTest::qWaitForWindowShown(&frame); + QApplication::setActiveWindow(&frame); + foreach (QWidget *widget, widgets) { + widget->setFocus(); + QApplication::processEvents(); + + QImage image(frame.width(), frame.height(), QImage::Format_ARGB32); + frame.render(&image); + if (image.depth() < 24) { + QSKIP("Test doesn't support color depth < 24", SkipAll); + } + + QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)), + (QString::fromLatin1(widget->metaObject()->className()) + + " did not contain background color #e8ff66, using style " + + QString::fromLatin1(qApp->style()->metaObject()->className())) + .toLocal8Bit().constData()); + QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)), + (QString::fromLatin1(widget->metaObject()->className()) + + " did not contain text color #ff0084, using style " + + QString::fromLatin1(qApp->style()->metaObject()->className())) + .toLocal8Bit().constData()); + } +} + void tst_QStyleSheetStyle::task188195_baseBackground() { QTreeView tree; -- cgit v0.12 From e97b99f249ed65c6cedfc23f751a9834641271cb Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Wed, 23 Sep 2009 14:52:08 +0200 Subject: Added QSlider to tst_QStyleSheetStyle::complexWidgetFocus. When using style sheets, QSlider::handle couldn't be customized if QSlider::groove wasn't. QComboBox::down-arrow:focus wasn't properly drawn. Reviewed-by: Olivier --- src/gui/styles/qstylesheetstyle.cpp | 20 +++++++++++++------- src/gui/styles/qwindowsstyle.cpp | 2 ++ tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp | 12 +++--------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index def82ae..0f3a88b 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3136,19 +3136,25 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC if (const QStyleOptionSlider *slider = qstyleoption_cast(opt)) { rule.drawRule(p, opt->rect); - QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderGroove); - if (!subRule.hasDrawable()) { - baseStyle()->drawComplexControl(cc, slider, p, w); - return; + QRenderRule grooveSubRule = renderRule(w, opt, PseudoElement_SliderGroove); + QRenderRule handleSubRule = renderRule(w, opt, PseudoElement_SliderHandle); + if (!grooveSubRule.hasDrawable()) { + QStyleOptionSlider slOpt(*slider); + bool handleHasRule = handleSubRule.hasDrawable(); + // If the style specifies a different handler rule, draw the groove without the handler. + if (handleHasRule) + slOpt.subControls &= ~SC_SliderHandle; + baseStyle()->drawComplexControl(cc, &slOpt, p, w); + if (!handleHasRule) + return; } QRect gr = subControlRect(cc, opt, SC_SliderGroove, w); if (slider->subControls & SC_SliderGroove) { - subRule.drawRule(p, gr); + grooveSubRule.drawRule(p, gr); } if (slider->subControls & SC_SliderHandle) { - QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderHandle); QRect hr = subControlRect(cc, opt, SC_SliderHandle, w); QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage); @@ -3169,7 +3175,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC subRule2.drawRule(p, r); } - subRule.drawRule(p, subRule.boxRect(hr, Margin)); + handleSubRule.drawRule(p, grooveSubRule.boxRect(hr, Margin)); } if (slider->subControls & SC_SliderTickmarks) { diff --git a/src/gui/styles/qwindowsstyle.cpp b/src/gui/styles/qwindowsstyle.cpp index 2ed9303..0f72440 100644 --- a/src/gui/styles/qwindowsstyle.cpp +++ b/src/gui/styles/qwindowsstyle.cpp @@ -3030,6 +3030,8 @@ void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComp ar.adjust(2, 2, -2, -2); if (opt->state & State_Enabled) flags |= State_Enabled; + if (opt->state & State_HasFocus) + flags |= State_HasFocus; if (sunkenArrow) flags |= State_Sunken; diff --git a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp index e8fbd86..50bb846 100644 --- a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -1459,16 +1459,15 @@ void tst_QStyleSheetStyle::complexWidgetFocus() // For this reason, we use unusual and extremely ugly colors! :-) QDialog frame; - // We only want to test the buttons colors. frame.setStyleSheet("*:focus { background: black; color: black } " - "QSpinBox::up-button:focus, QSpinBox::down-button:focus { width: 15px; height: 15px; background: #e8ff66; color: #ff0084 } " "QSpinBox::up-arrow:focus, QSpinBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 } " - "QComboBox::drop-down:focus { background: #e8ff66; color: #ff0084 } " - "QComboBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084; color: #e8ff66 }"); + "QComboBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 }" + "QSlider::handle:horizontal:focus { width: 7px; height: 7px; background: #ff0084 } "); QList widgets; widgets << new QSpinBox; widgets << new QComboBox; + widgets << new QSlider(Qt::Horizontal); QLayout* layout = new QGridLayout; layout->addWidget(new QLineEdit); // Avoids initial focus. @@ -1489,11 +1488,6 @@ void tst_QStyleSheetStyle::complexWidgetFocus() QSKIP("Test doesn't support color depth < 24", SkipAll); } - QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)), - (QString::fromLatin1(widget->metaObject()->className()) - + " did not contain background color #e8ff66, using style " - + QString::fromLatin1(qApp->style()->metaObject()->className())) - .toLocal8Bit().constData()); QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)), (QString::fromLatin1(widget->metaObject()->className()) + " did not contain text color #ff0084, using style " -- cgit v0.12 From bfdee5f1658b1bac4a0d1b93c5a45dbc6709f9e3 Mon Sep 17 00:00:00 2001 From: mae Date: Wed, 23 Sep 2009 15:28:24 +0200 Subject: QTextCursor selection extension when inserting characters The change makes QTextCursor not extend the selection when inserting characters at the end of the selection, provided that the cursor position is at the end. Reviewed-by: Simon Hausmann Reviewed-by: Roberto Raggi --- src/gui/text/qtextcursor.cpp | 8 ++- tests/auto/qtextcursor/tst_qtextcursor.cpp | 94 ++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index 8b85d2d..ce62834 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -92,8 +92,12 @@ QTextCursorPrivate::AdjustResult QTextCursorPrivate::adjustPosition(int position { QTextCursorPrivate::AdjustResult result = QTextCursorPrivate::CursorMoved; // not(!) <= , so that inserting text adjusts the cursor correctly - if (position < positionOfChange || - (position == positionOfChange && op == QTextUndoCommand::KeepCursor)) { + if (position < positionOfChange + || (position == positionOfChange + && (op == QTextUndoCommand::KeepCursor + || anchor < position) + ) + ) { result = CursorUnchanged; } else { if (charsAddedOrRemoved < 0 && position < positionOfChange - charsAddedOrRemoved) diff --git a/tests/auto/qtextcursor/tst_qtextcursor.cpp b/tests/auto/qtextcursor/tst_qtextcursor.cpp index 88ecc73..d910c8d 100644 --- a/tests/auto/qtextcursor/tst_qtextcursor.cpp +++ b/tests/auto/qtextcursor/tst_qtextcursor.cpp @@ -147,6 +147,8 @@ private slots: void task244408_wordUnderCursor_data(); void task244408_wordUnderCursor(); + void adjustCursorsOnInsert(); + private: int blockCount(); @@ -1658,5 +1660,97 @@ void tst_QTextCursor::task244408_wordUnderCursor() QCOMPARE(cursor.selectedText(), expected); } +void tst_QTextCursor::adjustCursorsOnInsert() +{ + cursor.insertText("Some text before "); + int posBefore = cursor.position(); + cursor.insertText("selected text"); + int posAfter = cursor.position(); + cursor.insertText(" some text afterwards"); + + QTextCursor selection = cursor; + selection.setPosition(posBefore); + selection.setPosition(posAfter, QTextCursor::KeepAnchor); + + cursor.setPosition(posBefore-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore+1); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore+1); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter); + doc->undo(); + + cursor.setPosition(posAfter+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter); + doc->undo(); + + selection.setPosition(posAfter); + selection.setPosition(posBefore, QTextCursor::KeepAnchor); + + cursor.setPosition(posBefore-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore+1); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore+1); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter); + doc->undo(); + + + + +} + QTEST_MAIN(tst_QTextCursor) #include "tst_qtextcursor.moc" -- cgit v0.12 From 061f4976c7a3f9ac86ccd289ee93fc64182de27d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Sep 2009 15:18:06 +0200 Subject: missing & in foreach --- tools/linguist/lupdate/cpp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index be86c93..6c56a56 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -1969,7 +1969,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat CppFiles::setResults(filename, parser.getResults()); } - foreach (const QString filename, filenames) + foreach (const QString &filename, filenames) if (!CppFiles::isBlacklisted(filename)) if (Translator *tor = CppFiles::getResults(filename)->tor) foreach (const TranslatorMessage &msg, tor->messages()) -- cgit v0.12 From f64753362edf6c22879b1f39e83de1f69b8dda77 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Sep 2009 10:55:40 +0200 Subject: simplify --- tools/linguist/lupdate/cpp.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 6c56a56..9b7fdc8 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -1056,10 +1056,7 @@ QSet &CppFiles::blacklistedFiles() const ParseResults *CppFiles::getResults(const QString &cleanFile) { - ParseResultHash::ConstIterator it = parsedFiles().find(cleanFile); - if (it == parsedFiles().constEnd()) - return 0; - return *it; + return parsedFiles().value(cleanFile); } void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) -- cgit v0.12 From 5fc344431354c00340d9727f64dbb3c29972f93d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 17:31:05 +0200 Subject: optimize directory scanning qdiroperator uses qregexp for filtering, which is sloooow. so use a hash lookup on extensions instead. --- tools/linguist/lupdate/main.cpp | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp index 3cba90d..e8cf121 100644 --- a/tools/linguist/lupdate/main.cpp +++ b/tools/linguist/lupdate/main.cpp @@ -62,23 +62,14 @@ static void printOut(const QString & out) } static void recursiveFileInfoList(const QDir &dir, - const QStringList &nameFilters, QDir::Filters filter, bool recursive, + const QSet &nameFilters, QDir::Filters filter, QFileInfoList *fileinfolist) { - if (recursive) - filter |= QDir::AllDirs; - QFileInfoList entries = dir.entryInfoList(nameFilters, filter); - - QFileInfoList::iterator it; - for (it = entries.begin(); it != entries.end(); ++it) { - QString fname = it->fileName(); - if (fname != QLatin1String(".") && fname != QLatin1String("..")) { - if (it->isDir()) - recursiveFileInfoList(QDir(it->absoluteFilePath()), nameFilters, filter, recursive, fileinfolist); - else - fileinfolist->append(*it); - } - } + foreach (const QFileInfo &fi, dir.entryInfoList(filter)) + if (fi.isDir()) + recursiveFileInfoList(QDir(fi.absoluteFilePath()), nameFilters, filter, fileinfolist); + else if (nameFilters.contains(fi.suffix())) + fileinfolist->append(fi); } static void printUsage() @@ -243,7 +234,7 @@ int main(int argc, char **argv) bool recursiveScan = true; QString extensions = m_defaultExtensions; - QStringList extensionsNameFilters; + QSet extensionsNameFilters; for (int i = 1; i < argc; ++i) { if (args.at(i) == QLatin1String("-ts")) @@ -418,15 +409,15 @@ int main(int argc, char **argv) foreach (QString ext, extensions.split(QLatin1Char(','))) { ext = ext.trimmed(); if (ext.startsWith(QLatin1Char('.'))) - ext.remove(0,1); - ext.insert(0, QLatin1String("*.")); - extensionsNameFilters << ext; + ext.remove(0, 1); + extensionsNameFilters.insert(ext); } } QDir::Filters filters = QDir::Files | QDir::NoSymLinks; + if (recursiveScan) + filters |= QDir::AllDirs | QDir::NoDotAndDotDot; QFileInfoList fileinfolist; - recursiveFileInfoList(dir, extensionsNameFilters, filters, - recursiveScan, &fileinfolist); + recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist); int scanRootLen = dir.absolutePath().length(); foreach (const QFileInfo &fi, fileinfolist) { QString fn = QDir::cleanPath(fi.absoluteFilePath()); -- cgit v0.12 From 5bd5154ae0095a3e166e8be9347c613b2194e0be Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 19:14:21 +0200 Subject: cut down use of qstring::simplified() --- tools/linguist/lupdate/cpp.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 9b7fdc8..e72f1c9 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE /* qmake ignore Q_OBJECT */ -static const char MagicComment[] = "TRANSLATOR "; +static QString MagicComment(QLatin1String("TRANSLATOR")); #define STRING(s) static QString str##s(QLatin1String(#s)) @@ -1811,9 +1811,15 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } sourcetext.resize(ptr - (ushort *)sourcetext.data()); } else { - comment = yyWord.simplified(); - if (comment.startsWith(QLatin1String(MagicComment))) { - comment.remove(0, sizeof(MagicComment) - 1); + const ushort *uc = (const ushort *)yyWord.unicode(); // Is zero-terminated + int idx = 0; + ushort c; + while ((c = uc[idx]) == ' ' || c == '\t' || c == '\n') + ++idx; + if (!memcmp(uc + idx, MagicComment.unicode(), MagicComment.length() * 2)) { + idx += MagicComment.length(); + comment = QString::fromRawData(yyWord.unicode() + idx, + yyWord.length() - idx).simplified(); int k = comment.indexOf(QLatin1Char(' ')); if (k == -1) { context = comment; @@ -1826,8 +1832,6 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) results->tor->setExtras(extra); extra.clear(); } - } else { - comment.detach(); } } yyTok = getToken(); -- cgit v0.12 From 2bc1550b3dfe05353c2cb72f9d980c67e68aceaf Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 19:23:09 +0200 Subject: avoid isalpha() & isalnum() they are surprisingly expensive --- tools/linguist/lupdate/cpp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index e72f1c9..c224e2f 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -561,12 +561,13 @@ uint CppParser::getToken() } } while (yyCh != '\n' && yyCh != EOF); yyCh = getChar(); - } else if (isalpha(yyCh) || yyCh == '_') { + } else if ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') || yyCh == '_') { ushort *ptr = (ushort *)yyWord.unicode(); do { *ptr++ = yyCh; yyCh = getChar(); - } while (isalnum(yyCh) || yyCh == '_'); + } while ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') + || (yyCh >= '0' && yyCh <= '9') || yyCh == '_'); yyWord.resize(ptr - (ushort *)yyWord.unicode()); //qDebug() << "IDENT: " << yyWord; -- cgit v0.12 From b17a8c5c1bc7d8c26f2bf35116de71d7b582751f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 19:59:28 +0200 Subject: when matching strings, skip also leading comments --- tools/linguist/lupdate/cpp.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index c224e2f..b8f8451 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -1174,16 +1174,18 @@ bool CppParser::match(uint t) bool CppParser::matchString(QString *s) { - bool matches = (yyTok == Tok_String); + bool matches = false; s->clear(); - while (yyTok == Tok_String) { + forever { + while (yyTok == Tok_Comment) + yyTok = getToken(); + if (yyTok != Tok_String) + return matches; + matches = true; *s += yyWord; s->detach(); - do { - yyTok = getToken(); - } while (yyTok == Tok_Comment); + yyTok = getToken(); } - return matches; } bool CppParser::matchEncoding(bool *utf8) -- cgit v0.12 From d5d169a79fe199ad210d5625b20344bdc2814e60 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 20:01:15 +0200 Subject: no need to actually compute number values. only 0 is special --- tools/linguist/lupdate/cpp.cpp | 55 ++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index b8f8451..8de403e 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -167,7 +167,6 @@ private: bool match(uint t); bool matchString(QString *s); bool matchEncoding(bool *utf8); - bool matchInteger(qlonglong *number); bool matchStringOrNull(QString *s); bool matchExpression(); @@ -202,7 +201,7 @@ private: Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, Tok_Equals, Tok_LeftBrace = 30, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, - Tok_Integer = 40, + Tok_Null = 40, Tok_Integer, Tok_QuotedInclude = 50, Tok_AngledInclude, Tok_Other = 99 }; @@ -796,6 +795,17 @@ uint CppParser::getToken() yyCh = getChar(); return Tok_Semicolon; case '0': + yyCh = getChar(); + if (yyCh == 'x') { + do { + yyCh = getChar(); + } while ((yyCh >= '0' && yyCh <= '9') + || (yyCh >= 'a' && yyCh <= 'f') || (yyCh >= 'A' && yyCh <= 'F')); + return Tok_Integer; + } + if (yyCh < '0' || yyCh > '9') + return Tok_Null; + // Fallthrough case '1': case '2': case '3': @@ -805,25 +815,10 @@ uint CppParser::getToken() case '7': case '8': case '9': - { - QByteArray ba; - ba += yyCh; + do { yyCh = getChar(); - bool hex = yyCh == 'x'; - if (hex) { - ba += yyCh; - yyCh = getChar(); - } - while (hex ? isxdigit(yyCh) : isdigit(yyCh)) { - ba += yyCh; - yyCh = getChar(); - } - bool ok; - yyInteger = ba.toLongLong(&ok); - if (ok) - return Tok_Integer; - break; - } + } while (yyCh >= '0' && yyCh <= '9'); + return Tok_Integer; default: yyCh = getChar(); break; @@ -1211,28 +1206,14 @@ bool CppParser::matchEncoding(bool *utf8) if (yyWord == strDefaultCodec || yyWord == strCodecForTr) { *utf8 = false; yyTok = getToken(); - return true; + return true; } return false; } -bool CppParser::matchInteger(qlonglong *number) -{ - bool matches = (yyTok == Tok_Integer); - if (matches) { - yyTok = getToken(); - *number = yyInteger; - } - return matches; -} - bool CppParser::matchStringOrNull(QString *s) { - bool matches = matchString(s); - qlonglong num = 0; - if (!matches) - matches = matchInteger(&num); - return matches && num == 0; + return matchString(s) || match(Tok_Null); } /* @@ -1251,7 +1232,7 @@ bool CppParser::matchStringOrNull(QString *s) */ bool CppParser::matchExpression() { - if (match(Tok_Integer)) + if (match(Tok_Null) || match(Tok_Integer)) return true; int parenlevel = 0; -- cgit v0.12 From e4e45bc5bb3a4b38f8f726b26f863c1fdb5575f1 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 20:09:47 +0200 Subject: take advantage of knowing that qstrings are zero-terminated internally --- tools/linguist/lupdate/cpp.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 8de403e..3999b84 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -307,13 +307,12 @@ void CppParser::setInput(QTextStream &ts, const QString &fileName) uint CppParser::getChar() { - int len = yyInStr.size(); const ushort *uc = (const ushort *)yyInStr.unicode(); forever { - if (yyInPos >= len) - return EOF; uint c = uc[yyInPos++]; - if (c == '\\' && yyInPos < len) { + if (!c) + return EOF; + if (c == '\\') { if (uc[yyInPos] == '\n') { ++yyCurLineNo; ++yyInPos; @@ -322,13 +321,13 @@ uint CppParser::getChar() if (uc[yyInPos] == '\r') { ++yyCurLineNo; ++yyInPos; - if (yyInPos < len && uc[yyInPos] == '\n') + if (uc[yyInPos] == '\n') ++yyInPos; continue; } } if (c == '\r') { - if (yyInPos < len && uc[yyInPos] == '\n') + if (uc[yyInPos] == '\n') ++yyInPos; c = '\n'; ++yyCurLineNo; -- cgit v0.12 From 830fd43c53a9cd53d626b8f6fe3682d92df0cc59 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 20:19:25 +0200 Subject: use a source char pointer instead of a string + index --- tools/linguist/lupdate/cpp.cpp | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 3999b84..8e9933d 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -226,7 +226,7 @@ private: QTextCodec *yySourceCodec; bool yySourceIsUnicode; QString yyInStr; - int yyInPos; + const ushort *yyInPtr; // Parser state uint yyTok; @@ -254,7 +254,6 @@ CppParser::CppParser(ParseResults *_results) results = new ParseResults; directInclude = false; } - yyInPos = 0; yyBraceDepth = 0; yyParenDepth = 0; yyCurLineNo = 1; @@ -307,28 +306,32 @@ void CppParser::setInput(QTextStream &ts, const QString &fileName) uint CppParser::getChar() { - const ushort *uc = (const ushort *)yyInStr.unicode(); + const ushort *uc = yyInPtr; forever { - uint c = uc[yyInPos++]; - if (!c) + ushort c = *uc; + if (!c) { + yyInPtr = uc; return EOF; + } + ++uc; if (c == '\\') { - if (uc[yyInPos] == '\n') { + ushort cc = *uc; + if (cc == '\n') { ++yyCurLineNo; - ++yyInPos; + ++uc; continue; } - if (uc[yyInPos] == '\r') { + if (cc == '\r') { ++yyCurLineNo; - ++yyInPos; - if (uc[yyInPos] == '\n') - ++yyInPos; + ++uc; + if (*uc == '\n') + ++uc; continue; } } if (c == '\r') { - if (uc[yyInPos] == '\n') - ++yyInPos; + if (*uc == '\n') + ++uc; c = '\n'; ++yyCurLineNo; yyAtNewline = true; @@ -338,6 +341,7 @@ uint CppParser::getChar() } else if (c != ' ' && c != '\t' && c != '#') { yyAtNewline = false; } + yyInPtr = uc; return c; } } @@ -1355,6 +1359,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) bool yyTokColonSeen = false; // Start of c'tor's initializer list yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking. + yyInPtr = (const ushort *)yyInStr.unicode(); yyCh = getChar(); yyTok = getToken(); while (yyTok != Tok_Eof) { -- cgit v0.12 From 13fa5aa35e6cbf6bf7710952f541810fee7bba27 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 18 Aug 2009 20:33:57 +0200 Subject: move static objects out of function scope cuts away a few thousand instructions. need to revisit this in case of making the parser a dynamic library. --- tools/linguist/lupdate/cpp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 8e9933d..f6ebfb1 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -1186,14 +1186,14 @@ bool CppParser::matchString(QString *s) } } +STRING(QApplication); +STRING(QCoreApplication); +STRING(UnicodeUTF8); +STRING(DefaultCodec); +STRING(CodecForTr); + bool CppParser::matchEncoding(bool *utf8) { - STRING(QApplication); - STRING(QCoreApplication); - STRING(UnicodeUTF8); - STRING(DefaultCodec); - STRING(CodecForTr); - if (yyTok != Tok_Ident) return false; if (yyWord == strQApplication || yyWord == strQCoreApplication) { -- cgit v0.12 From 313c49628ac74f647df0f3b1e2a660ebd1f4436c Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 18 Sep 2009 12:35:12 +0200 Subject: remove dead code needsTrFunctions was never set any more --- tools/linguist/lupdate/cpp.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index f6ebfb1..c6f38a0 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -76,7 +76,7 @@ struct Namespace { Namespace() : isClass(false), - hasTrFunctions(false), needsTrFunctions(false), complained(false) + hasTrFunctions(false), complained(false) {} QString name; @@ -89,7 +89,6 @@ struct Namespace { bool isClass; bool hasTrFunctions; - bool needsTrFunctions; bool complained; // ... that tr functions are missing. }; @@ -875,7 +874,6 @@ Namespace *ParseResults::include(Namespace *that, const Namespace *other) // (though not necessary) if they are shared thisSub->isClass |= otherSub->isClass; thisSub->hasTrFunctions |= otherSub->hasTrFunctions; - thisSub->needsTrFunctions |= otherSub->needsTrFunctions; thisSub->complained |= otherSub->complained; if (Namespace *newSub = include(thisSub, otherSub)) { @@ -1843,17 +1841,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) #endif break; case Tok_RightBrace: - if (yyBraceDepth + 1 == namespaceDepths.count()) { - // class or namespace - Namespace *ns = namespaces.last(); - if (ns->needsTrFunctions && !ns->hasTrFunctions && !ns->complained) { - qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", - qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(namespaces))); - ns->complained = true; - } + if (yyBraceDepth + 1 == namespaceDepths.count()) // class or namespace truncateNamespaces(&namespaces, namespaceDepths.pop()); - } if (yyBraceDepth == namespaceDepths.count()) { // function, class or namespace if (!yyBraceDepth && !directInclude) { -- cgit v0.12 From dd499bac5ce01abe730d47a84c7ad3e29bc3cf4d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 17 Sep 2009 19:21:15 +0200 Subject: remove more dead code no need for parameter "unresolved" --- tools/linguist/lupdate/cpp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index c6f38a0..fce53af 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -1521,8 +1521,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) yyTok = getToken(); } NamespaceList nsl; - QStringList unresolved; - if (fullyQualify(namespaces, fullName, false, &nsl, &unresolved)) { + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { modifyNamespace(&namespaces); namespaces.last()->usings.insert(stringListifyNamespace(nsl)); } -- cgit v0.12 From b647762117f49a3e8d20ceba84c47d4fb2941722 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 18 Sep 2009 16:10:13 +0200 Subject: do not record class forward declarations they don't create useful namespaces and don't hold flags, so it is pointless to clutter the namespace maps with them. --- tools/linguist/lupdate/cpp.cpp | 55 +++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index fce53af..5dbb8e2 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -1394,8 +1394,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } case Tok_friend: yyTok = getToken(); - // Ensure that these don't end up being interpreted as forward declarations - // (they are forwards, but with different namespacing). + // These are forward declarations, so ignore them. if (yyTok == Tok_class) yyTok = getToken(); break; @@ -1406,7 +1405,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) */ yyTok = getToken(); if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { - QStringList fct; + QStringList quali; + QString fct; do { /* This code should execute only once, but we play @@ -1414,52 +1414,51 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) 'class Q_EXPORT QMessageBox', in which case 'QMessageBox' is the class name, not 'Q_EXPORT'. */ - text = yyWord; - text.detach(); - fct = QStringList(text); + fct = yyWord; + fct.detach(); yyTok = getToken(); } while (yyTok == Tok_Ident); while (yyTok == Tok_ColonColon) { yyTok = getToken(); if (yyTok != Tok_Ident) break; // Oops ... - text = yyWord; - text.detach(); - fct += text; + quali << fct; + fct = yyWord; + fct.detach(); yyTok = getToken(); } - if (fct.count() > 1) { - // Forward-declared class definitions can be namespaced - NamespaceList nsl; - if (!fullyQualify(namespaces, fct, true, &nsl, 0)) { - qWarning("%s:%d: Ignoring definition of undeclared qualified class\n", - qPrintable(yyFileName), yyLineNo); - break; - } - namespaceDepths.push(namespaces.count()); - namespaces = nsl; - } else { - namespaceDepths.push(namespaces.count()); - enterNamespace(&namespaces, fct.first()); - } - namespaces.last()->isClass = true; - while (yyTok == Tok_Comment) yyTok = getToken(); if (yyTok == Tok_Colon) { - // Skip any token until '{' since lupdate might do things wrong if it finds + // Skip any token until '{' since we might do things wrong if we find // a '::' token here. do { yyTok = getToken(); } while (yyTok != Tok_LeftBrace && yyTok != Tok_Eof); } else { if (yyTok != Tok_LeftBrace) { - // Obviously a forward decl - truncateNamespaces(&namespaces, namespaceDepths.pop()); + // Obviously a forward declaration. We skip those, as they + // don't create actually usable namespaces. break; } } + if (!quali.isEmpty()) { + // Forward-declared class definitions can be namespaced. + NamespaceList nsl; + if (!fullyQualify(namespaces, quali, true, &nsl, 0)) { + qWarning("%s:%d: Ignoring definition of undeclared qualified class\n", + qPrintable(yyFileName), yyLineNo); + break; + } + namespaceDepths.push(namespaces.count()); + namespaces = nsl; + } else { + namespaceDepths.push(namespaces.count()); + } + enterNamespace(&namespaces, fct); + namespaces.last()->isClass = true; + functionContext = namespaces; functionContextUnresolved.clear(); // Pointless prospectiveContext.clear(); -- cgit v0.12 From 57df91e20b8e669f4833e1f11dc2474d8118e0c9 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 18 Sep 2009 17:52:10 +0200 Subject: optimize/clarify function context stringification --- tools/linguist/lupdate/cpp.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 5dbb8e2..d5d2e10 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -1590,14 +1590,14 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } while (!functionContext.at(idx - 1)->hasTrFunctions) { if (idx == 1 || !functionContext.at(idx - 2)->isClass) { - idx = functionContext.length(); + context = stringifyNamespace(functionContext); if (!functionContext.last()->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(functionContext))); + qPrintable(context)); functionContext.last()->complained = true; } - break; + goto gotctx; } --idx; } @@ -1626,19 +1626,20 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) NamespaceList nsl; QStringList unresolved; if (fullyQualify(functionContext, prefix.split(strColons), false, &nsl, &unresolved)) { + context = stringifyNamespace(nsl); if (!nsl.last()->hasTrFunctions && !nsl.last()->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(nsl))); + qPrintable(context)); nsl.last()->complained = true; } - context = stringifyNamespace(nsl); } else { context = (stringListifyNamespace(nsl) + unresolved).join(strColons); } prefix.clear(); } + gotctx: recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural); } extracomment.clear(); -- cgit v0.12 From 1c4dc6be0c5b6a730e5ae910afa8c4da986e37ee Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Sep 2009 12:47:45 +0200 Subject: drastically improve lupdate's scalability do not import all data from included files into the current file (which turned out to be extremely expensive for 3rdparty/webkit), but do hierarchical lookups on demand. this makes the lookups as such much slower, of course, but it still pays off. --- tools/linguist/lupdate/cpp.cpp | 477 ++++++++++++++++++++++++----------------- 1 file changed, 280 insertions(+), 197 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index d5d2e10..c9b25f3 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -43,6 +43,7 @@ #include +#include #include #include #include @@ -62,53 +63,110 @@ static QString MagicComment(QLatin1String("TRANSLATOR")); //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this -uint qHash(const QStringList &qsl) +class HashString { +public: + HashString() : m_hashed(false) {} + explicit HashString(const QString &str) : m_str(str), m_hashed(false) {} + void setValue(const QString &str) { m_str = str; m_hashed = false; } + const QString &value() const { return m_str; } + bool operator==(const HashString &other) const { return m_str == other.m_str; } +private: + QString m_str; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashString &str); +}; + +uint qHash(const HashString &str) +{ + if (!str.m_hashed) { + str.m_hashed = true; + str.m_hash = qHash(str.m_str); + } + return str.m_hash; +} + +class HashStringList { +public: + explicit HashStringList(const QList &list) : m_list(list), m_hashed(false) {} + const QList &value() const { return m_list; } + bool operator==(const HashStringList &other) const { return m_list == other.m_list; } +private: + QList m_list; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashStringList &list); +}; + +uint qHash(const HashStringList &list) { - uint hash = 0; - foreach (const QString &qs, qsl) { - hash ^= qHash(qs) ^ 0xa09df22f; - hash = (hash << 13) | (hash >> 19); + if (!list.m_hashed) { + list.m_hashed = true; + uint hash = 0; + foreach (const HashString &qs, list.m_list) { + hash ^= qHash(qs) ^ 0xa09df22f; + hash = (hash << 13) | (hash >> 19); + } + list.m_hash = hash; } - return hash; + return list.m_hash; } +typedef QList NamespaceList; + struct Namespace { Namespace() : - isClass(false), + classDef(0), hasTrFunctions(false), complained(false) {} - QString name; - QMap children; - QMap aliases; - QSet usings; - - int fileId; + QHash children; + QHash aliases; + QList usings; - bool isClass; + // Class declarations set no flags and create no namespaces, so they are ignored. + // Class definitions may appear multiple times - but only because we are trying to + // "compile" all sources irrespective of build configuration. + // Nested classes may be forward-declared inside a definition, and defined in another file. + // The latter will detach the class' child list, so clones need a backlink to the original + // definition (either one in case of multiple definitions). + Namespace *classDef; bool hasTrFunctions; bool complained; // ... that tr functions are missing. }; -typedef QList NamespaceList; +static int nextFileId; + +class VisitRecorder { +public: + VisitRecorder() + { + m_ba.resize(nextFileId); + } + bool tryVisit(int fileId) + { + if (m_ba.at(fileId)) + return false; + m_ba[fileId] = true; + return true; + } +private: + QBitArray m_ba; +}; struct ParseResults { ParseResults() { - static int nextFileId; - rootNamespace.fileId = nextFileId++; tor = 0; } - bool detachNamespace(Namespace **that); - Namespace *include(Namespace *that, const Namespace *other); - void unite(const ParseResults *other); + int fileId; Namespace rootNamespace; Translator *tor; - QSet allIncludes; + QSet includes; }; typedef QHash ParseResultHash; @@ -117,7 +175,7 @@ class CppFiles { public: static const ParseResults *getResults(const QString &cleanFile); - static void setResults(const QString &cleanFile, const ParseResults *results); + static void setResults(const QString &cleanFile, ParseResults *results); static bool isBlacklisted(const QString &cleanFile); static void setBlacklisted(const QString &cleanFile); @@ -135,13 +193,13 @@ public: void setTranslator(Translator *tor) { results->tor = tor; } void parse(const QString &initialContext, ConversionData &cd, QSet &inclusions); void parseInternal(ConversionData &cd, QSet &inclusions); - const ParseResults *getResults() const { return results; } + ParseResults *getResults() const { return results; } void deleteResults() { delete results; } struct SavedState { - QStringList namespaces; + NamespaceList namespaces; QStack namespaceDepths; - QStringList functionContext; + NamespaceList functionContext; QString functionContextUnresolved; QString pendingContext; }; @@ -183,15 +241,28 @@ private: static QString stringifyNamespace(const NamespaceList &namespaces); static QStringList stringListifyNamespace(const NamespaceList &namespaces); - void modifyNamespace(NamespaceList *namespaces); - NamespaceList resolveNamespaces(const QStringList &segments); - bool qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved); - bool fullyQualify(const NamespaceList &namespaces, const QStringList &segments, + typedef bool (CppParser::*VisitNamespaceCallback)(const Namespace *ns, void *context) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const; + static QStringList stringListifySegments(const QList &namespaces); + bool qualifyOneCallbackOwn(const Namespace *ns, void *context) const; + bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const; + bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, + NamespaceList *resolved) const; + bool fullyQualify(const NamespaceList &namespaces, const QList &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved); - void enterNamespace(NamespaceList *namespaces, const QString &name); + NamespaceList *resolved, QStringList *unresolved) const; + bool fullyQualify(const NamespaceList &namespaces, const QString &segments, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const; + bool findNamespaceCallback(const Namespace *ns, void *context) const; + const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; + void enterNamespace(NamespaceList *namespaces, const HashString &name, bool isClass); void truncateNamespaces(NamespaceList *namespaces, int lenght); + Namespace *modifyNamespace(NamespaceList *namespaces, bool tryOrigin = true); enum { Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, @@ -837,85 +908,40 @@ uint CppParser::getToken() void CppParser::saveState(SavedState *state) { - state->namespaces = stringListifyNamespace(namespaces); + state->namespaces = namespaces; state->namespaceDepths = namespaceDepths; - state->functionContext = stringListifyNamespace(functionContext); + state->functionContext = functionContext; state->functionContextUnresolved = functionContextUnresolved; state->pendingContext = pendingContext; } void CppParser::loadState(const SavedState *state) { - namespaces = resolveNamespaces(state->namespaces); + namespaces = state->namespaces; namespaceDepths = state->namespaceDepths; - functionContext = resolveNamespaces(state->functionContext); + functionContext = state->functionContext; functionContextUnresolved = state->functionContextUnresolved; pendingContext = state->pendingContext; } -bool ParseResults::detachNamespace(Namespace **that) -{ - if ((*that)->fileId != rootNamespace.fileId) { - Namespace *newThat = new Namespace; - *newThat = **that; - newThat->fileId = rootNamespace.fileId; - *that = newThat; - return true; - } - return false; -} - -Namespace *ParseResults::include(Namespace *that, const Namespace *other) +Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin) { - Namespace *origThat = that; - foreach (Namespace *otherSub, other->children) { - if (Namespace *thisSub = that->children.value(otherSub->name)) { - // Don't make these cause a detach - it's best - // (though not necessary) if they are shared - thisSub->isClass |= otherSub->isClass; - thisSub->hasTrFunctions |= otherSub->hasTrFunctions; - thisSub->complained |= otherSub->complained; - - if (Namespace *newSub = include(thisSub, otherSub)) { - thisSub = newSub; - detachNamespace(&that); - that->children[thisSub->name] = thisSub; - } - } else { - detachNamespace(&that); - that->children[otherSub->name] = otherSub; - } - } - if ((that->aliases != other->aliases && !other->aliases.isEmpty()) - || (that->usings != other->usings && !other->usings.isEmpty())) { - detachNamespace(&that); - that->aliases.unite(other->aliases); - that->usings.unite(other->usings); - } - return (that != origThat) ? that : 0; -} - -void ParseResults::unite(const ParseResults *other) -{ - allIncludes.unite(other->allIncludes); - include(&rootNamespace, &other->rootNamespace); -} - -void CppParser::modifyNamespace(NamespaceList *namespaces) -{ - Namespace *pns = 0; - int i = namespaces->count(); - forever { - --i; - Namespace *ns = namespaces->at(i); - bool detached = results->detachNamespace(&ns); - if (pns) - ns->children[pns->name] = pns; - if (!detached) // Known to be true for root namespace - return; + Namespace *pns, *ns = &results->rootNamespace; + for (int i = 1; i < namespaces->count(); ++i) { pns = ns; - namespaces->replace(i, ns); + if (!(ns = pns->children.value(namespaces->at(i)))) { + do { + ns = new Namespace; + if (tryOrigin) + if (const Namespace *ons = findNamespace(*namespaces, i + 1)) + ns->classDef = ons->classDef; + pns->children.insert(namespaces->at(i), ns); + pns = ns; + } while (++i < namespaces->count()); + break; + } } + return ns; } QString CppParser::stringifyNamespace(const NamespaceList &namespaces) @@ -924,7 +950,7 @@ QString CppParser::stringifyNamespace(const NamespaceList &namespaces) for (int i = 1; i < namespaces.count(); ++i) { if (i > 1) ret += QLatin1String("::"); - ret += namespaces.at(i)->name; + ret += namespaces.at(i).value(); } return ret; } @@ -933,58 +959,102 @@ QStringList CppParser::stringListifyNamespace(const NamespaceList &namespaces) { QStringList ret; for (int i = 1; i < namespaces.count(); ++i) - ret << namespaces.at(i)->name; + ret << namespaces.at(i).value(); return ret; } -// This function is called only with known-existing namespaces -NamespaceList CppParser::resolveNamespaces(const QStringList &segments) +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const { - NamespaceList ret; - Namespace *ns = &results->rootNamespace; - ret << ns; - foreach (const QString &seg, segments) { - ns = ns->children.value(seg); - ret << ns; - } + const Namespace *ns = &rslt->rootNamespace; + for (int i = 1; i < nsCount; ++i) + if (!(ns = ns->children.value(namespaces.at(i)))) + goto supers; + if ((this->*callback)(ns, context)) + return true; +supers: + foreach (const ParseResults *sup, rslt->includes) + if (vr.tryVisit(sup->fileId) + && visitNamespace(namespaces, nsCount, callback, context, vr, sup)) + return true; + return false; +} + +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const +{ + VisitRecorder vr; + return visitNamespace(namespaces, nsCount, callback, context, vr, results); +} + +QStringList CppParser::stringListifySegments(const QList &segments) +{ + QStringList ret; + for (int i = 0; i < segments.count(); ++i) + ret << segments.at(i).value(); return ret; } -bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved) +struct QualifyOneData { + const NamespaceList &namespaces; + int nsCount; + const HashString &segment; + NamespaceList *resolved; + QSet visitedUsings; +}; + +bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const { - const Namespace *ns = namespaces.at(nsIdx); - QMap::ConstIterator cnsi = ns->children.constFind(segment); - if (cnsi != ns->children.constEnd()) { - *resolved = namespaces.mid(0, nsIdx + 1); - *resolved << *cnsi; + QualifyOneData *data = (QualifyOneData *)context; + if (ns->children.contains(data->segment)) { + *data->resolved = data->namespaces.mid(0, data->nsCount); + *data->resolved << data->segment; return true; } - QMap::ConstIterator nsai = ns->aliases.constFind(segment); + QHash::ConstIterator nsai = ns->aliases.constFind(data->segment); if (nsai != ns->aliases.constEnd()) { - *resolved = resolveNamespaces(*nsai); + *data->resolved = *nsai; return true; } - foreach (const QStringList &use, ns->usings) { - NamespaceList usedNs = resolveNamespaces(use); - if (qualifyOne(usedNs, usedNs.count() - 1, segment, resolved)) - return true; - } return false; } -bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList &segments, +bool CppParser::qualifyOneCallbackUsing(const Namespace *ns, void *context) const +{ + QualifyOneData *data = (QualifyOneData *)context; + foreach (const HashStringList &use, ns->usings) + if (!data->visitedUsings.contains(use)) { + data->visitedUsings.insert(use); + if (qualifyOne(use.value(), use.value().count(), data->segment, data->resolved)) + return true; + } + return false; +} + +bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, + NamespaceList *resolved) const +{ + QualifyOneData data = { namespaces, nsCnt, segment, resolved, QSet() }; + + if (visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackOwn, &data)) + return true; + + return visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackUsing, &data); +} + +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) + NamespaceList *resolved, QStringList *unresolved) const { int nsIdx; int initSegIdx; - if (segments.first().isEmpty()) { + if (segments.first().value().isEmpty()) { // fully qualified if (segments.count() == 1) { resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); return true; } initSegIdx = 1; @@ -995,12 +1065,12 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } do { - if (qualifyOne(namespaces, nsIdx, segments[initSegIdx], resolved)) { + if (qualifyOne(namespaces, nsIdx + 1, segments[initSegIdx], resolved)) { int segIdx = initSegIdx; while (++segIdx < segments.count()) { - if (!qualifyOne(*resolved, resolved->count() - 1, segments[segIdx], resolved)) { + if (!qualifyOne(*resolved, resolved->count(), segments[segIdx], resolved)) { if (unresolved) - *unresolved = segments.mid(segIdx); + *unresolved = stringListifySegments(segments.mid(segIdx)); return false; } } @@ -1008,23 +1078,47 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } } while (!isDeclaration && --nsIdx >= 0); resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); if (unresolved) - *unresolved = segments.mid(initSegIdx); + *unresolved = stringListifySegments(segments.mid(initSegIdx)); return false; } -void CppParser::enterNamespace(NamespaceList *namespaces, const QString &name) +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const +{ + static QString strColons(QLatin1String("::")); + + QList segments; + foreach (const QString &str, quali.split(strColons)) // XXX slow, but needs to be fast(?) + segments << HashString(str); + return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved); +} + +bool CppParser::findNamespaceCallback(const Namespace *ns, void *context) const { - Namespace *ns = namespaces->last()->children.value(name); - if (!ns) { - ns = new Namespace; - ns->fileId = results->rootNamespace.fileId; - ns->name = name; - modifyNamespace(namespaces); - namespaces->last()->children[name] = ns; + *((const Namespace **)context) = ns; + return true; +} + +const Namespace *CppParser::findNamespace(const NamespaceList &namespaces, int nsCount) const +{ + const Namespace *ns = 0; + if (nsCount == -1) + nsCount = namespaces.count(); + visitNamespace(namespaces, nsCount, &CppParser::findNamespaceCallback, &ns); + return ns; +} + +void CppParser::enterNamespace(NamespaceList *namespaces, const HashString &name, bool isClass) +{ + *namespaces << name; + if (!findNamespace(*namespaces)) { + Namespace *ns = modifyNamespace(namespaces, false); + if (isClass) + ns->classDef = ns; } - *namespaces << ns; } void CppParser::truncateNamespaces(NamespaceList *namespaces, int length) @@ -1056,8 +1150,9 @@ const ParseResults *CppFiles::getResults(const QString &cleanFile) return parsedFiles().value(cleanFile); } -void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) +void CppFiles::setResults(const QString &cleanFile, ParseResults *results) { + results->fileId = nextFileId++; parsedFiles().insert(cleanFile, results); } @@ -1093,12 +1188,8 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, QString fileExt = QFileInfo(cleanFile).suffix(); if (fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive)) { - if (results->allIncludes.contains(cleanFile)) - return; - results->allIncludes.insert(cleanFile); - if (const ParseResults *res = CppFiles::getResults(cleanFile)) { - results->unite(res); + results->includes.insert(res); return; } @@ -1128,8 +1219,8 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, } parser.setInput(ts, cleanFile); parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(cleanFile, parser.getResults()); - results->unite(parser.results); + CppFiles::setResults(cleanFile, parser.results); + results->includes.insert(parser.results); } else { CppParser parser(results); parser.namespaces = namespaces; @@ -1138,12 +1229,6 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, parser.pendingContext = pendingContext; parser.setInput(ts, cleanFile); parser.parseInternal(cd, inclusions); - // Don't wreak havoc if not enough braces were found. - truncateNamespaces(&parser.namespaces, namespaces.count()); - truncateNamespaces(&parser.functionContext, functionContext.count()); - // Copy them back - the pointers might have changed. - namespaces = parser.namespaces; - functionContext = parser.functionContext; // Avoid that messages obtained by direct scanning are used CppFiles::setBlacklisted(cleanFile); } @@ -1330,7 +1415,7 @@ void CppParser::parse(const QString &initialContext, ConversionData &cd, if (results->tor) yyCodecIsUtf8 = (results->tor->codecName() == "UTF-8"); - namespaces << &results->rootNamespace; + namespaces << HashString(); functionContext = namespaces; functionContextUnresolved = initialContext; @@ -1405,8 +1490,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) */ yyTok = getToken(); if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { - QStringList quali; - QString fct; + QList quali; + HashString fct; do { /* This code should execute only once, but we play @@ -1414,8 +1499,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) 'class Q_EXPORT QMessageBox', in which case 'QMessageBox' is the class name, not 'Q_EXPORT'. */ - fct = yyWord; - fct.detach(); + text = yyWord; + text.detach(); + fct.setValue(text); yyTok = getToken(); } while (yyTok == Tok_Ident); while (yyTok == Tok_ColonColon) { @@ -1423,8 +1509,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) if (yyTok != Tok_Ident) break; // Oops ... quali << fct; - fct = yyWord; - fct.detach(); + text = yyWord; + text.detach(); + fct.setValue(text); yyTok = getToken(); } while (yyTok == Tok_Comment) @@ -1456,8 +1543,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } else { namespaceDepths.push(namespaces.count()); } - enterNamespace(&namespaces, fct); - namespaces.last()->isClass = true; + enterNamespace(&namespaces, fct, true); functionContext = namespaces; functionContextUnresolved.clear(); // Pointless @@ -1469,34 +1555,33 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) yyTokColonSeen = false; yyTok = getToken(); if (yyTok == Tok_Ident) { - QString ns = yyWord; - ns.detach(); + text = yyWord; + text.detach(); + HashString ns = HashString(text); yyTok = getToken(); if (yyTok == Tok_LeftBrace) { namespaceDepths.push(namespaces.count()); - enterNamespace(&namespaces, ns); + enterNamespace(&namespaces, ns, false); yyTok = getToken(); } else if (yyTok == Tok_Equals) { // e.g. namespace Is = OuterSpace::InnerSpace; - QStringList fullName; + QList fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(ns, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->aliases[ns] = nsl; } } else if (yyTok == Tok_LeftBrace) { // Anonymous namespace @@ -1506,43 +1591,40 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) break; case Tok_using: yyTok = getToken(); + // XXX this should affect only the current scope, not the entire current namespace if (yyTok == Tok_namespace) { - QStringList fullName; + QList fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->usings.insert(stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->usings << HashStringList(nsl); } else { - QStringList fullName; + QList fullName; if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(nsl.last()->name, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, true)->aliases[nsl.last()] = nsl; } break; case Tok_tr: @@ -1570,8 +1652,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } if (!pendingContext.isEmpty()) { QStringList unresolved; - if (!fullyQualify(namespaces, pendingContext.split(strColons), true, - &functionContext, &unresolved)) { + if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { functionContextUnresolved = unresolved.join(strColons); qWarning("%s:%d: Qualifying with unknown namespace/class %s::%s\n", qPrintable(yyFileName), yyLineNo, @@ -1588,14 +1669,15 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) qPrintable(yyFileName), yyLineNo); break; } - while (!functionContext.at(idx - 1)->hasTrFunctions) { - if (idx == 1 || !functionContext.at(idx - 2)->isClass) { + while (!findNamespace(functionContext, idx)->classDef->hasTrFunctions) { + if (idx == 1 || !findNamespace(functionContext, idx - 1)->classDef) { context = stringifyNamespace(functionContext); - if (!functionContext.last()->complained) { + Namespace *fctx = findNamespace(functionContext)->classDef; + if (!fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, qPrintable(context)); - functionContext.last()->complained = true; + fctx->complained = true; } goto gotctx; } @@ -1603,7 +1685,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } context.clear(); for (int i = 1;;) { - context += functionContext.at(i)->name; + context += functionContext.at(i).value(); if (++i == idx) break; context += strColons; @@ -1625,13 +1707,14 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) prefix.chop(2); NamespaceList nsl; QStringList unresolved; - if (fullyQualify(functionContext, prefix.split(strColons), false, &nsl, &unresolved)) { + if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { context = stringifyNamespace(nsl); - if (!nsl.last()->hasTrFunctions && !nsl.last()->complained) { + Namespace *fctx = findNamespace(nsl)->classDef; + if (!fctx->hasTrFunctions && !fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, qPrintable(context)); - nsl.last()->complained = true; + fctx->complained = true; } } else { context = (stringListifyNamespace(nsl) + unresolved).join(strColons); @@ -1727,7 +1810,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) break; case Tok_Q_DECLARE_TR_FUNCTIONS: case Tok_Q_OBJECT: - namespaces.last()->hasTrFunctions = true; + modifyNamespace(&namespaces, true)->hasTrFunctions = true; yyTok = getToken(); break; case Tok_Ident: -- cgit v0.12 From 158a48e06134845a72dcab14452390641747d211 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 22 Sep 2009 20:26:24 +0200 Subject: namespaces *can* have tr() functions, after all ... by virtue of the Q_DECLARE_TR_FUNCTIONS macro. so remove the artificial limitation to classes (which was mostly an optimization anyway). --- tools/linguist/lupdate/cpp.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index c9b25f3..81623ab 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -117,7 +117,7 @@ typedef QList NamespaceList; struct Namespace { Namespace() : - classDef(0), + classDef(this), hasTrFunctions(false), complained(false) {} @@ -260,7 +260,7 @@ private: NamespaceList *resolved, QStringList *unresolved) const; bool findNamespaceCallback(const Namespace *ns, void *context) const; const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; - void enterNamespace(NamespaceList *namespaces, const HashString &name, bool isClass); + void enterNamespace(NamespaceList *namespaces, const HashString &name); void truncateNamespaces(NamespaceList *namespaces, int lenght); Namespace *modifyNamespace(NamespaceList *namespaces, bool tryOrigin = true); @@ -1111,14 +1111,11 @@ const Namespace *CppParser::findNamespace(const NamespaceList &namespaces, int n return ns; } -void CppParser::enterNamespace(NamespaceList *namespaces, const HashString &name, bool isClass) +void CppParser::enterNamespace(NamespaceList *namespaces, const HashString &name) { *namespaces << name; - if (!findNamespace(*namespaces)) { - Namespace *ns = modifyNamespace(namespaces, false); - if (isClass) - ns->classDef = ns; - } + if (!findNamespace(*namespaces)) + modifyNamespace(namespaces, false); } void CppParser::truncateNamespaces(NamespaceList *namespaces, int length) @@ -1543,7 +1540,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } else { namespaceDepths.push(namespaces.count()); } - enterNamespace(&namespaces, fct, true); + enterNamespace(&namespaces, fct); functionContext = namespaces; functionContextUnresolved.clear(); // Pointless @@ -1561,7 +1558,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) yyTok = getToken(); if (yyTok == Tok_LeftBrace) { namespaceDepths.push(namespaces.count()); - enterNamespace(&namespaces, ns, false); + enterNamespace(&namespaces, ns); yyTok = getToken(); } else if (yyTok == Tok_Equals) { // e.g. namespace Is = OuterSpace::InnerSpace; @@ -1670,7 +1667,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) break; } while (!findNamespace(functionContext, idx)->classDef->hasTrFunctions) { - if (idx == 1 || !findNamespace(functionContext, idx - 1)->classDef) { + if (idx == 1) { context = stringifyNamespace(functionContext); Namespace *fctx = findNamespace(functionContext)->classDef; if (!fctx->complained) { -- cgit v0.12 From 178945342d0d46ddde460f230c22d2acb9f930a8 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 22 Sep 2009 20:27:26 +0200 Subject: actually use the argument of Q_DECLARE_TR_FUNCTIONS which means that one can set an arbitrary context. as a side effect, this caches the stringified context of Q_OBJECT-derived classes. --- .../lupdate/testdata/good/parsecontexts/main.cpp | 9 +++ .../testdata/good/parsecontexts/project.ts.result | 9 +++ tools/linguist/lupdate/cpp.cpp | 68 +++++++++++++++++++--- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp index 7e81b84..25c2c0d 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp +++ b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp @@ -262,6 +262,15 @@ QString C2::foo() } +namespace Fooish { + Q_DECLARE_TR_FUNCTIONS(Bears::And::Spiders) +} + +void Fooish::bar() +{ + return tr("whatever the context", "Bears::And::Spiders"); +} + int main(int /*argc*/, char ** /*argv*/) { return 0; diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result index 9b00d53..2f21de2 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result +++ b/tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result @@ -102,6 +102,15 @@ + Bears::And::Spiders + + + whatever the context + Bears::And::Spiders + + + + C1 diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 81623ab..44a8feb 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -133,6 +133,8 @@ struct Namespace { // definition (either one in case of multiple definitions). Namespace *classDef; + QString trQualification; + bool hasTrFunctions; bool complained; // ... that tr functions are missing. }; @@ -221,6 +223,7 @@ private: uint getChar(); uint getToken(); + bool getMacroArgs(); bool match(uint t); bool matchString(QString *s); bool matchEncoding(bool *utf8); @@ -416,6 +419,34 @@ uint CppParser::getChar() } } +// This ignores commas, parens and comments. +// IOW, it understands only a single, simple argument. +bool CppParser::getMacroArgs() +{ + // Failing this assertion would mean losing the preallocated buffer. + Q_ASSERT(yyWord.isDetached()); + yyWord.resize(0); + + while (isspace(yyCh)) + yyCh = getChar(); + if (yyCh != '(') + return false; + do { + yyCh = getChar(); + } while (isspace(yyCh)); + ushort *ptr = (ushort *)yyWord.unicode(); + while (yyCh != ')') { + if (yyCh == EOF) + return false; + *ptr++ = yyCh; + yyCh = getChar(); + } + yyCh = getChar(); + for (; ptr != (ushort *)yyWord.unicode() && isspace(*(ptr - 1)); --ptr) ; + yyWord.resize(ptr - (ushort *)yyWord.unicode()); + return true; +} + STRING(Q_OBJECT); STRING(Q_DECLARE_TR_FUNCTIONS); STRING(QT_TR_NOOP); @@ -1666,10 +1697,11 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) qPrintable(yyFileName), yyLineNo); break; } - while (!findNamespace(functionContext, idx)->classDef->hasTrFunctions) { + Namespace *fctx; + while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { if (idx == 1) { context = stringifyNamespace(functionContext); - Namespace *fctx = findNamespace(functionContext)->classDef; + fctx = findNamespace(functionContext)->classDef; if (!fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, @@ -1680,12 +1712,17 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } --idx; } - context.clear(); - for (int i = 1;;) { - context += functionContext.at(i).value(); - if (++i == idx) - break; - context += strColons; + if (fctx->trQualification.isEmpty()) { + context.clear(); + for (int i = 1;;) { + context += functionContext.at(i).value(); + if (++i == idx) + break; + context += strColons; + } + fctx->trQualification = context; + } else { + context = fctx->trQualification; } } else { context = (stringListifyNamespace(functionContext) @@ -1705,8 +1742,13 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) NamespaceList nsl; QStringList unresolved; if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { - context = stringifyNamespace(nsl); Namespace *fctx = findNamespace(nsl)->classDef; + if (fctx->trQualification.isEmpty()) { + context = stringifyNamespace(nsl); + fctx->trQualification = context; + } else { + context = fctx->trQualification; + } if (!fctx->hasTrFunctions && !fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, @@ -1806,6 +1848,14 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) extra.clear(); break; case Tok_Q_DECLARE_TR_FUNCTIONS: + if (getMacroArgs()) { + Namespace *ns = modifyNamespace(&namespaces, true); + ns->hasTrFunctions = true; + ns->trQualification = yyWord; + ns->trQualification.detach(); + } + yyTok = getToken(); + break; case Tok_Q_OBJECT: modifyNamespace(&namespaces, true)->hasTrFunctions = true; yyTok = getToken(); -- cgit v0.12 From 0040d5a582b7fb7e9719d7c04c8de272e2a1389d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Sep 2009 14:59:04 +0200 Subject: reduce peak memory consumption drop the parse results of files which are unlikely to be included (i.e., which are not headers). --- tools/linguist/lupdate/cpp.cpp | 100 ++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 44a8feb..0a710e2 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -120,6 +120,10 @@ struct Namespace { classDef(this), hasTrFunctions(false), complained(false) {} + ~Namespace() + { + qDeleteAll(children); + } QHash children; QHash aliases; @@ -159,30 +163,27 @@ private: }; struct ParseResults { - - ParseResults() - { - tor = 0; - } - int fileId; Namespace rootNamespace; - Translator *tor; QSet includes; }; typedef QHash ParseResultHash; +typedef QHash TranslatorHash; class CppFiles { public: static const ParseResults *getResults(const QString &cleanFile); static void setResults(const QString &cleanFile, ParseResults *results); + static const Translator *getTranslator(const QString &cleanFile); + static void setTranslator(const QString &cleanFile, const Translator *results); static bool isBlacklisted(const QString &cleanFile); static void setBlacklisted(const QString &cleanFile); private: static ParseResultHash &parsedFiles(); + static TranslatorHash &translatedFiles(); static QSet &blacklistedFiles(); }; @@ -192,10 +193,10 @@ public: CppParser(ParseResults *results = 0); void setInput(const QString &in); void setInput(QTextStream &ts, const QString &fileName); - void setTranslator(Translator *tor) { results->tor = tor; } + void setTranslator(Translator *_tor) { tor = _tor; } void parse(const QString &initialContext, ConversionData &cd, QSet &inclusions); void parseInternal(ConversionData &cd, QSet &inclusions); - ParseResults *getResults() const { return results; } + const ParseResults *recordResults(bool isHeader); void deleteResults() { delete results; } struct SavedState { @@ -311,6 +312,7 @@ private: QString prospectiveContext; QString pendingContext; ParseResults *results; + Translator *tor; bool directInclude; SavedState savedState; @@ -320,6 +322,7 @@ private: CppParser::CppParser(ParseResults *_results) { + tor = 0; if (_results) { results = _results; directInclude = true; @@ -1166,6 +1169,13 @@ ParseResultHash &CppFiles::parsedFiles() return parsed; } +TranslatorHash &CppFiles::translatedFiles() +{ + static TranslatorHash tors; + + return tors; +} + QSet &CppFiles::blacklistedFiles() { static QSet blacklisted; @@ -1184,6 +1194,16 @@ void CppFiles::setResults(const QString &cleanFile, ParseResults *results) parsedFiles().insert(cleanFile, results); } +const Translator *CppFiles::getTranslator(const QString &cleanFile) +{ + return translatedFiles().value(cleanFile); +} + +void CppFiles::setTranslator(const QString &cleanFile, const Translator *tor) +{ + translatedFiles().insert(cleanFile, tor); +} + bool CppFiles::isBlacklisted(const QString &cleanFile) { return blacklistedFiles().contains(cleanFile); @@ -1194,6 +1214,12 @@ void CppFiles::setBlacklisted(const QString &cleanFile) blacklistedFiles().insert(cleanFile); } +static bool isHeader(const QString &name) +{ + QString fileExt = QFileInfo(name).suffix(); + return fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive); +} + void CppParser::processInclude(const QString &file, ConversionData &cd, QSet &inclusions) { @@ -1212,17 +1238,15 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, bool isIndirect = false; if (namespaces.count() == 1 && functionContext.count() == 1 && functionContextUnresolved.isEmpty() && pendingContext.isEmpty() - && !CppFiles::isBlacklisted(cleanFile)) { - QString fileExt = QFileInfo(cleanFile).suffix(); - if (fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive)) { - - if (const ParseResults *res = CppFiles::getResults(cleanFile)) { - results->includes.insert(res); - return; - } + && !CppFiles::isBlacklisted(cleanFile) + && isHeader(cleanFile)) { - isIndirect = true; + if (const ParseResults *res = CppFiles::getResults(cleanFile)) { + results->includes.insert(res); + return; } + + isIndirect = true; } QFile f(cleanFile); @@ -1247,8 +1271,7 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, } parser.setInput(ts, cleanFile); parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(cleanFile, parser.results); - results->includes.insert(parser.results); + results->includes.insert(parser.recordResults(true)); } else { CppParser parser(results); parser.namespaces = namespaces; @@ -1434,14 +1457,14 @@ void CppParser::recordMessage( msg.setExtras(extra); if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit()) msg.setUtf8(true); - results->tor->append(msg); + tor->append(msg); } void CppParser::parse(const QString &initialContext, ConversionData &cd, QSet &inclusions) { - if (results->tor) - yyCodecIsUtf8 = (results->tor->codecName() == "UTF-8"); + if (tor) + yyCodecIsUtf8 = (tor->codecName() == "UTF-8"); namespaces << HashString(); functionContext = namespaces; @@ -1657,7 +1680,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) break; case Tok_tr: case Tok_trUtf8: - if (!results->tor) + if (!tor) goto case_default; if (!sourcetext.isEmpty()) qWarning("%s:%d: //%% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n", @@ -1770,7 +1793,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) break; case Tok_translateUtf8: case Tok_translate: - if (!results->tor) + if (!tor) goto case_default; if (!sourcetext.isEmpty()) qWarning("%s:%d: //%% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n", @@ -1825,7 +1848,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) extra.clear(); break; case Tok_trid: - if (!results->tor) + if (!tor) goto case_default; if (sourcetext.isEmpty()) { yyTok = getToken(); @@ -1871,7 +1894,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) } break; case Tok_Comment: - if (!results->tor) + if (!tor) goto case_default; if (yyWord.startsWith(QLatin1Char(':'))) { yyWord.remove(0, 1); @@ -1944,7 +1967,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) recordMessage(yyLineNo, context, QString(), comment, extracomment, QString(), TranslatorMessage::ExtraData(), false, false); extracomment.clear(); - results->tor->setExtras(extra); + tor->setExtras(extra); extra.clear(); } } @@ -2029,6 +2052,23 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) qPrintable(yyFileName), yyParenLineNo); } +const ParseResults *CppParser::recordResults(bool isHeader) +{ + if (tor) { + if (tor->messageCount()) + CppFiles::setTranslator(yyFileName, tor); + else + delete tor; + } + if (isHeader) { + CppFiles::setResults(yyFileName, results); + return results; + } else { + delete results; + return 0; + } +} + /* Fetches tr() calls in C++ code in UI files (inside "" tag). This mechanism is obsolete. @@ -2073,12 +2113,12 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat parser.setTranslator(tor); QSet inclusions; parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(filename, parser.getResults()); + parser.recordResults(isHeader(filename)); } foreach (const QString &filename, filenames) if (!CppFiles::isBlacklisted(filename)) - if (Translator *tor = CppFiles::getResults(filename)->tor) + if (const Translator *tor = CppFiles::getTranslator(filename)) foreach (const TranslatorMessage &msg, tor->messages()) translator.extend(msg); } -- cgit v0.12 From b9fd3e2836553dbe9c48c5d8784155b02a5699a2 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Sep 2009 15:17:32 +0200 Subject: detect and eliminate forwarding headers this will save quite some hash lookups (even if in empty hashes) and make the VisitRecorder bitmap smaller. --- tools/linguist/lupdate/cpp.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 0a710e2..ed41edb 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -175,7 +175,7 @@ class CppFiles { public: static const ParseResults *getResults(const QString &cleanFile); - static void setResults(const QString &cleanFile, ParseResults *results); + static void setResults(const QString &cleanFile, const ParseResults *results); static const Translator *getTranslator(const QString &cleanFile); static void setTranslator(const QString &cleanFile, const Translator *results); static bool isBlacklisted(const QString &cleanFile); @@ -1188,9 +1188,8 @@ const ParseResults *CppFiles::getResults(const QString &cleanFile) return parsedFiles().value(cleanFile); } -void CppFiles::setResults(const QString &cleanFile, ParseResults *results) +void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) { - results->fileId = nextFileId++; parsedFiles().insert(cleanFile, results); } @@ -2055,14 +2054,28 @@ void CppParser::parseInternal(ConversionData &cd, QSet &inclusions) const ParseResults *CppParser::recordResults(bool isHeader) { if (tor) { - if (tor->messageCount()) + if (tor->messageCount()) { CppFiles::setTranslator(yyFileName, tor); - else + } else { delete tor; + tor = 0; + } } if (isHeader) { - CppFiles::setResults(yyFileName, results); - return results; + const ParseResults *pr; + if (!tor && results->includes.count() == 1 + && results->rootNamespace.children.isEmpty() + && results->rootNamespace.aliases.isEmpty() + && results->rootNamespace.usings.isEmpty()) { + // This is a forwarding header. Slash it. + pr = *results->includes.begin(); + delete results; + } else { + results->fileId = nextFileId++; + pr = results; + } + CppFiles::setResults(yyFileName, pr); + return pr; } else { delete results; return 0; -- cgit v0.12 From 9d552fbf54a25b4bab7fff8a150ab0d03d524983 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 23 Sep 2009 15:30:24 +0200 Subject: Small change in the API of animations We're not taking a parameter in updateCurrentTime any more because that parameter was the total currenttime. So it was taking into account the currenttime and the currentloop at once. This was inconsistent Reviewed-by: Leo --- examples/animation/easing/animation.h | 4 ++-- src/corelib/animation/qabstractanimation.cpp | 18 +++++++++--------- src/corelib/animation/qabstractanimation.h | 2 +- src/corelib/animation/qparallelanimationgroup.cpp | 2 +- src/corelib/animation/qparallelanimationgroup.h | 2 +- src/corelib/animation/qpauseanimation.cpp | 3 +-- src/corelib/animation/qpauseanimation.h | 2 +- src/corelib/animation/qsequentialanimationgroup.cpp | 16 ++++++---------- src/corelib/animation/qsequentialanimationgroup.h | 2 +- src/corelib/animation/qsequentialanimationgroup_p.h | 2 +- src/corelib/animation/qvariantanimation.cpp | 3 +-- src/corelib/animation/qvariantanimation.h | 2 +- .../tst_qsequentialanimationgroup.cpp | 6 +++--- tests/benchmarks/qanimation/rectanimation.cpp | 4 ++-- tests/benchmarks/qanimation/rectanimation.h | 2 +- 15 files changed, 32 insertions(+), 38 deletions(-) diff --git a/examples/animation/easing/animation.h b/examples/animation/easing/animation.h index 45a7b17..78fdc14 100644 --- a/examples/animation/easing/animation.h +++ b/examples/animation/easing/animation.h @@ -68,7 +68,7 @@ public: m_path = QPainterPath(); } - void updateCurrentTime(int msecs) + void updateCurrentTime() { if (m_pathType == CirclePath) { if (m_path.isEmpty()) { @@ -90,7 +90,7 @@ public: updateCurrentValue(pt); emit valueChanged(pt); } else { - QPropertyAnimation::updateCurrentTime(msecs); + QPropertyAnimation::updateCurrentTime(); } } diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 6306882..9027be0 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -81,12 +81,12 @@ QAbstractAnimation provides pure virtual functions used by subclasses to track the progress of the animation: duration() and updateCurrentTime(). The duration() function lets you report a - duration for the animation (as discussed above). The current time - is delivered by the animation framework through calls to - updateCurrentTime(). By reimplementing this function, you can - track the animation progress. Note that neither the interval - between calls nor the number of calls to this function are - defined; though, it will normally be 60 updates per second. + duration for the animation (as discussed above). The animation + framework calls updateCurrentTime() when current time has changed. + By reimplementing this function, you can track the animation + progress. Note that neither the interval between calls nor the + number of calls to this function are defined; though, it will + normally be 60 updates per second. By reimplementing updateState(), you can track the animation's state changes, which is particularly useful for animations that @@ -604,7 +604,7 @@ void QAbstractAnimation::setCurrentTime(int msecs) } } - updateCurrentTime(msecs); + updateCurrentTime(); if (d->currentLoop != oldLoop) emit currentLoopChanged(d->currentLoop); @@ -705,10 +705,10 @@ bool QAbstractAnimation::event(QEvent *event) } /*! - \fn virtual void QAbstractAnimation::updateCurrentTime(int msecs) = 0; + \fn virtual void QAbstractAnimation::updateCurrentTime() = 0; This pure virtual function is called every time the animation's current - time changes. The \a msecs argument is the current time. + time changes. \sa updateState() */ diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h index dc0af19..516f5e9 100644 --- a/src/corelib/animation/qabstractanimation.h +++ b/src/corelib/animation/qabstractanimation.h @@ -119,7 +119,7 @@ protected: QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = 0); bool event(QEvent *event); - virtual void updateCurrentTime(int msecs) = 0; + virtual void updateCurrentTime() = 0; virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); virtual void updateDirection(QAbstractAnimation::Direction direction); diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp index 349090b..82d5224 100644 --- a/src/corelib/animation/qparallelanimationgroup.cpp +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -125,7 +125,7 @@ int QParallelAnimationGroup::duration() const /*! \reimp */ -void QParallelAnimationGroup::updateCurrentTime(int) +void QParallelAnimationGroup::updateCurrentTime() { Q_D(QParallelAnimationGroup); if (d->animations.isEmpty()) diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h index f013bc7..6afe4a7 100644 --- a/src/corelib/animation/qparallelanimationgroup.h +++ b/src/corelib/animation/qparallelanimationgroup.h @@ -67,7 +67,7 @@ protected: QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, QObject *parent); bool event(QEvent *event); - void updateCurrentTime(int msecs); + void updateCurrentTime(); void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); void updateDirection(QAbstractAnimation::Direction direction); diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp index 8bfed08..c382b19 100644 --- a/src/corelib/animation/qpauseanimation.cpp +++ b/src/corelib/animation/qpauseanimation.cpp @@ -141,9 +141,8 @@ bool QPauseAnimation::event(QEvent *e) /*! \reimp */ -void QPauseAnimation::updateCurrentTime(int msecs) +void QPauseAnimation::updateCurrentTime() { - Q_UNUSED(msecs); } diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h index 05eb3b3..caac9e9 100644 --- a/src/corelib/animation/qpauseanimation.h +++ b/src/corelib/animation/qpauseanimation.h @@ -68,7 +68,7 @@ public: protected: bool event(QEvent *e); - void updateCurrentTime(int msecs); + void updateCurrentTime(); private: Q_DISABLE_COPY(QPauseAnimation) diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 53fc4f3..9ad433f 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -112,17 +112,13 @@ int QSequentialAnimationGroupPrivate::animationActualTotalDuration(int index) co return ret; } -QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForTime(int msecs) const +QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForCurrentTime() const { - Q_Q(const QSequentialAnimationGroup); Q_ASSERT(!animations.isEmpty()); AnimationIndex ret; int duration = 0; - // in case duration is -1, currentLoop will always be 0 - ret.timeOffset = currentLoop * q->duration(); - for (int i = 0; i < animations.size(); ++i) { duration = animationActualTotalDuration(i); @@ -131,8 +127,8 @@ QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivat // 2. it ends after msecs // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation) // 4. it ends exactly in msecs and the direction is backwards - if (duration == -1 || msecs < (ret.timeOffset + duration) - || (msecs == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) { + if (duration == -1 || currentTime < (ret.timeOffset + duration) + || (currentTime == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) { ret.index = i; return ret; } @@ -338,13 +334,13 @@ int QSequentialAnimationGroup::duration() const /*! \reimp */ -void QSequentialAnimationGroup::updateCurrentTime(int msecs) +void QSequentialAnimationGroup::updateCurrentTime() { Q_D(QSequentialAnimationGroup); if (!d->currentAnimation) return; - const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForTime(msecs); + const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForCurrentTime(); // remove unneeded animations from actualDuration list while (newAnimationIndex.index < d->actualDuration.size()) @@ -363,7 +359,7 @@ void QSequentialAnimationGroup::updateCurrentTime(int msecs) d->setCurrentAnimation(newAnimationIndex.index); - const int newCurrentTime = msecs - newAnimationIndex.timeOffset; + const int newCurrentTime = d->currentTime - newAnimationIndex.timeOffset; if (d->currentAnimation) { d->currentAnimation->setCurrentTime(newCurrentTime); diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h index e17e103..1c9e4cc 100644 --- a/src/corelib/animation/qsequentialanimationgroup.h +++ b/src/corelib/animation/qsequentialanimationgroup.h @@ -77,7 +77,7 @@ protected: QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, QObject *parent); bool event(QEvent *event); - void updateCurrentTime(int msecs); + void updateCurrentTime(); void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); void updateDirection(QAbstractAnimation::Direction direction); diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h index 2e65cc0..ab41d35 100644 --- a/src/corelib/animation/qsequentialanimationgroup_p.h +++ b/src/corelib/animation/qsequentialanimationgroup_p.h @@ -79,7 +79,7 @@ public: }; int animationActualTotalDuration(int index) const; - AnimationIndex indexForTime(int msecs) const; + AnimationIndex indexForCurrentTime() const; void setCurrentAnimation(int index, bool intermediate = false); void activateCurrentAnimation(bool intermediate = false); diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index c831a34..ae8bf2f 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -656,9 +656,8 @@ QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &t /*! \reimp */ -void QVariantAnimation::updateCurrentTime(int msecs) +void QVariantAnimation::updateCurrentTime() { - Q_UNUSED(msecs); d_func()->recalculateCurrentInterval(); } diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h index c803150..98c1aec 100644 --- a/src/corelib/animation/qvariantanimation.h +++ b/src/corelib/animation/qvariantanimation.h @@ -102,7 +102,7 @@ protected: QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent = 0); bool event(QEvent *event); - void updateCurrentTime(int msecs); + void updateCurrentTime(); void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); virtual void updateCurrentValue(const QVariant &value) = 0; diff --git a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp index 209e68b..b14d6f8 100644 --- a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp +++ b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp @@ -169,10 +169,10 @@ public: int duration() const { return -1; /* not time driven */ } protected: - void updateCurrentTime(int msecs) + void updateCurrentTime() { - QPropertyAnimation::updateCurrentTime(msecs); - if (msecs >= QPropertyAnimation::duration()) + QPropertyAnimation::updateCurrentTime(); + if (currentTime() >= QPropertyAnimation::duration()) stop(); } }; diff --git a/tests/benchmarks/qanimation/rectanimation.cpp b/tests/benchmarks/qanimation/rectanimation.cpp index e5f2f57..5522847 100644 --- a/tests/benchmarks/qanimation/rectanimation.cpp +++ b/tests/benchmarks/qanimation/rectanimation.cpp @@ -73,9 +73,9 @@ int RectAnimation::duration() const } -void RectAnimation::updateCurrentTime(int msecs) +void RectAnimation::updateCurrentTime() { - qreal progress = m_easing.valueForProgress( qreal(msecs) / qreal(m_dura) ); + qreal progress = m_easing.valueForProgress( currentTime() / qreal(m_dura) ); QRect now; now.setCoords(interpolateInteger(m_start.left(), m_end.left(), progress), interpolateInteger(m_start.top(), m_end.top(), progress), diff --git a/tests/benchmarks/qanimation/rectanimation.h b/tests/benchmarks/qanimation/rectanimation.h index 84ec97d..995becb 100644 --- a/tests/benchmarks/qanimation/rectanimation.h +++ b/tests/benchmarks/qanimation/rectanimation.h @@ -58,7 +58,7 @@ public: void setDuration(int d); int duration() const; - virtual void updateCurrentTime(int msecs); + virtual void updateCurrentTime(); virtual void updateState(QAbstractAnimation::State state); private: -- cgit v0.12 From aed412fd14e39a356a886c5a472ceade3da56d13 Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Wed, 23 Sep 2009 15:50:49 +0200 Subject: Avoid calling ensureContext() in setGeometry. We can delay calling ensureContext() since it will happen when painting begins anyway. There is a chance that we can get to this function when a window is being hidden and if this is the first thing that happens in the application, there is no need to call ensureContext() yet. Reviewed-by: Rhys Weatherley --- src/openvg/qwindowsurface_vg.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openvg/qwindowsurface_vg.cpp b/src/openvg/qwindowsurface_vg.cpp index 1997ee8..6cc2e27 100644 --- a/src/openvg/qwindowsurface_vg.cpp +++ b/src/openvg/qwindowsurface_vg.cpp @@ -85,7 +85,6 @@ void QVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoin void QVGWindowSurface::setGeometry(const QRect &rect) { QWindowSurface::setGeometry(rect); - d_ptr->ensureContext(window()); } bool QVGWindowSurface::scroll(const QRegion &area, int dx, int dy) -- cgit v0.12