From cb2a108d79b09ec6ea91106e7f33826dceac4a42 Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Wed, 27 Oct 2010 12:05:52 +1000 Subject: Fix QTBUG-14132 oracle (xe) stored procedures with bind variables get errors Strange Oracle bug: some Oracle servers crash the server process with non-zero error handle (mostly for 10g). So pass null error handle pointer to OCIAttrSet when setting OCI_ATTR_CHARSET_FORM to bypass this bug. Change-Id: Ifcf65994a22783e69a89bebe1adb882cdf36bdbb Task-number:QTBUG-14132 Reviewed-by: Michael Goddard --- src/sql/drivers/oci/qsql_oci.cpp | 106 +++++++++++++-------------------- tests/auto/qsqlquery/tst_qsqlquery.cpp | 21 +++++++ 2 files changed, 63 insertions(+), 64 deletions(-) diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index e11cf75..3f30ea5 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -93,11 +93,13 @@ enum { QOCIEncoding = 2002 }; // AL16UTF16LE enum { QOCIEncoding = 2000 }; // AL16UTF16 #endif +#ifdef OCI_ATTR_CHARSET_FORM // Always set the OCI_ATTR_CHARSET_FORM to SQLCS_NCHAR is safe // because Oracle server will deal with the implicit Conversion // Between CHAR and NCHAR. // see: http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/oci05bnd.htm#422705 static const ub1 qOraCharsetForm = SQLCS_NCHAR; +#endif #if defined (OCI_UTF16ID) static const ub2 qOraCharset = OCI_UTF16ID; @@ -117,6 +119,8 @@ static // for some reason, Sun CC can't use qOraWarning when it's declared stati void qOraWarning(const char* msg, OCIError *err); static QSqlError qMakeError(const QString& errString, QSqlError::ErrorType type, OCIError *err); + + class QOCIRowId: public QSharedData { public: @@ -164,7 +168,6 @@ struct QOCIResultPrivate int serverVersion; int prefetchRows, prefetchMem; - void setCharset(OCIBind* hbnd); void setStatementAttributes(); int bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos, const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList &tmpStorage); @@ -176,6 +179,41 @@ struct QOCIResultPrivate { return q->bindValueType(i) & QSql::Out; } inline bool isBinaryValue(int i) const { return q->bindValueType(i) & QSql::Binary; } + + void setCharset(dvoid* handle, ub4 type) const + { + int r = 0; + Q_ASSERT(handle); + +#ifdef OCI_ATTR_CHARSET_FORM + r = OCIAttrSet(handle, + type, + // this const cast is safe since OCI doesn't touch + // the charset. + const_cast(static_cast(&qOraCharsetForm)), + 0, + OCI_ATTR_CHARSET_FORM, + //Strange Oracle bug: some Oracle servers crash the server process with non-zero error handle (mostly for 10g). + //So ignore the error message here. + 0); + #ifdef QOCI_DEBUG + if (r != 0) + qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM."); + #endif +#endif + + r = OCIAttrSet(handle, + type, + // this const cast is safe since OCI doesn't touch + // the charset. + const_cast(static_cast(&qOraCharset)), + 0, + OCI_ATTR_CHARSET_ID, + err); + if (r != 0) + qOraWarning("QOCIResultPrivate::setCharsetI Couldn't set OCI_ATTR_CHARSET_ID: ", err); + + } }; void QOCIResultPrivate::setStatementAttributes() @@ -208,36 +246,6 @@ void QOCIResultPrivate::setStatementAttributes() } } -void QOCIResultPrivate::setCharset(OCIBind* hbnd) -{ - int r = 0; - - Q_ASSERT(hbnd); - - r = OCIAttrSet(hbnd, - OCI_HTYPE_BIND, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast(static_cast(&qOraCharsetForm)), - 0, - OCI_ATTR_CHARSET_FORM, - err); - if (r != 0) - qOraWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM: ", err); - - r = OCIAttrSet(hbnd, - OCI_HTYPE_BIND, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast(static_cast(&qOraCharset)), - 0, - OCI_ATTR_CHARSET_ID, - err); - if (r != 0) - qOraWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_ID: ", err); - -} - int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, int pos, const QVariant &val, dvoid *indPtr, ub2 *tmpSize, QList &tmpStorage) { @@ -325,7 +333,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in (s.length() + 1) * sizeof(QChar), SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT); if (r == OCI_SUCCESS) - setCharset(*hbnd); + setCharset(*hbnd, OCI_HTYPE_BIND); break; } } // fall through for OUT values @@ -349,7 +357,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in SQLT_STR, indPtr, 0, 0, 0, 0, OCI_DEFAULT); } if (r == OCI_SUCCESS) - setCharset(*hbnd); + setCharset(*hbnd, OCI_HTYPE_BIND); tmpStorage.append(ba); break; } // default case @@ -688,7 +696,6 @@ class QOCICols public: QOCICols(int size, QOCIResultPrivate* dp); ~QOCICols(); - void setCharset(OCIDefine* dfn); int readPiecewise(QVector &values, int index = 0); int readLOBs(QVector &values, int index = 0); int fieldFromDefine(OCIDefine* d); @@ -890,7 +897,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp) &(fieldInf[idx].ind), 0, 0, OCI_DEFAULT); if (r == 0) - setCharset(dfn); + d->setCharset(dfn, OCI_HTYPE_DEFINE); } break; default: @@ -950,35 +957,6 @@ OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env) return &lob; } -void QOCICols::setCharset(OCIDefine* dfn) -{ - int r = 0; - - Q_ASSERT(dfn); - - r = OCIAttrSet(dfn, - OCI_HTYPE_DEFINE, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast(static_cast(&qOraCharsetForm)), - 0, - OCI_ATTR_CHARSET_FORM, - d->err); - if (r != 0) - qOraWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM: ", d->err); - - r = OCIAttrSet(dfn, - OCI_HTYPE_DEFINE, - // this const cast is safe since OCI doesn't touch - // the charset. - const_cast(static_cast(&qOraCharset)), - 0, - OCI_ATTR_CHARSET_ID, - d->err); - if (r != 0) - qOraWarning("QOCICols::setCharset: Couldn't set OCI_ATTR_CHARSET_ID: ", d->err); -} - int QOCICols::readPiecewise(QVector &values, int index) { OCIDefine* dfn; diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index c7a61a5..7c93c7a 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -209,6 +209,8 @@ private slots: void QTBUG_6852(); void QTBUG_5765_data() { generic_data("QMYSQL"); } void QTBUG_5765(); + void QTBUG_14132_data() { generic_data("QOCI"); } + void QTBUG_14132(); void sqlite_constraint_data() { generic_data("QSQLITE"); } void sqlite_constraint(); @@ -2933,6 +2935,25 @@ void tst_QSqlQuery::QTBUG_551() QCOMPARE(res_outLst[2].toString(), QLatin1String("3. Value is 2")); } +void tst_QSqlQuery::QTBUG_14132() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + QSqlQuery q(db); + const QString procedureName(qTableName("procedure", __FILE__)); + QVERIFY_SQL(q, exec("CREATE OR REPLACE PROCEDURE "+ procedureName + " (outStr OUT varchar2) \n\ + is \n\ + begin \n\ + outStr := 'OUTSTRING'; \n\ + end;")); + QString outValue = "XXXXXXXXX"; + q.prepare("CALL "+procedureName+"(?)"); + q.addBindValue(outValue, QSql::Out); + QVERIFY_SQL(q, exec()); + QCOMPARE(outValue, QLatin1String("OUTSTRING")); +} + void tst_QSqlQuery::QTBUG_5251() { QFETCH( QString, dbName ); -- cgit v0.12 From c76f9f15d1c604cdf3d68d2147a4a06d227871fa Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 28 Oct 2010 09:27:24 +0200 Subject: Fix possible crash in QStaticText and QDeclarativeTextLayout The QStaticTextItem held an uncounted reference to QFontEngine. The pointer would dangle in some cases where there was no font object referencing the engine and the cache was cleaned out (e.g. when a new application font is added.) Properly count the reference, and also add reference counting to userData to make it harder to shoot yourself in the foot, since the QStaticTextItem class is now being used in different places, Task-number: QTBUG-14446 Reviewed-by: Martin Jones --- .../graphicsitems/qdeclarativetextlayout.cpp | 4 +- src/gui/painting/qpaintengine_raster.cpp | 2 +- src/gui/painting/qpainter.cpp | 4 +- src/gui/text/qstatictext.cpp | 22 ++++++++- src/gui/text/qstatictext_p.h | 54 ++++++++++++++++++---- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 24 +++++----- src/opengl/qpaintengine_opengl.cpp | 8 ++-- src/openvg/qpaintengine_vg.cpp | 2 +- 8 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp index 89a2158..635ceab 100644 --- a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp @@ -94,7 +94,7 @@ class DrawTextItemRecorder: public QPaintEngine if (!m_inertText->items.isEmpty()) { QStaticTextItem &last = m_inertText->items[m_inertText->items.count() - 1]; - if (last.fontEngine == ti.fontEngine && last.font == ti.font() && + if (last.fontEngine() == ti.fontEngine && last.font == ti.font() && (!m_dirtyPen || last.color == state->pen().color())) { needFreshCurrentItem = false; @@ -107,7 +107,7 @@ class DrawTextItemRecorder: public QPaintEngine if (needFreshCurrentItem) { QStaticTextItem currentItem; - currentItem.fontEngine = ti.fontEngine; + currentItem.setFontEngine(ti.fontEngine); currentItem.font = ti.font(); currentItem.charOffset = charOffset; currentItem.numChars = ti.num_chars; diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 8f9d8ba..d4b044b 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3300,7 +3300,7 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) ensureState(); drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, - textItem->fontEngine); + textItem->fontEngine()); } /*! diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 7fed7e4..ab9707d 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5746,7 +5746,7 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *posit QStaticTextItem staticTextItem; staticTextItem.color = state->pen.color(); staticTextItem.font = state->font; - staticTextItem.fontEngine = fontEngine; + staticTextItem.setFontEngine(fontEngine); staticTextItem.numGlyphs = glyphCount; staticTextItem.glyphs = reinterpret_cast(const_cast(glyphArray)); staticTextItem.glyphPositions = positions.data(); @@ -5938,7 +5938,7 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText d->extended->drawStaticTextItem(item); drawDecorationForGlyphs(this, item->glyphs, item->glyphPositions, - item->numGlyphs, item->fontEngine, staticText_d->font, + item->numGlyphs, item->fontEngine(), staticText_d->font, QTextCharFormat()); } if (currentColor != oldPen.color()) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 9506006..edf248a 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -445,7 +445,7 @@ namespace { const QTextItemInt &ti = static_cast(textItem); QStaticTextItem currentItem; - currentItem.fontEngine = ti.fontEngine; + currentItem.setFontEngine(ti.fontEngine); currentItem.font = ti.font(); currentItem.charOffset = m_chars.size(); currentItem.numChars = ti.num_chars; @@ -713,4 +713,24 @@ void QStaticTextPrivate::init() needsRelayout = false; } +QStaticTextItem::~QStaticTextItem() +{ + if (m_userData != 0 && !m_userData->ref.deref()) + delete m_userData; + if (!m_fontEngine->ref.deref()) + delete m_fontEngine; +} + +void QStaticTextItem::setFontEngine(QFontEngine *fe) +{ + if (m_fontEngine != 0) { + if (!m_fontEngine->ref.deref()) + delete m_fontEngine; + } + + m_fontEngine = fe; + if (m_fontEngine != 0) + m_fontEngine->ref.ref(); +} + QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index cb60626..87ef0d5 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -68,27 +68,60 @@ public: OpenGLUserData }; - QStaticTextUserData(Type t) : type(t) {} + QStaticTextUserData(Type t) : type(t) { ref = 0; } virtual ~QStaticTextUserData() {} + QAtomicInt ref; Type type; }; class Q_GUI_EXPORT QStaticTextItem { public: - QStaticTextItem() : chars(0), numChars(0), fontEngine(0), userData(0), - useBackendOptimizations(false), userDataNeedsUpdate(0) {} - ~QStaticTextItem() { delete userData; } + QStaticTextItem() : chars(0), numChars(0), useBackendOptimizations(false), + userDataNeedsUpdate(0), m_fontEngine(0), m_userData(0) {} + + QStaticTextItem(const QStaticTextItem &other) + { + operator=(other); + } + + void operator=(const QStaticTextItem &other) + { + glyphPositions = other.glyphPositions; + glyphs = other.glyphs; + chars = other.chars; + numGlyphs = other.numGlyphs; + numChars = other.numChars; + font = other.font; + color = other.color; + useBackendOptimizations = other.useBackendOptimizations; + userDataNeedsUpdate = other.userDataNeedsUpdate; + + m_fontEngine = 0; + m_userData = 0; + setUserData(other.userData()); + setFontEngine(other.fontEngine()); + } + + ~QStaticTextItem(); void setUserData(QStaticTextUserData *newUserData) { - if (userData == newUserData) + if (m_userData == newUserData) return; - delete userData; - userData = newUserData; + if (m_userData != 0 && !m_userData->ref.deref()) + delete m_userData; + + m_userData = newUserData; + if (m_userData != 0) + m_userData->ref.ref(); } + QStaticTextUserData *userData() const { return m_userData; } + + void setFontEngine(QFontEngine *fe); + QFontEngine *fontEngine() const { return m_fontEngine; } union { QFixedPoint *glyphPositions; // 8 bytes per glyph @@ -108,14 +141,17 @@ public: // 12 bytes for pointers int numGlyphs; // 4 bytes per item int numChars; // 4 bytes per item - QFontEngine *fontEngine; // 4 bytes per item QFont font; // 8 bytes per item QColor color; // 10 bytes per item - QStaticTextUserData *userData; // 8 bytes per item char useBackendOptimizations : 1; // 1 byte per item char userDataNeedsUpdate : 1; // // ================ // 51 bytes per item + +private: // Needs special handling in setters, so private to avoid abuse + QFontEngine *m_fontEngine; // 4 bytes per item + QStaticTextUserData *m_userData; // 8 bytes per item + }; class QStaticText; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 84c7fed..1dcb773 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1350,8 +1350,8 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) ensureActive(); - QFontEngineGlyphCache::Type glyphType = textItem->fontEngine->glyphFormat >= 0 - ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat) + QFontEngineGlyphCache::Type glyphType = textItem->fontEngine()->glyphFormat >= 0 + ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) : d->glyphCacheType; if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { if (d->device->alphaRequested() || state()->matrix.type() > QTransform::TxTranslate @@ -1430,7 +1430,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem { QStaticTextItem staticTextItem; staticTextItem.chars = const_cast(ti.chars); - staticTextItem.fontEngine = ti.fontEngine; + staticTextItem.setFontEngine(ti.fontEngine); staticTextItem.glyphs = glyphs.data(); staticTextItem.numChars = ti.num_chars; staticTextItem.numGlyphs = glyphs.size(); @@ -1475,18 +1475,18 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QOpenGL2PaintEngineState *s = q->state(); QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform()); + (QGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(ctx, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); - staticTextItem->fontEngine->setGlyphCache(ctx, cache); + staticTextItem->fontEngine()->setGlyphCache(ctx, cache); } bool recreateVertexArrays = false; if (staticTextItem->userDataNeedsUpdate) recreateVertexArrays = true; - else if (staticTextItem->userData == 0) + else if (staticTextItem->userData() == 0) recreateVertexArrays = true; - else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) + else if (staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) recreateVertexArrays = true; // We only need to update the cache with new glyphs if we are actually going to recreate the vertex arrays. @@ -1494,8 +1494,8 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp // cache so this text is performed before we test if the cache size has changed. if (recreateVertexArrays) { cache->setPaintEnginePrivate(this); - cache->populate(staticTextItem->fontEngine, staticTextItem->numGlyphs, staticTextItem->glyphs, - staticTextItem->glyphPositions); + cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, + staticTextItem->glyphs, staticTextItem->glyphPositions); } if (cache->width() == 0 || cache->height() == 0) @@ -1515,14 +1515,14 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp if (staticTextItem->useBackendOptimizations) { QOpenGLStaticTextUserData *userData = 0; - if (staticTextItem->userData == 0 - || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) { + if (staticTextItem->userData() == 0 + || staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) { userData = new QOpenGLStaticTextUserData(); staticTextItem->setUserData(userData); } else { - userData = static_cast(staticTextItem->userData); + userData = static_cast(staticTextItem->userData()); } // Use cache if backend optimizations is turned on diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 74b6b9a..a04d930 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -4918,7 +4918,7 @@ void QOpenGLPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) d->flushDrawQueue(); // make sure the glyphs we want to draw are in the cache - qt_glyph_cache()->cacheGlyphs(d->device->context(), textItem->fontEngine, textItem->glyphs, + qt_glyph_cache()->cacheGlyphs(d->device->context(), textItem->fontEngine(), textItem->glyphs, textItem->numGlyphs); d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops @@ -4941,13 +4941,13 @@ void QOpenGLPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bool antialias = !(textItem->fontEngine->fontDef.styleStrategy & QFont::NoAntialias) + bool antialias = !(textItem->fontEngine()->fontDef.styleStrategy & QFont::NoAntialias) && (d->matrix.type() > QTransform::TxTranslate); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, antialias ? GL_LINEAR : GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, antialias ? GL_LINEAR : GL_NEAREST); for (int i=0; i< textItem->numGlyphs; ++i) { - QGLGlyphCoord *g = qt_glyph_cache()->lookup(textItem->fontEngine, textItem->glyphs[i]); + QGLGlyphCoord *g = qt_glyph_cache()->lookup(textItem->fontEngine(), textItem->glyphs[i]); // we don't cache glyphs with no width/height if (!g) @@ -5003,7 +5003,7 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte { QStaticTextItem staticTextItem; staticTextItem.chars = const_cast(ti.chars); - staticTextItem.fontEngine = ti.fontEngine; + staticTextItem.setFontEngine(ti.fontEngine); staticTextItem.glyphs = glyphs.data(); staticTextItem.numChars = ti.num_chars; staticTextItem.numGlyphs = glyphs.size(); diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index ce9d11a..f8788b0 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -3407,7 +3407,7 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) void QVGPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) { - drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->font, textItem->fontEngine, + drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->font, textItem->fontEngine(), QPointF(0, 0), textItem->glyphPositions); } -- cgit v0.12 From c4d715260bd0ed5f3b6d38a63a2659715342c90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 29 Oct 2010 13:37:43 +0200 Subject: Prevented threading related crash in OpenGL module. If the last shallow copy of a QImage which is cached in the QGLTextureCache is destroyed in a thread at the same time as the QGLContext which the texture was initialized in is active in a different thread, the QImage thread incorrectly tries to make the context active in two threads at once. To prevent this from happening it's best to always do the texture clean-up in the main thread. Task-number: QT-4238 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/opengl/qgl.cpp | 7 ++- src/opengl/qgl_p.h | 68 +++++++++++++++++--------- tests/auto/qgl/tst_qgl.cpp | 118 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 24 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index dbd295f..84cfa97 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -127,7 +127,12 @@ Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance) Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy) QGLSignalProxy *QGLSignalProxy::instance() { - return theSignalProxy(); + QGLSignalProxy *proxy = theSignalProxy(); + if (proxy && proxy->thread() != qApp->thread()) { + if (proxy->thread() == QThread::currentThread()) + proxy->moveToThread(qApp->thread()); + } + return proxy; } diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index f86c77f..18b2765 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -434,20 +434,6 @@ public: static void setCurrentContext(QGLContext *context); }; -// ### make QGLContext a QObject in 5.0 and remove the proxy stuff -class Q_OPENGL_EXPORT QGLSignalProxy : public QObject -{ - Q_OBJECT -public: - QGLSignalProxy() : QObject() {} - void emitAboutToDestroyContext(const QGLContext *context) { - emit aboutToDestroyContext(context); - } - static QGLSignalProxy *instance(); -Q_SIGNALS: - void aboutToDestroyContext(const QGLContext *context); -}; - Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions) // Temporarily make a context current if not already current or @@ -490,6 +476,48 @@ private: QGLContext *m_ctx; }; +// ### make QGLContext a QObject in 5.0 and remove the proxy stuff +class Q_OPENGL_EXPORT QGLSignalProxy : public QObject +{ + Q_OBJECT +public: + QGLSignalProxy() : QObject() { + qRegisterMetaType("GLuint"); + connect(this, SIGNAL(freeTexture(QGLContext *, QPixmapData *, GLuint)), + this, SLOT(freeTexture_slot(QGLContext *, QPixmapData *, GLuint))); + } + void emitAboutToDestroyContext(const QGLContext *context) { + emit aboutToDestroyContext(context); + } + void emitFreeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id) { + emit freeTexture(context, boundPixmap, id); + } + static QGLSignalProxy *instance(); +Q_SIGNALS: + void aboutToDestroyContext(const QGLContext *context); + void freeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id); + +private slots: + void freeTexture_slot(QGLContext *context, QPixmapData *boundPixmap, GLuint id) { +#if defined(Q_WS_X11) + if (boundPixmap) { + QGLContext *oldContext = const_cast(QGLContext::currentContext()); + context->makeCurrent(); + // Although glXReleaseTexImage is a glX call, it must be called while there + // is a current context - the context the pixmap was bound to a texture in. + // Otherwise the release doesn't do anything and you get BadDrawable errors + // when you come to delete the context. + QGLContextPrivate::unbindPixmapFromTexture(boundPixmap); + glDeleteTextures(1, &id); + oldContext->makeCurrent(); + return; + } +#endif + QGLShareContextScope scope(context); + glDeleteTextures(1, &id); + } +}; + class QGLTexture { public: QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D, @@ -506,16 +534,10 @@ public: ~QGLTexture() { if (options & QGLContext::MemoryManagedBindOption) { Q_ASSERT(context); - QGLShareContextScope scope(context); -#if defined(Q_WS_X11) - // Although glXReleaseTexImage is a glX call, it must be called while there - // is a current context - the context the pixmap was bound to a texture in. - // Otherwise the release doesn't do anything and you get BadDrawable errors - // when you come to delete the context. - if (boundPixmap) - QGLContextPrivate::unbindPixmapFromTexture(boundPixmap); +#if !defined(Q_WS_X11) + QPixmapData *boundPixmap = 0; #endif - glDeleteTextures(1, &id); + QGLSignalProxy::instance()->emitFreeTexture(context, boundPixmap, id); } } diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp index e411508..4220b45 100644 --- a/tests/auto/qgl/tst_qgl.cpp +++ b/tests/auto/qgl/tst_qgl.cpp @@ -96,6 +96,7 @@ private slots: void shareRegister(); void qglContextDefaultBindTexture(); void textureCleanup(); + void threadImages(); }; tst_QGL::tst_QGL() @@ -2253,6 +2254,123 @@ void tst_QGL::textureCleanup() #endif } +namespace ThreadImages { + +class Producer : public QObject +{ + Q_OBJECT +public: + Producer() + { + startTimer(20); + + QThread *thread = new QThread; + thread->start(); + + connect(this, SIGNAL(destroyed()), thread, SLOT(quit())); + + moveToThread(thread); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + } + +signals: + void imageReady(const QImage &image); + +protected: + void timerEvent(QTimerEvent *) + { + QImage image(256, 256, QImage::Format_RGB32); + QLinearGradient g(0, 0, 0, 256); + g.setColorAt(0, QColor(255, 180, 180)); + g.setColorAt(1, Qt::white); + g.setSpread(QGradient::ReflectSpread); + + QBrush brush(g); + brush.setTransform(QTransform::fromTranslate(0, delta)); + delta += 10; + + QPainter p(&image); + p.fillRect(image.rect(), brush); + + if (images.size() > 10) + images.removeFirst(); + + images.append(image); + + emit imageReady(image); + } + +private: + QList images; + int delta; +}; + + +class DisplayWidget : public QGLWidget +{ + Q_OBJECT +public: + DisplayWidget(QWidget *parent) : QGLWidget(parent) {} + void paintEvent(QPaintEvent *) + { + QPainter p(this); + p.drawImage(rect(), m_image); + } + +public slots: + void setImage(const QImage &image) + { + m_image = image; + update(); + } + +private: + QImage m_image; +}; + +class Widget : public QWidget +{ + Q_OBJECT +public: + Widget() + : iterations(0) + , display(0) + { + startTimer(400); + } + + int iterations; + +protected: + void timerEvent(QTimerEvent *) + { + ++iterations; + + delete display; + display = new DisplayWidget(this); + connect(&producer, SIGNAL(imageReady(const QImage &)), display, SLOT(setImage(const QImage &))); + + display->setGeometry(rect()); + display->show(); + } + +private: + Producer producer; + DisplayWidget *display; +}; + +} + +void tst_QGL::threadImages() +{ + ThreadImages::Widget *widget = new ThreadImages::Widget; + widget->show(); + + while (widget->iterations <= 5) { + qApp->processEvents(); + } +} + class tst_QGLDummy : public QObject { Q_OBJECT -- cgit v0.12 From fb94cee1a10c7bfb8e73dd0a094ae71fe96bf3e7 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 29 Oct 2010 14:06:28 +0200 Subject: Fix gcc bug in qReallocAligned the line faked.pptr[-1] = real.ptr; was ignored by the GCC 4.5. (optimized out) Workaround by using proper reinterpret_cast casting instead of union casting. Fixes crash in tst_Collections::alignment The crash would occurs for any use of qReallocAligned with alignement > sizeof(void*) (fortunately this is not often called) Reviewed-by: thiago --- src/corelib/global/qmalloc.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/corelib/global/qmalloc.cpp b/src/corelib/global/qmalloc.cpp index 090998c..028a0a5 100644 --- a/src/corelib/global/qmalloc.cpp +++ b/src/corelib/global/qmalloc.cpp @@ -90,8 +90,6 @@ void *qReallocAligned(void *oldptr, size_t newsize, size_t oldsize, size_t align return newptr + 1; } - union { void *ptr; void **pptr; quintptr n; } real, faked; - // qMalloc returns pointers aligned at least at sizeof(size_t) boundaries // but usually more (8- or 16-byte boundaries). // So we overallocate by alignment-sizeof(size_t) bytes, so we're guaranteed to find a @@ -100,19 +98,21 @@ void *qReallocAligned(void *oldptr, size_t newsize, size_t oldsize, size_t align // However, we need to store the actual pointer, so we need to allocate actually size + // alignment anyway. - real.ptr = qRealloc(actualptr, newsize + alignment); - if (!real.ptr) + void *real = qRealloc(actualptr, newsize + alignment); + if (!real) return 0; - faked.n = real.n + alignment; - faked.n &= ~(alignment - 1); + quintptr faked = reinterpret_cast(real) + alignment; + faked &= ~(alignment - 1); + + void **faked_ptr = reinterpret_cast(faked); // now save the value of the real pointer at faked-sizeof(void*) // by construction, alignment > sizeof(void*) and is a power of 2, so // faked-sizeof(void*) is properly aligned for a pointer - faked.pptr[-1] = real.ptr; + faked_ptr[-1] = real; - return faked.ptr; + return faked_ptr; } void qFreeAligned(void *ptr) -- cgit v0.12 From 1fff0c3c764500c755c615f9eb8dc90433406a10 Mon Sep 17 00:00:00 2001 From: Michael Dominic K Date: Fri, 29 Oct 2010 16:01:55 +0200 Subject: 32bit => 16bit conversion has 4byte-aligned output. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge-request: 2499 Reviewed-by: Samuel Rødal --- src/plugins/graphicssystems/meego/dithering.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/plugins/graphicssystems/meego/dithering.cpp b/src/plugins/graphicssystems/meego/dithering.cpp index b50826c..c0b4b53 100644 --- a/src/plugins/graphicssystems/meego/dithering.cpp +++ b/src/plugins/graphicssystems/meego/dithering.cpp @@ -76,8 +76,13 @@ // Converts incoming RGB32 (QImage::Format_RGB32) to RGB565. Returns the newly allocated data. unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride) { + // Output line stride. Alligned to 4 bytes. + int alignedWidth = width; + if (alignedWidth % 2 > 0) + alignedWidth++; + // Will store output - unsigned short *out = (unsigned short *) malloc(width * height * 2); + unsigned short *out = (unsigned short *) malloc(alignedWidth * height * 2); // Lookup tables for the 8bit => 6bit and 8bit => 5bit conversion unsigned char lookup_8bit_to_5bit[256]; @@ -174,7 +179,7 @@ unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int h } // Write the newly produced pixel - PUT_565(out, x, y, width, component[2], component[1], component[0]); + PUT_565(out, x, y, alignedWidth, component[2], component[1], component[0]); } } @@ -183,10 +188,16 @@ unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int h // Converts incoming RGBA32 (QImage::Format_ARGB32_Premultiplied) to RGB565. Returns the newly allocated data. // This function is similar (yet different) to the _565 variant but it makes sense to duplicate it here for simplicity. +// The output has each scan line aligned to 4 bytes (as expected by GL by default). unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, int height, int stride) { + // Output line stride. Alligned to 4 bytes. + int alignedWidth = width; + if (alignedWidth % 2 > 0) + alignedWidth++; + // Will store output - unsigned short *out = (unsigned short *) malloc(width * height * 2); + unsigned short *out = (unsigned short *) malloc(alignedWidth * 2 * height); // Lookup tables for the 8bit => 4bit conversion unsigned char lookup_8bit_to_4bit[256]; @@ -269,7 +280,7 @@ unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, in } // Write the newly produced pixel - PUT_4444(out, x, y, width, component[0], component[1], component[2], component[3]); + PUT_4444(out, x, y, alignedWidth, component[0], component[1], component[2], component[3]); } } -- cgit v0.12 From 81fc8ec995a07909e59602b9281fbebfff4bd94c Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Thu, 28 Oct 2010 10:13:34 +1000 Subject: Fix QTBUG-14640:oci performance problem with qlonglong missing qlonglong switch case in bindValue(), so all qlonglong value fall back into QString, which makes the query slow. Change-Id: I7d8bf1c44ce3aaa15ee85be325a5c98dc3ed3ce1 Task-number:QTBUG-14640 Reviewed-by: Michael Goddard --- src/sql/drivers/oci/qsql_oci.cpp | 8 ++++++++ tests/auto/qsqlquery/tst_qsqlquery.cpp | 31 ++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index 3f30ea5..2392a17 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -291,6 +291,14 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in sizeof(uint), SQLT_UIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT); break; + case QVariant::LongLong: + r = OCIBindByPos(sql, hbnd, err, + pos + 1, + // if it's an out value, the data is already detached + // so the const cast is safe. + const_cast(data), + sizeof(OCINumber), + SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT); case QVariant::Double: r = OCIBindByPos(sql, hbnd, err, pos + 1, diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index 7c93c7a..5367bd6 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -211,6 +211,8 @@ private slots: void QTBUG_5765(); void QTBUG_14132_data() { generic_data("QOCI"); } void QTBUG_14132(); + void QTBUG_14640_data() { generic_data("QOCI"); } + void QTBUG_14640(); void sqlite_constraint_data() { generic_data("QSQLITE"); } void sqlite_constraint(); @@ -329,7 +331,8 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) << qTableName( "Planet", __FILE__ ) << qTableName( "task_250026", __FILE__ ) << qTableName( "task_234422", __FILE__ ) - << qTableName("test141895", __FILE__); + << qTableName("test141895", __FILE__) + << qTableName("qtest_QTBUG14640", __FILE__); if ( db.driverName().startsWith("QPSQL") ) tablenames << qTableName("task_233829", __FILE__); @@ -3101,6 +3104,32 @@ void tst_QSqlQuery::QTBUG_5765() QCOMPARE(q.value(0).toInt(), 123); } +void tst_QSqlQuery::QTBUG_14640() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + const QString qtest_QTBUG14640(qTableName("qtest_QTBUG14640", __FILE__)); + + QSqlQuery q( db ); + q.setForwardOnly( true ); + QVERIFY_SQL( q, exec( "create table " + qtest_QTBUG14640 + + " (col1 number, col2 number)" ) ); + QVERIFY_SQL( q, exec( "insert into " + qtest_QTBUG14640 + " values (1, 1111)" ) ); + QVERIFY_SQL( q, exec( "insert into " + qtest_QTBUG14640 + " values (2, 2222)" ) ); + QVERIFY_SQL( q, exec( "insert into " + qtest_QTBUG14640 + " values (3, 3333)" ) ); + + QString sqlStr = "select * from " + qtest_QTBUG14640 + " where col1 == :bindValue0 AND col2 == :bindValue1"; + q.prepare(sqlStr); + q.bindValue(":bindValue0", qlonglong(1), QSql::In); + q.bindValue(":bindValue1", qlonglong(1111), QSql::In); + QVERIFY_SQL( q, exec() ); + + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toLongLong(), qlonglong(1)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), qlonglong(1111)); +} + void tst_QSqlQuery::sqlite_constraint() { QFETCH( QString, dbName ); -- cgit v0.12 From d190802d33b763e7a21b85fb3dc2ed7c039ddbb6 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Mon, 1 Nov 2010 16:19:11 +0100 Subject: Doc: Fixing typo --- tools/macdeployqt/shared/shared.cpp | 2 +- tools/porting/src/preprocessorcontrol.cpp | 2 +- tools/porting/src/textreplacement.h | 4 ++-- tools/qdoc3/ditaxmlgenerator.cpp | 4 ++-- tools/qdoc3/tokenizer.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/macdeployqt/shared/shared.cpp b/tools/macdeployqt/shared/shared.cpp index 52cf04b..c7d23c0 100644 --- a/tools/macdeployqt/shared/shared.cpp +++ b/tools/macdeployqt/shared/shared.cpp @@ -388,7 +388,7 @@ DeploymentInfo deployQtFrameworks(QList frameworks, foreach (FrameworkInfo dependency, dependencies) { changeInstallName(dependency.installName, dependency.deployedInstallName, deployedBinaryPath); - // Deploy framework if neccesary. + // Deploy framework if necessary. if (copiedFrameworks.contains(dependency.frameworkName) == false && frameworks.contains(dependency) == false) { frameworks.append(dependency); } diff --git a/tools/porting/src/preprocessorcontrol.cpp b/tools/porting/src/preprocessorcontrol.cpp index 673ed08..31adc32 100644 --- a/tools/porting/src/preprocessorcontrol.cpp +++ b/tools/porting/src/preprocessorcontrol.cpp @@ -154,7 +154,7 @@ QByteArray PreprocessorCache::readFile(const QString &filename) const // read the file for us. if (receivers(SIGNAL(readFile(QByteArray&,QString))) > 0) { QByteArray array; - // Workaround for "not beeing able to emit from const function" + // Workaround for "not being able to emit from const function" PreprocessorCache *cache = const_cast(this); emit cache->readFile(array, filename); return array; diff --git a/tools/porting/src/textreplacement.h b/tools/porting/src/textreplacement.h index f90fb82..f351552 100644 --- a/tools/porting/src/textreplacement.h +++ b/tools/porting/src/textreplacement.h @@ -53,7 +53,7 @@ class TextReplacement public: QByteArray newText; int insertPosition; - int currentLenght; //lenght of the text that is going to be replaced. + int currentLenght; //length of the text that is going to be replaced. bool operator<(const TextReplacement &other) const { return (insertPosition < other.insertPosition); @@ -70,7 +70,7 @@ public: insert maintains the TextReplacement list in sorted order. - Returns true if the insert was successfull, false otherwise; + Returns true if the insert was successful, false otherwise; */ bool insert(QByteArray newText, int insertPosition, int currentLenght); void clear(); diff --git a/tools/qdoc3/ditaxmlgenerator.cpp b/tools/qdoc3/ditaxmlgenerator.cpp index a83a321..d43ad96 100644 --- a/tools/qdoc3/ditaxmlgenerator.cpp +++ b/tools/qdoc3/ditaxmlgenerator.cpp @@ -2015,7 +2015,7 @@ void DitaXmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *mark } /*! - Generates a table of contents begining at \a node. + Generates a table of contents beginning at \a node. */ void DitaXmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, @@ -2101,7 +2101,7 @@ void DitaXmlGenerator::generateTableOfContents(const Node *node, /*! Revised for the new doc format. - Generates a table of contents begining at \a node. + Generates a table of contents beginning at \a node. */ void DitaXmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, diff --git a/tools/qdoc3/tokenizer.h b/tools/qdoc3/tokenizer.h index bd35965..af617f1 100644 --- a/tools/qdoc3/tokenizer.h +++ b/tools/qdoc3/tokenizer.h @@ -145,7 +145,7 @@ class Tokenizer int ch = getch(); if (ch == EOF) return EOF; - // cast explicitely to make sure the value of ch + // cast explicitily to make sure the value of ch // is in range [0..255] to avoid assert messages // when using debug CRT that checks its input. return int(uint(uchar(ch))); -- cgit v0.12 From a1aee0f169614b31a7fde201a3d1c64010198218 Mon Sep 17 00:00:00 2001 From: Michael Dominic K Date: Tue, 2 Nov 2010 11:35:42 +0100 Subject: One more fix for dithering. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge-request: 2499 Reviewed-by: Samuel Rødal --- src/plugins/graphicssystems/meego/dithering.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/graphicssystems/meego/dithering.cpp b/src/plugins/graphicssystems/meego/dithering.cpp index c0b4b53..76d15a3 100644 --- a/src/plugins/graphicssystems/meego/dithering.cpp +++ b/src/plugins/graphicssystems/meego/dithering.cpp @@ -68,7 +68,7 @@ // Writes(ads) a new value to the diffusion accumulator. accumulator is a short. // x, y is a position in the accumulation buffer. y can be 0 or 1 -- we operate on two lines at time. -#define ACCUMULATE(accumulator, x, y, width, v) if (x < width && x > 0) accumulator[(y * width) + x] += v +#define ACCUMULATE(accumulator, x, y, width, v) if (x < width && x >= 0) accumulator[(y * width) + x] += v // Clamps a value to be in 0..255 range. #define CLAMP_256(v) if (v > 255) v = 255; if (v < 0) v = 0; @@ -110,18 +110,18 @@ unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int h // Produce the conversion lookup tables. for (i = 0; i < 256; i++) { lookup_8bit_to_5bit[i] = round(i / 8.0); - if (lookup_8bit_to_5bit[i] > 31) - lookup_8bit_to_5bit[i] -= 1; // Before bitshifts: (i * 8) - (... * 8 * 8) lookup_8bit_to_5bit_diff[i] = (i << 3) - (lookup_8bit_to_5bit[i] << 6); + if (lookup_8bit_to_5bit[i] > 31) + lookup_8bit_to_5bit[i] -= 1; lookup_8bit_to_6bit[i] = round(i / 4.0); - if (lookup_8bit_to_6bit[i] > 63) - lookup_8bit_to_6bit[i] -= 1; // Before bitshifts: (i * 8) - (... * 4 * 8) lookup_8bit_to_6bit_diff[i] = (i << 3) - (lookup_8bit_to_6bit[i] << 5); + if (lookup_8bit_to_6bit[i] > 63) + lookup_8bit_to_6bit[i] -= 1; } // Clear the accumulators @@ -221,11 +221,11 @@ unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, in // Produce the conversion lookup tables. for (i = 0; i < 256; i++) { lookup_8bit_to_4bit[i] = round(i / 16.0); - if (lookup_8bit_to_4bit[i] > 15) - lookup_8bit_to_4bit[i] -= 1; - // Before bitshifts: (i * 8) - (... * 16 * 8) lookup_8bit_to_4bit_diff[i] = (i << 3) - (lookup_8bit_to_4bit[i] << 7); + + if (lookup_8bit_to_4bit[i] > 15) + lookup_8bit_to_4bit[i] = 15; } // Clear the accumulators -- cgit v0.12 From 2f12d81a72fe6abb48cce4d327ecc27d308a8418 Mon Sep 17 00:00:00 2001 From: Michael Dominic K Date: Tue, 2 Nov 2010 11:35:42 +0100 Subject: Use 32bit textures for alpha textures after all. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4444 16bit are too bad quality-wise. Merge-request: 2499 Reviewed-by: Samuel Rødal --- src/plugins/graphicssystems/meego/dithering.cpp | 18 ++++++++++++++++++ src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp | 5 +++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/plugins/graphicssystems/meego/dithering.cpp b/src/plugins/graphicssystems/meego/dithering.cpp index 76d15a3..122c51e 100644 --- a/src/plugins/graphicssystems/meego/dithering.cpp +++ b/src/plugins/graphicssystems/meego/dithering.cpp @@ -286,3 +286,21 @@ unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, in return out; } + +unsigned char* convertBGRA32_to_RGBA32(const unsigned char *in, int width, int height, int stride) +{ + unsigned char *out = (unsigned char *) malloc(stride * height); + + // For each line... + for (int y = 0; y < height; y++) { + // For each column + for (int x = 0; x < width; x++) { + out[(stride * y) + (x * 4) + 0] = in[(stride * y) + (x * 4) + 2]; + out[(stride * y) + (x * 4) + 1] = in[(stride * y) + (x * 4) + 1]; + out[(stride * y) + (x * 4) + 2] = in[(stride * y) + (x * 4) + 0]; + out[(stride * y) + (x * 4) + 3] = in[(stride * y) + (x * 4) + 3]; + } + } + + return out; +} \ No newline at end of file diff --git a/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp index 02a4273..eb63692 100644 --- a/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp +++ b/src/plugins/graphicssystems/meego/qmeegopixmapdata.cpp @@ -51,6 +51,7 @@ // from dithering.cpp extern unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride); extern unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, int height, int stride); +extern unsigned char* convertBGRA32_to_RGBA32(const unsigned char *in, int width, int height, int stride); static EGLint preserved_image_attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; @@ -146,8 +147,8 @@ Qt::HANDLE QMeeGoPixmapData::imageToEGLSharedImage(const QImage &image) glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); if (image.hasAlphaChannel() && const_cast(image).data_ptr()->checkForAlphaPixels()) { - void *converted = convertARGB32_to_RGBA4444(image.bits(), image.width(), image.height(), image.bytesPerLine()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, converted); + void *converted = convertBGRA32_to_RGBA32(image.bits(), image.width(), image.height(), image.bytesPerLine()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, converted); free(converted); } else { void *converted = convertRGB32_to_RGB565(image.bits(), image.width(), image.height(), image.bytesPerLine()); -- cgit v0.12 From 7229aa57f96d35290914906601084a200132a7ea Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 2 Nov 2010 12:04:36 +0100 Subject: Update .def files for QtGui and QtOpenVG Update the .def files with the latest changes. Reviewed-by: Jason Barron --- src/s60installs/eabi/QtGuiu.def | 3 +++ src/s60installs/eabi/QtOpenVGu.def | 1 + 2 files changed, 4 insertions(+) diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index f772bcc..75bb026 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -12101,4 +12101,7 @@ EXPORTS _ZN19QApplicationPrivate25qmljsDebugArgumentsStringEv @ 12100 NONAME _ZNK5QFont14lastResortFontEv @ 12101 NONAME _ZN11QFontEngine33convertToPostscriptFontFamilyNameERK10QByteArray @ 12102 NONAME + _ZN15QStaticTextItem13setFontEngineEP11QFontEngine @ 12103 NONAME + _ZN15QStaticTextItemD1Ev @ 12104 NONAME + _ZN15QStaticTextItemD2Ev @ 12105 NONAME diff --git a/src/s60installs/eabi/QtOpenVGu.def b/src/s60installs/eabi/QtOpenVGu.def index 99942b8..e1828c1 100644 --- a/src/s60installs/eabi/QtOpenVGu.def +++ b/src/s60installs/eabi/QtOpenVGu.def @@ -205,4 +205,5 @@ EXPORTS _ZN13QVGPixmapData20createPixmapForImageER6QImage6QFlagsIN2Qt19ImageConversionFlagEEb @ 204 NONAME _ZN13QVGPixmapData8fromDataEPKhjPKc6QFlagsIN2Qt19ImageConversionFlagEE @ 205 NONAME _ZN13QVGPixmapData8fromFileERK7QStringPKc6QFlagsIN2Qt19ImageConversionFlagEE @ 206 NONAME + _ZNK14QVGPaintEngine16canVgWritePixelsERK6QImage @ 207 NONAME -- cgit v0.12 From 891221a3f0c952817eb7891b9243827edda61085 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Tue, 2 Nov 2010 13:41:50 +0100 Subject: Fix Malayalam Rendering - 'Ra' is PreBase Task-number: QTBUG-1887 Reviewed-by: Lars Knoll --- src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp b/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp index 4d8418b..237c9ae 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp +++ b/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp @@ -833,7 +833,7 @@ static const unsigned char indicPosition[0xe00-0x900] = { None, None, None, None, None, None, None, Post, - Post, None, Below, None, + Pre, None, Below, None, None, Post, None, None, None, None, None, None, None, None, Post, Post, -- cgit v0.12 From acc1a2bd5520369c690c2769f067aec6bfd869f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 3 Nov 2010 12:10:01 +0100 Subject: Fixed grabWidget sometimes returning uninitialized memory. Use a QImage initialized with transparent to prevent any translucent parts of the widget to end up as garbage, and to ensure that the resulting QPixmap ends up with an alpha format only when needed. Task-number: QTBUG-14945 Reviewed-by: Kim --- src/gui/image/qpixmap.cpp | 5 +++-- tests/auto/qpixmap/tst_qpixmap.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 64d8ed2..290c0f0 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1101,10 +1101,11 @@ QPixmap QPixmap::grabWidget(QWidget * widget, const QRect &rect) if (!r.intersects(widget->rect())) return QPixmap(); - QPixmap res(r.size()); + QImage res(r.size(), QImage::Format_ARGB32_Premultiplied); + res.fill(0); widget->d_func()->render(&res, QPoint(), r, QWidget::DrawWindowBackground | QWidget::DrawChildren | QWidget::IgnoreMask, true); - return res; + return QPixmap::fromImage(res); } /*! diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index fdf8311..a733d56 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -817,7 +817,7 @@ void tst_QPixmap::grabWidget() for (int row = 0; row < image.height(); ++row) { QRgb *line = reinterpret_cast(image.scanLine(row)); for (int col = 0; col < image.width(); ++col) - line[col] = qRgb(rand() & 255, row, col); + line[col] = qRgba(rand() & 255, row, col, 127); } QPalette pal = widget.palette(); -- cgit v0.12 From 75648ab9c4f64830aa36753686bec1a8f91d2f7e Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Wed, 3 Nov 2010 13:04:04 +0100 Subject: Doc: Fixing typo --- src/plugins/graphicssystems/meego/dithering.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/graphicssystems/meego/dithering.cpp b/src/plugins/graphicssystems/meego/dithering.cpp index 122c51e..1a2e3fa 100644 --- a/src/plugins/graphicssystems/meego/dithering.cpp +++ b/src/plugins/graphicssystems/meego/dithering.cpp @@ -76,7 +76,7 @@ // Converts incoming RGB32 (QImage::Format_RGB32) to RGB565. Returns the newly allocated data. unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride) { - // Output line stride. Alligned to 4 bytes. + // Output line stride. Aligned to 4 bytes. int alignedWidth = width; if (alignedWidth % 2 > 0) alignedWidth++; @@ -191,7 +191,7 @@ unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int h // The output has each scan line aligned to 4 bytes (as expected by GL by default). unsigned short* convertARGB32_to_RGBA4444(const unsigned char *in, int width, int height, int stride) { - // Output line stride. Alligned to 4 bytes. + // Output line stride. Aligned to 4 bytes. int alignedWidth = width; if (alignedWidth % 2 > 0) alignedWidth++; @@ -303,4 +303,4 @@ unsigned char* convertBGRA32_to_RGBA32(const unsigned char *in, int width, int h } return out; -} \ No newline at end of file +} -- cgit v0.12 From c32ec4e928895a85aa10ce47a73c2bd439e7fc89 Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Thu, 4 Nov 2010 12:30:46 +1000 Subject: More fix for QTBUG-14640:oci performance problem with qlonglong 1. OCINumber must be declared & initialized seperately, and the bound OCINumber values must be hold until the QOCIResultPrivate object is deleted. 2. More auto tests for this bug. 3. Add qulonglong support as well 4. Make the execBatch() works with longlong and ulonglong Task-number:QTBUG-14640 Reviewed-by: Michael Goddard Change-Id: I7d8bf1c44ce3aaa15ee85be325a5c98dc3ed3ce1 --- src/sql/drivers/oci/qsql_oci.cpp | 133 ++++++++++++++++++++++++++++++-- tests/auto/qsqldatabase/tst_databases.h | 2 +- tests/auto/qsqlquery/tst_qsqlquery.cpp | 121 ++++++++++++++++++++++++----- 3 files changed, 227 insertions(+), 29 deletions(-) diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index 2392a17..1bf59bf 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -112,7 +112,15 @@ typedef QVarLengthArray SizeArray; static QByteArray qMakeOraDate(const QDateTime& dt); static QDateTime qMakeDate(const char* oraDate); + +static QByteArray qMakeOCINumber(const qlonglong &ll, OCIError *err); +static QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err); + +static qlonglong qMakeLongLong(const char* ociNumber, OCIError* err); +static qulonglong qMakeULongLong(const char* ociNumber, OCIError* err); + static QString qOraWarn(OCIError *err, int *errorCode = 0); + #ifndef Q_CC_SUN static // for some reason, Sun CC can't use qOraWarning when it's declared static #endif @@ -292,13 +300,27 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in SQLT_UIN, indPtr, 0, 0, 0, 0, OCI_DEFAULT); break; case QVariant::LongLong: + { + QByteArray ba = qMakeOCINumber(val.toLongLong(), err); r = OCIBindByPos(sql, hbnd, err, pos + 1, - // if it's an out value, the data is already detached - // so the const cast is safe. - const_cast(data), - sizeof(OCINumber), + ba.data(), + ba.size(), SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT); + tmpStorage.append(ba); + break; + } + case QVariant::ULongLong: + { + QByteArray ba = qMakeOCINumber(val.toULongLong(), err); + r = OCIBindByPos(sql, hbnd, err, + pos + 1, + ba.data(), + ba.size(), + SQLT_VNU, indPtr, 0, 0, 0, 0, OCI_DEFAULT); + tmpStorage.append(ba); + break; + } case QVariant::Double: r = OCIBindByPos(sql, hbnd, err, pos + 1, @@ -394,7 +416,7 @@ int QOCIResultPrivate::bindValues(QVector &values, IndicatorArray &ind } // will assign out value and remove its temp storage. -static void qOraOutValue(QVariant &value, QList &storage) +static void qOraOutValue(QVariant &value, QList &storage, OCIError* err) { switch (value.type()) { case QVariant::Time: @@ -406,6 +428,12 @@ static void qOraOutValue(QVariant &value, QList &storage) case QVariant::DateTime: value = qMakeDate(storage.takeFirst()); break; + case QVariant::LongLong: + value = qMakeLongLong(storage.takeFirst(), err); + break; + case QVariant::ULongLong: + value = qMakeULongLong(storage.takeFirst(), err); + break; case QVariant::String: value = QString( reinterpret_cast(storage.takeFirst().constData())); @@ -423,7 +451,7 @@ void QOCIResultPrivate::outValues(QVector &values, IndicatorArray &ind if (!isOutValue(i)) continue; - qOraOutValue(values[i], tmpStorage); + qOraOutValue(values[i], tmpStorage, err); QVariant::Type typ = values.at(i).type(); if (indicators[i] == -1) // NULL @@ -683,6 +711,56 @@ QByteArray qMakeOraDate(const QDateTime& dt) return ba; } +/*! + \internal + + Convert qlonglong to the internal Oracle OCINumber format. + */ +QByteArray qMakeOCINumber(const qlonglong& ll, OCIError* err) +{ + QByteArray ba(sizeof(OCINumber), 0); + + OCINumberFromInt(err, + &ll, + sizeof(qlonglong), + OCI_NUMBER_SIGNED, + reinterpret_cast(ba.data())); + return ba; +} + +/*! + \internal + + Convert qulonglong to the internal Oracle OCINumber format. + */ +QByteArray qMakeOCINumber(const qulonglong& ull, OCIError* err) +{ + QByteArray ba(sizeof(OCINumber), 0); + + OCINumberFromInt(err, + &ull, + sizeof(qlonglong), + OCI_NUMBER_UNSIGNED, + reinterpret_cast(ba.data())); + return ba; +} + +qlonglong qMakeLongLong(const char* ociNumber, OCIError* err) +{ + qlonglong qll = 0; + OCINumberToInt(err, reinterpret_cast(ociNumber), sizeof(qlonglong), + OCI_NUMBER_SIGNED, &qll); + return qll; +} + +qulonglong qMakeULongLong(const char* ociNumber, OCIError* err) +{ + qulonglong qull = 0; + OCINumberToInt(err, reinterpret_cast(ociNumber), sizeof(qulonglong), + OCI_NUMBER_UNSIGNED, &qull); + return qull; +} + QDateTime qMakeDate(const char* oraDate) { int century = uchar(oraDate[0]); @@ -1267,6 +1345,16 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector &boundValues, b col.maxLen = sizeof(uint); break; + case QVariant::LongLong: + col.bindAs = SQLT_VNU; + col.maxLen = sizeof(OCINumber); + break; + + case QVariant::ULongLong: + col.bindAs = SQLT_VNU; + col.maxLen = sizeof(OCINumber); + break; + case QVariant::Double: col.bindAs = SQLT_FLT; col.maxLen = sizeof(double); @@ -1338,6 +1426,22 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector &boundValues, b *reinterpret_cast(dataPtr) = val.toUInt(); break; + case QVariant::LongLong: + { + columns[i].lengths[row] = columns[i].maxLen; + const QByteArray ba = qMakeOCINumber(val.toLongLong(), d->err); + Q_ASSERT(ba.size() == int(columns[i].maxLen)); + memcpy(dataPtr, ba.constData(), columns[i].maxLen); + break; + } + case QVariant::ULongLong: + { + columns[i].lengths[row] = columns[i].maxLen; + const QByteArray ba = qMakeOCINumber(val.toULongLong(), d->err); + Q_ASSERT(ba.size() == int(columns[i].maxLen)); + memcpy(dataPtr, ba.constData(), columns[i].maxLen); + break; + } case QVariant::Double: columns[i].lengths[row] = columns[i].maxLen; *reinterpret_cast(dataPtr) = val.toDouble(); @@ -1445,7 +1549,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector &boundValues, b QVariant::Type tp = boundValues.at(i).type(); if (tp != QVariant::List) { - qOraOutValue(boundValues[i], tmpStorage); + qOraOutValue(boundValues[i], tmpStorage, d->err); if (*columns[i].indicators == -1) boundValues[i] = QVariant(tp); continue; @@ -1475,6 +1579,21 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVector &boundValues, b (*list)[r] = *reinterpret_cast(data + r * columns[i].maxLen); break; + case SQLT_VNU: + { + switch (boundValues.at(i).type()) { + case QVariant::LongLong: + (*list)[r] = qMakeLongLong(data + r * columns[i].maxLen, d->err); + break; + case QVariant::ULongLong: + (*list)[r] = qMakeULongLong(data + r * columns[i].maxLen, d->err); + break; + default: + break; + } + break; + } + case SQLT_FLT: (*list)[r] = *reinterpret_cast(data + r * columns[i].maxLen); break; diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index 5837719..80535df 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -208,7 +208,7 @@ public: // addDb( "QOCI8", "//horsehead.nokia.troll.no:1521/ustest.troll.no", "scott", "tiger", "" ); // Oracle 9i on horsehead // addDb( "QOCI8", "//iceblink.nokia.troll.no:1521/ice.troll.no", "scott", "tiger", "" ); // Oracle 8 on iceblink (not currently working) // addDb( "QOCI", "//silence.nokia.troll.no:1521/testdb", "scott", "tiger" ); // Oracle 10g on silence -// addDb( "QOCI", "//oracle10g-nokia.trolltech.com.au:1521/XE", "scott", "tiger" ); // Oracle 10gexpress on xen +// addDb( "QOCI", "//bq-oracle10g.apac.nokia.com:1521/XE", "scott", "tiger" ); // Oracle 10gexpress // This requires a local ODBC data source to be configured( pointing to a MySql database ) // addDb( "QODBC", "mysqlodbc", "troll", "trond" ); diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index 5367bd6..b4a3e08 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -139,6 +139,8 @@ private slots: void oraClob(); void oraLong_data() { generic_data("QOCI"); } void oraLong(); + void oraOCINumber_data() { generic_data("QOCI"); } + void oraOCINumber(); void outValuesDB2_data() { generic_data("QDB2"); } void outValuesDB2(); void storedProceduresIBase_data() {generic_data("QIBASE"); } @@ -211,8 +213,7 @@ private slots: void QTBUG_5765(); void QTBUG_14132_data() { generic_data("QOCI"); } void QTBUG_14132(); - void QTBUG_14640_data() { generic_data("QOCI"); } - void QTBUG_14640(); + void sqlite_constraint_data() { generic_data("QSQLITE"); } void sqlite_constraint(); @@ -332,7 +333,7 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) << qTableName( "task_250026", __FILE__ ) << qTableName( "task_234422", __FILE__ ) << qTableName("test141895", __FILE__) - << qTableName("qtest_QTBUG14640", __FILE__); + << qTableName("qtest_oraOCINumber", __FILE__); if ( db.driverName().startsWith("QPSQL") ) tablenames << qTableName("task_233829", __FILE__); @@ -2950,11 +2951,11 @@ void tst_QSqlQuery::QTBUG_14132() begin \n\ outStr := 'OUTSTRING'; \n\ end;")); - QString outValue = "XXXXXXXXX"; - q.prepare("CALL "+procedureName+"(?)"); - q.addBindValue(outValue, QSql::Out); + QString placeholder = "XXXXXXXXX"; + QVERIFY(q.prepare("CALL "+procedureName+"(?)")); + q.addBindValue(placeholder, QSql::Out); QVERIFY_SQL(q, exec()); - QCOMPARE(outValue, QLatin1String("OUTSTRING")); + QCOMPARE(q.boundValue(0).toString(), QLatin1String("OUTSTRING")); } void tst_QSqlQuery::QTBUG_5251() @@ -3104,30 +3105,108 @@ void tst_QSqlQuery::QTBUG_5765() QCOMPARE(q.value(0).toInt(), 123); } -void tst_QSqlQuery::QTBUG_14640() +void tst_QSqlQuery::oraOCINumber() { QFETCH( QString, dbName ); QSqlDatabase db = QSqlDatabase::database( dbName ); CHECK_DATABASE( db ); - const QString qtest_QTBUG14640(qTableName("qtest_QTBUG14640", __FILE__)); + const QString qtest_oraOCINumber(qTableName("qtest_oraOCINumber", __FILE__)); QSqlQuery q( db ); q.setForwardOnly( true ); - QVERIFY_SQL( q, exec( "create table " + qtest_QTBUG14640 + - " (col1 number, col2 number)" ) ); - QVERIFY_SQL( q, exec( "insert into " + qtest_QTBUG14640 + " values (1, 1111)" ) ); - QVERIFY_SQL( q, exec( "insert into " + qtest_QTBUG14640 + " values (2, 2222)" ) ); - QVERIFY_SQL( q, exec( "insert into " + qtest_QTBUG14640 + " values (3, 3333)" ) ); - - QString sqlStr = "select * from " + qtest_QTBUG14640 + " where col1 == :bindValue0 AND col2 == :bindValue1"; - q.prepare(sqlStr); - q.bindValue(":bindValue0", qlonglong(1), QSql::In); - q.bindValue(":bindValue1", qlonglong(1111), QSql::In); + QVERIFY_SQL( q, exec( "create table " + qtest_oraOCINumber + + " (col1 number(20), col2 number(20))" ) ); + QVERIFY(q.prepare("insert into " + qtest_oraOCINumber + " values (?, ?)")); + QVariantList col1Values; + QVariantList col2Values; + col1Values << (qulonglong)(1) + << (qulonglong)(0) + << (qulonglong)(INT_MAX) + << (qulonglong)(UINT_MAX) + << (qulonglong)(LONG_MAX) + << (qulonglong)(ULONG_MAX) + << (qulonglong)(LLONG_MAX) + << (qulonglong)(ULLONG_MAX); + + col2Values << (qlonglong)(1) + << (qlonglong)(0) + << (qlonglong)(-1) + << (qlonglong)(LONG_MAX) + << (qlonglong)(LONG_MIN) + << (qlonglong)(ULONG_MAX) + << (qlonglong)(LLONG_MAX) + << (qlonglong)(LLONG_MIN); + + q.addBindValue(col1Values); + q.addBindValue(col2Values); + QVERIFY(q.execBatch()); + QString sqlStr = "select * from " + qtest_oraOCINumber + " where col1 = :bindValue0 AND col2 = :bindValue1"; + QVERIFY(q.prepare(sqlStr)); + + q.bindValue(":bindValue0", (qulonglong)(1), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(1), QSql::InOut); + + QVERIFY_SQL( q, exec() ); + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toULongLong(), qulonglong(1)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(1)); + + q.bindValue(":bindValue0", (qulonglong)(0), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(0), QSql::InOut); + QVERIFY_SQL( q, exec() ); + + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toULongLong(), (qulonglong)(0)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(0)); + + q.bindValue(":bindValue0", (qulonglong)(INT_MAX), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(-1), QSql::InOut); + QVERIFY_SQL( q, exec() ); + + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toULongLong(), (qulonglong)(INT_MAX)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(-1)); + + q.bindValue(":bindValue0", (qulonglong)(UINT_MAX), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(LONG_MAX), QSql::InOut); + QVERIFY_SQL( q, exec() ); + + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toULongLong(), (qulonglong)(UINT_MAX)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(LONG_MAX)); + + q.bindValue(":bindValue0", (qulonglong)(LONG_MAX), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(LONG_MIN), QSql::InOut); + QVERIFY_SQL( q, exec() ); + + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toULongLong(), (qulonglong)(LONG_MAX)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(LONG_MIN)); + + q.bindValue(":bindValue0", (qulonglong)(ULONG_MAX), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(ULONG_MAX), QSql::InOut); QVERIFY_SQL( q, exec() ); QVERIFY( q.next() ); - QCOMPARE(q.boundValue( 0 ).toLongLong(), qlonglong(1)); - QCOMPARE(q.boundValue( 1 ).toLongLong(), qlonglong(1111)); + QCOMPARE(q.boundValue( 0 ).toULongLong(), (qulonglong)(ULONG_MAX)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(ULONG_MAX)); + + q.bindValue(":bindValue0", (qulonglong)(LLONG_MAX), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(LLONG_MAX), QSql::InOut); + QVERIFY_SQL( q, exec() ); + + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toULongLong(), (qulonglong)(LLONG_MAX)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(LLONG_MAX)); + + q.bindValue(":bindValue0", (qulonglong)(ULLONG_MAX), QSql::InOut); + q.bindValue(":bindValue1", (qlonglong)(LLONG_MIN), QSql::InOut); + QVERIFY_SQL( q, exec() ); + + QVERIFY( q.next() ); + QCOMPARE(q.boundValue( 0 ).toULongLong(), (qulonglong)(ULLONG_MAX)); + QCOMPARE(q.boundValue( 1 ).toLongLong(), (qlonglong)(LLONG_MIN)); + } void tst_QSqlQuery::sqlite_constraint() -- cgit v0.12 From ee958e086847e2131f9b746e5c6de4491ae1f44b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 8 Nov 2010 10:05:28 +0100 Subject: Prevented race condition on texture destruction. When texture destruction was triggered from a different thread, we posted a signal to the QGLSignalProxy. However, before the signal is delivered the corresponding QGLContext might be destroyed in the main thread. We need to post a signal to a QObject which is destroyed when the QGLContext is destroyed instead, to prevent trying to access an invalid QGLContext pointer. Task-number: QT-4238 Reviewed-by: Gunnar Sletta --- src/opengl/qgl.cpp | 11 +++++++++++ src/opengl/qgl.h | 1 + src/opengl/qgl_p.h | 30 ++++++++++++++++++++---------- tests/auto/qgl/tst_qgl.cpp | 8 ++++++-- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 84cfa97..ed9753e 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1642,12 +1642,23 @@ const QGLContext *qt_gl_transfer_context(const QGLContext *ctx) return 0; } +QGLContextPrivate::QGLContextPrivate(QGLContext *context) + : internal_context(false) + , q_ptr(context) +{ + group = new QGLContextGroup(context); + texture_destroyer = new QGLTextureDestroyer; + texture_destroyer->moveToThread(qApp->thread()); +} + QGLContextPrivate::~QGLContextPrivate() { if (!group->m_refs.deref()) { Q_ASSERT(group->context() == q_ptr); delete group; } + + delete texture_destroyer; } void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index f85cad5..9ae619d 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -428,6 +428,7 @@ private: friend class QGLSharedResourceGuard; friend class QGLPixmapBlurFilter; friend class QGLExtensions; + friend class QGLTexture; friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags(); #ifdef Q_WS_MAC public: diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 18b2765..4742bdb 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -317,6 +317,7 @@ private: }; class QGLTexture; +class QGLTextureDestroyer; // This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's // all the GL2 engine uses: @@ -326,7 +327,7 @@ class QGLContextPrivate { Q_DECLARE_PUBLIC(QGLContext) public: - explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {group = new QGLContextGroup(context);} + explicit QGLContextPrivate(QGLContext *context); ~QGLContextPrivate(); QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options); @@ -417,6 +418,7 @@ public: GLuint current_fbo; GLuint default_fbo; QPaintEngine *active_engine; + QGLTextureDestroyer *texture_destroyer; bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT]; @@ -476,25 +478,20 @@ private: QGLContext *m_ctx; }; -// ### make QGLContext a QObject in 5.0 and remove the proxy stuff -class Q_OPENGL_EXPORT QGLSignalProxy : public QObject +class QGLTextureDestroyer : public QObject { Q_OBJECT public: - QGLSignalProxy() : QObject() { + QGLTextureDestroyer() : QObject() { qRegisterMetaType("GLuint"); connect(this, SIGNAL(freeTexture(QGLContext *, QPixmapData *, GLuint)), this, SLOT(freeTexture_slot(QGLContext *, QPixmapData *, GLuint))); } - void emitAboutToDestroyContext(const QGLContext *context) { - emit aboutToDestroyContext(context); - } void emitFreeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id) { emit freeTexture(context, boundPixmap, id); } - static QGLSignalProxy *instance(); + Q_SIGNALS: - void aboutToDestroyContext(const QGLContext *context); void freeTexture(QGLContext *context, QPixmapData *boundPixmap, GLuint id); private slots: @@ -518,6 +515,19 @@ private slots: } }; +// ### make QGLContext a QObject in 5.0 and remove the proxy stuff +class Q_OPENGL_EXPORT QGLSignalProxy : public QObject +{ + Q_OBJECT +public: + void emitAboutToDestroyContext(const QGLContext *context) { + emit aboutToDestroyContext(context); + } + static QGLSignalProxy *instance(); +Q_SIGNALS: + void aboutToDestroyContext(const QGLContext *context); +}; + class QGLTexture { public: QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D, @@ -537,7 +547,7 @@ public: #if !defined(Q_WS_X11) QPixmapData *boundPixmap = 0; #endif - QGLSignalProxy::instance()->emitFreeTexture(context, boundPixmap, id); + context->d_ptr->texture_destroyer->emitFreeTexture(context, boundPixmap, id); } } diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp index 4220b45..e38bf42 100644 --- a/tests/auto/qgl/tst_qgl.cpp +++ b/tests/auto/qgl/tst_qgl.cpp @@ -2335,8 +2335,10 @@ public: Widget() : iterations(0) , display(0) + , producer(new Producer) { startTimer(400); + connect(this, SIGNAL(destroyed()), producer, SLOT(deleteLater())); } int iterations; @@ -2348,15 +2350,15 @@ protected: delete display; display = new DisplayWidget(this); - connect(&producer, SIGNAL(imageReady(const QImage &)), display, SLOT(setImage(const QImage &))); + connect(producer, SIGNAL(imageReady(const QImage &)), display, SLOT(setImage(const QImage &))); display->setGeometry(rect()); display->show(); } private: - Producer producer; DisplayWidget *display; + Producer *producer; }; } @@ -2369,6 +2371,8 @@ void tst_QGL::threadImages() while (widget->iterations <= 5) { qApp->processEvents(); } + + delete widget; } class tst_QGLDummy : public QObject -- cgit v0.12 From 285855b8fbbdc7ad428a0c66f6c4469d97e55769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 8 Nov 2010 17:33:49 +0100 Subject: Fixed text rendering bug in raster engine when opacity != 1.0. If opacity is updated independently from the pen properties sometimes the raster engine's fast_text flag would not be updated correctly, causing it to use a rendering path which doesn't support alpha. Reviewed-by: Robin Burchell Reviewed-by: Andreas Kling --- src/gui/painting/qpaintengine_raster.cpp | 4 +++- tests/auto/qpainter/tst_qpainter.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 161ced5..89202ac 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -875,9 +875,10 @@ void QRasterPaintEngine::updateState() if (s->dirty & DirtyTransform) updateMatrix(s->matrix); - if (s->dirty & (DirtyPen|DirtyCompositionMode)) { + if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) { const QPainter::CompositionMode mode = s->composition_mode; s->flags.fast_text = (s->penData.type == QSpanData::Solid) + && s->intOpacity == 256 && (mode == QPainter::CompositionMode_Source || (mode == QPainter::CompositionMode_SourceOver && qAlpha(s->penData.solid.color) == 255)); @@ -901,6 +902,7 @@ void QRasterPaintEngine::opacityChanged() s->fillFlags |= DirtyOpacity; s->strokeFlags |= DirtyOpacity; s->pixmapFlags |= DirtyOpacity; + s->dirty |= DirtyOpacity; s->intOpacity = (int) (s->opacity * 256); } diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp index ff9bf1c..83ff9a9 100644 --- a/tests/auto/qpainter/tst_qpainter.cpp +++ b/tests/auto/qpainter/tst_qpainter.cpp @@ -256,6 +256,7 @@ private slots: void drawPointScaled(); void QTBUG14614_gradientCacheRaceCondition(); + void drawTextOpacity(); private: void fillData(); @@ -4576,6 +4577,30 @@ void tst_QPainter::QTBUG14614_gradientCacheRaceCondition() producers[i].wait(); } +void tst_QPainter::drawTextOpacity() +{ + QImage image(32, 32, QImage::Format_RGB32); + image.fill(0xffffffff); + + QPainter p(&image); + p.setPen(QColor("#6F6F6F")); + p.setOpacity(0.5); + p.drawText(5, 30, QLatin1String("Qt")); + p.end(); + + QImage copy = image; + image.fill(0xffffffff); + + p.begin(&image); + p.setPen(QColor("#6F6F6F")); + p.drawLine(-10, -10, -1, -1); + p.setOpacity(0.5); + p.drawText(5, 30, QLatin1String("Qt")); + p.end(); + + QCOMPARE(image, copy); +} + QTEST_MAIN(tst_QPainter) #include "tst_qpainter.moc" -- cgit v0.12