diff options
Diffstat (limited to 'src')
44 files changed, 1144 insertions, 681 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.gypi b/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.gypi index 2d69c7d..5a75ab7 100644 --- a/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.gypi +++ b/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.gypi @@ -323,7 +323,7 @@ 'runtime/TimeoutChecker.cpp', 'runtime/TimeoutChecker.h', 'runtime/Tracing.h', - 'runtime/TypeInfo.h', + 'runtime/JSTypeInfo.h', 'runtime/UString.cpp', 'runtime/UString.h', 'wrec/CharacterClass.cpp', diff --git a/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp b/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp index 29a13ca..de5175e 100644 --- a/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/interpreter/RegisterFile.cpp @@ -36,6 +36,9 @@ RegisterFile::~RegisterFile() #if HAVE(MMAP) munmap(reinterpret_cast<char*>(m_buffer), ((m_max - m_start) + m_maxGlobals) * sizeof(Register)); #elif HAVE(VIRTUALALLOC) +#if PLATFORM(WINCE) + VirtualFree(m_buffer, DWORD(m_commitEnd) - DWORD(m_buffer), MEM_DECOMMIT); +#endif VirtualFree(m_buffer, 0, MEM_RELEASE); #else fastFree(m_buffer); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/TypeInfo.h b/src/3rdparty/webkit/JavaScriptCore/runtime/JSTypeInfo.h index 70aeed3..bea188b 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/TypeInfo.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSTypeInfo.h @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TypeInfo_h -#define TypeInfo_h +#ifndef JSTypeInfo_h +#define JSTypeInfo_h #include "JSType.h" @@ -69,4 +69,4 @@ namespace JSC { } -#endif // TypeInfo_h +#endif // JSTypeInfo_h diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.h b/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.h index dcd4e50..ca4552b 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.h @@ -31,7 +31,7 @@ #include "JSValue.h" #include "PropertyMapHashTable.h" #include "StructureTransitionTable.h" -#include "TypeInfo.h" +#include "JSTypeInfo.h" #include "UString.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index e1b8509..31f0841 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -157,6 +157,19 @@ #define DEFAULT_TIMER_INTERVAL 16 +#ifdef Q_WS_WIN + /// Fix for Qt 4.7 + //on windows if you're currently dragging a widget an inner eventloop was started by the system + //to make sure that this timer is getting fired, we need to make sure to use the system timers + //that will send a WM_TIMER event. We do that by settings the timer interval to 11 + //It is 11 because QEventDispatcherWin32Private::registerTimer specifically checks if the interval + //is greater than 10 to determine if it should use a system timer (or the multimedia timer). +#define STARTSTOP_TIMER_DELAY 11 +#else +#define STARTSTOP_TIMER_DELAY 0 +#endif + + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer) @@ -217,7 +230,7 @@ void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation) if (animations.contains(animation) || animationsToStart.contains(animation)) return; animationsToStart << animation; - startStopAnimationTimer.start(0, this); // we delay the check if we should start/stop the global timer + startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); // we delay the check if we should start/stop the global timer } void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) @@ -233,7 +246,7 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) } else { animationsToStart.removeOne(animation); } - startStopAnimationTimer.start(0, this); // we delay the check if we should start/stop the global timer + startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); // we delay the check if we should start/stop the global timer } diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 8f34e30..93de911 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1655,7 +1655,8 @@ public: FramebufferObject = 0x07, // GL framebuffer object CustomRaster = 0x08, MacQuartz = 0x09, - PaintBuffer = 0x0a + PaintBuffer = 0x0a, + OpenGL = 0x0b }; enum RelayoutType { RelayoutNormal, diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 50b4af7..80ccda3 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -865,15 +865,22 @@ QString QFSFileEngine::fileName(FileName file) const QString ret; if (!isRelativePathSymbian(d->filePath)) { if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') - && d->filePath.at(2) != slashChar || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt - d->filePath.startsWith(slashChar) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt - ) { - ret = QString(QDir::currentPath().left(2) + QDir::fromNativeSeparators(d->filePath)); + && d->filePath.at(2) != slashChar){ + // It's a drive-relative path, so C:a.txt -> C:/currentpath/a.txt, + // or if it's different drive than current, Z:a.txt -> Z:/a.txt + QString currentPath = QDir::currentPath(); + if (0 == currentPath.left(1).compare(d->filePath.left(1), Qt::CaseInsensitive)) + ret = currentPath + slashChar + d->filePath.mid(2); + else + ret = d->filePath.left(2) + slashChar + d->filePath.mid(2); + } else if (d->filePath.startsWith(slashChar)) { + // It's a absolute path to the current drive, so /a.txt -> C:/a.txt + ret = QDir::currentPath().left(2) + d->filePath; } else { ret = d->filePath; } } else { - ret = QDir::cleanPath(QDir::currentPath() + slashChar + d->filePath); + ret = QDir::currentPath() + slashChar + d->filePath; } // The path should be absolute at this point. @@ -889,6 +896,12 @@ QString QFSFileEngine::fileName(FileName file) const ret[0] = ret.at(0).toUpper(); } + // Clean up the path + bool isDir = ret.endsWith(slashChar); + ret = QDir::cleanPath(ret); + if (isDir) + ret += slashChar; + if (file == AbsolutePathName) { int slash = ret.lastIndexOf(slashChar); if (slash < 0) diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index c2bdbee..f316fec 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -367,21 +367,26 @@ Q_INLINE_TEMPLATE void QList<T>::node_copy(Node *from, Node *to, Node *src) if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) { QT_TRY { while(current != to) { - (current++)->v = new T(*reinterpret_cast<T*>((src++)->v)); + current->v = new T(*reinterpret_cast<T*>(src->v)); + ++current; + ++src; } } QT_CATCH(...) { - while (current != from) - delete reinterpret_cast<T*>(current--); + while (current-- != from) + delete reinterpret_cast<T*>(current->v); QT_RETHROW; } } else if (QTypeInfo<T>::isComplex) { QT_TRY { - while(current != to) - new (current++) T(*reinterpret_cast<T*>(src++)); + while(current != to) { + new (current) T(*reinterpret_cast<T*>(src)); + ++current; + ++src; + } } QT_CATCH(...) { - while (current != from) - (reinterpret_cast<T*>(current--))->~T(); + while (current-- != from) + (reinterpret_cast<T*>(current))->~T(); QT_RETHROW; } } else { diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index 052c456..28ec963 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -388,6 +388,10 @@ void QTimeLine::setDirection(Direction direction) By default, this value is 1000 (i.e., 1 second), but you can change this by either passing a duration to QTimeLine's constructor, or by calling setDuration(). The duration must be larger than 0. + + \note Changing the duration does not cause the current time to be reset + to zero or the new duration. You also need to call setCurrentTime() with + the desired value. */ int QTimeLine::duration() const { diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 52529ff..99e9aeb 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -1661,6 +1661,10 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers); bool edited = edit(index, trigger, event); + //in the case the user presses on no item we might decide to clear the selection + if (d->selectionModel && !index.isValid()) + d->selectionModel->select(QModelIndex(), selectionCommand(index, event)); + setState(NoState); if (click) { diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 511c797..a3420da 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4772,7 +4772,12 @@ void QApplicationPrivate::emitLastWindowClosed() If \a enable is true, Qt::Key_Up and Qt::Key_Down are used to change focus. - This feature is available in Qt for Embedded Linux and Symbian only. + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. \sa keypadNavigationEnabled() */ @@ -4785,7 +4790,12 @@ void QApplication::setKeypadNavigationEnabled(bool enable) Returns true if Qt is set to use keypad navigation; otherwise returns false. The default value is true on Symbian, but false on other platforms. - This feature is available in Qt for Embedded Linux and Symbian only. + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. \sa setKeypadNavigationEnabled() */ diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index e3bd786..ba2e6a6 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -2202,6 +2202,8 @@ void qt_init(QApplicationPrivate *priv, int type) mouse_double_click_distance = read_int_env_var("QWS_DBLCLICK_DISTANCE", 5); + priv->inputContext = 0; + int flags = 0; char *p; int argc = priv->argc; @@ -2361,6 +2363,11 @@ void qt_cleanup() delete mouseInWidget; mouseInWidget = 0; + +#if !defined(QT_NO_IM) + delete QApplicationPrivate::inputContext; + QApplicationPrivate::inputContext = 0; +#endif } diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index 8e76715..b3e137d 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -535,6 +535,12 @@ void QPinchGesture::reset() QGesture::reset(); } +/*! \enum QPinchGesture::WhatChange + \value ScaleFactorChanged + \value RotationAngleChanged + \value CenterPointChanged +*/ + /*! \property QPinchGesture::whatChanged diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index 284558f..bd30cad 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -731,6 +731,7 @@ private: friend class QGLContext; friend class QGLWidget; friend class QGLWindowSurface; + friend class QGLWindowSurfaceGLPaintDevice; friend class QVGWindowSurface; friend class QX11PaintEngine; friend class QWin32PaintEngine; diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp index f442788..42da637 100644 --- a/src/gui/painting/qpaintengine.cpp +++ b/src/gui/painting/qpaintengine.cpp @@ -386,6 +386,7 @@ void QPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDraw \value User First user type ID \value MaxUser Last user type ID \value OpenGL2 + \value PaintBuffer */ /*! diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index 3d8dec6..b1fd415 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -1130,10 +1130,10 @@ void QRenderRule::drawBorderImage(QPainter *p, const QRect& rect) const QStyleSheetBorderImageData *borderImageData = border()->borderImage(); const int *targetBorders = border()->borders; const int *sourceBorders = borderImageData->cuts; - QMargins sourceMargins(sourceBorders[TopEdge], sourceBorders[LeftEdge], - sourceBorders[BottomEdge], sourceBorders[RightEdge]); - QMargins targetMargins(targetBorders[TopEdge], targetBorders[LeftEdge], - targetBorders[BottomEdge], targetBorders[RightEdge]); + QMargins sourceMargins(sourceBorders[LeftEdge], sourceBorders[TopEdge], + sourceBorders[RightEdge], sourceBorders[BottomEdge]); + QMargins targetMargins(targetBorders[LeftEdge], targetBorders[TopEdge], + targetBorders[RightEdge], targetBorders[BottomEdge]); bool wasSmoothPixmapTransform = p->renderHints() & QPainter::SmoothPixmapTransform; p->setRenderHint(QPainter::SmoothPixmapTransform); diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index b150f50..60e5296 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1589,27 +1589,54 @@ void QTextLine::setNumColumns(int numColumns, qreal alignmentWidth) #define LB_DEBUG if (0) qDebug #endif -static inline bool checkFullOtherwiseExtend(QScriptLine &line, QScriptLine &tmpData, QScriptLine &spaceData, - int glyphCount, int maxGlyphs, QFixed &minw, bool manualWrap, - QFixed softHyphenWidth = QFixed()) -{ +namespace { + + struct LineBreakHelper + { + LineBreakHelper() : glyphCount(0), maxGlyphs(0), manualWrap(false) {} + + QScriptLine tmpData; + QScriptLine spaceData; + + int glyphCount; + int maxGlyphs; + + QFixed minw; + QFixed softHyphenWidth; + QFixed rightBearing; + + bool manualWrap; + + bool checkFullOtherwiseExtend(QScriptLine &line); + }; + +inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) +{ LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); - if (line.length && !manualWrap && - (line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth > line.width || glyphCount > maxGlyphs)) + + QFixed newWidth = line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth + rightBearing; + if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs)) return true; + minw = qMax(minw, tmpData.textWidth); line += tmpData; line.textWidth += spaceData.textWidth; + line.length += spaceData.length; tmpData.textWidth = 0; tmpData.length = 0; spaceData.textWidth = 0; spaceData.length = 0; + return false; } +} // anonymous namespace + + static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount, - const QScriptItem ¤t, const unsigned short *logClusters, const QGlyphLayout &glyphs) + const QScriptItem ¤t, const unsigned short *logClusters, + const QGlyphLayout &glyphs) { int glyphPosition = logClusters[pos]; do { // got to the first next cluster @@ -1642,9 +1669,13 @@ void QTextLine::layout_helper(int maxGlyphs) Q_ASSERT(line.from < eng->layoutData->string.length()); + LineBreakHelper lbh; + + lbh.maxGlyphs = maxGlyphs; + QTextOption::WrapMode wrapMode = eng->option.wrapMode(); bool breakany = (wrapMode == QTextOption::WrapAnywhere); - bool manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap); + lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap); // #### binary search! int item = -1; @@ -1654,12 +1685,7 @@ void QTextLine::layout_helper(int maxGlyphs) break; } - QFixed minw = 0; - int glyphCount = 0; - LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); - QScriptLine tmpData; - QScriptLine spaceData; Qt::Alignment alignment = eng->option.alignment(); @@ -1668,7 +1694,10 @@ void QTextLine::layout_helper(int maxGlyphs) int end = 0; QGlyphLayout glyphs; const unsigned short *logClusters = eng->layoutData->logClustersPtr; + while (newItem < eng->layoutData->items.size()) { + lbh.rightBearing = 0; + lbh.softHyphenWidth = 0; if (newItem != item) { item = newItem; const QScriptItem ¤t = eng->layoutData->items[item]; @@ -1683,57 +1712,60 @@ void QTextLine::layout_helper(int maxGlyphs) } const QScriptItem ¤t = eng->layoutData->items[item]; - tmpData.ascent = qMax(tmpData.ascent, current.ascent); - tmpData.descent = qMax(tmpData.descent, current.descent); + lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent); + lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent); if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) { - if (checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap)) + if (lbh.checkFullOtherwiseExtend(line)) goto found; - QFixed x = line.x + line.textWidth + tmpData.textWidth + spaceData.textWidth; - spaceData.textWidth += eng->calculateTabWidth(item, x); - spaceData.length++; + QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth; + lbh.spaceData.textWidth += eng->calculateTabWidth(item, x); + lbh.spaceData.length++; newItem = item + 1; - ++glyphCount; - if (checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap)) + ++lbh.glyphCount; + if (lbh.checkFullOtherwiseExtend(line)) goto found; } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) { // if the line consists only of the line separator make sure // we have a sane height - if (!line.length && !tmpData.length) + if (!line.length && !lbh.tmpData.length) line.setDefaultHeight(eng); if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators) { - addNextCluster(pos, end, tmpData, glyphCount, current, logClusters, glyphs); + addNextCluster(pos, end, lbh.tmpData, lbh.glyphCount, + current, logClusters, glyphs); } else { - tmpData.length++; + lbh.tmpData.length++; } - line += tmpData; + line += lbh.tmpData; goto found; } else if (current.analysis.flags == QScriptAnalysis::Object) { - tmpData.length++; + lbh.tmpData.length++; QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item])); if (eng->block.docHandle()) eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format); - tmpData.textWidth += current.width; + lbh.tmpData.textWidth += current.width; newItem = item + 1; - ++glyphCount; - if (checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap)) + ++lbh.glyphCount; + if (lbh.checkFullOtherwiseExtend(line)) goto found; } else if (attributes[pos].whiteSpace) { while (pos < end && attributes[pos].whiteSpace) - addNextCluster(pos, end, spaceData, glyphCount, current, logClusters, glyphs); + addNextCluster(pos, end, lbh.spaceData, lbh.glyphCount, + current, logClusters, glyphs); - if (!manualWrap && spaceData.textWidth > line.width) { - spaceData.textWidth = line.width; // ignore spaces that fall out of the line. + if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) { + lbh.spaceData.textWidth = line.width; // ignore spaces that fall out of the line. goto found; } } else { bool sb_or_ws = false; do { - addNextCluster(pos, end, tmpData, glyphCount, current, logClusters, glyphs); + addNextCluster(pos, end, lbh.tmpData, lbh.glyphCount, + current, logClusters, glyphs); if (attributes[pos].whiteSpace || attributes[pos-1].lineBreakType != HB_NoBreak) { sb_or_ws = true; @@ -1742,9 +1774,8 @@ void QTextLine::layout_helper(int maxGlyphs) break; } } while (pos < end); - minw = qMax(tmpData.textWidth, minw); + lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw); - QFixed softHyphenWidth; if (pos && attributes[pos - 1].lineBreakType == HB_SoftHyphen) { // if we are splitting up a word because of // a soft hyphen then we ... @@ -1763,16 +1794,29 @@ void QTextLine::layout_helper(int maxGlyphs) // and thus become invisible again. // if (line.length) - softHyphenWidth = glyphs.advances_x[logClusters[pos - 1]]; + lbh.softHyphenWidth = glyphs.advances_x[logClusters[pos - 1]]; else if (breakany) - tmpData.textWidth += glyphs.advances_x[logClusters[pos - 1]]; + lbh.tmpData.textWidth += glyphs.advances_x[logClusters[pos - 1]]; } - if ((sb_or_ws|breakany) - && checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap, softHyphenWidth)) { + // The actual width of the text needs to take the right bearing into account. The + // right bearing is left-ward, which means that if the rightmost pixel is to the right + // of the advance of the glyph, the bearing will be negative. We flip the sign + // for the code to be more readable. Logic borrowed from qfontmetrics.cpp. + if (pos) { + QFontEngine *fontEngine = eng->fontEngine(current); + glyph_t glyph = glyphs.glyphs[logClusters[pos - 1]]; + glyph_metrics_t gi = fontEngine->boundingBox(glyph); + lbh.rightBearing = -qRound(gi.xoff - gi.x - gi.width); + } + + if ((sb_or_ws|breakany) && lbh.checkFullOtherwiseExtend(line)) { if (!breakany) { - line.textWidth += softHyphenWidth; + line.textWidth += lbh.softHyphenWidth; } + + line.textWidth += lbh.rightBearing; + goto found; } } @@ -1780,45 +1824,48 @@ void QTextLine::layout_helper(int maxGlyphs) newItem = item + 1; } LB_DEBUG("reached end of line"); - checkFullOtherwiseExtend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap); -found: + lbh.checkFullOtherwiseExtend(line); + line.textWidth += lbh.rightBearing; + +found: if (line.length == 0) { LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", - tmpData.length, tmpData.textWidth.toReal(), spaceData.length, spaceData.textWidth.toReal()); - line += tmpData; + lbh.tmpData.length, lbh.tmpData.textWidth.toReal(), + lbh.spaceData.length, lbh.spaceData.textWidth.toReal()); + line += lbh.tmpData; } LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(), - line.descent.toReal(), line.textWidth.toReal(), spaceData.width.toReal()); + line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal()); LB_DEBUG(" : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data()); - if (manualWrap) { + if (lbh.manualWrap) { eng->minWidth = qMax(eng->minWidth, line.textWidth); eng->maxWidth = qMax(eng->maxWidth, line.textWidth); } else { - eng->minWidth = qMax(eng->minWidth, minw); + eng->minWidth = qMax(eng->minWidth, lbh.minw); eng->maxWidth += line.textWidth; } if (line.textWidth > 0 && item < eng->layoutData->items.size()) - eng->maxWidth += spaceData.textWidth; + eng->maxWidth += lbh.spaceData.textWidth; if (eng->option.flags() & QTextOption::IncludeTrailingSpaces) - line.textWidth += spaceData.textWidth; - line.length += spaceData.length; - if (spaceData.length) + line.textWidth += lbh.spaceData.textWidth; + line.length += lbh.spaceData.length; + if (lbh.spaceData.length) line.hasTrailingSpaces = true; line.justified = false; line.gridfitted = false; if (eng->option.wrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere) { - if ((maxGlyphs != INT_MAX && glyphCount > maxGlyphs) - || (maxGlyphs == INT_MAX && line.textWidth > line.width)) { + if ((lbh.maxGlyphs != INT_MAX && lbh.glyphCount > lbh.maxGlyphs) + || (lbh.maxGlyphs == INT_MAX && line.textWidth > line.width)) { eng->option.setWrapMode(QTextOption::WrapAnywhere); line.length = 0; line.textWidth = 0; - layout_helper(maxGlyphs); + layout_helper(lbh.maxGlyphs); eng->option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); } } diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index a81f138..f46abf1 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -109,6 +109,7 @@ public: int width() const; int height() const; int ascent() const; + qreal naturalTextWidth() const; void setSelection(int start, int length); @@ -410,6 +411,11 @@ inline int QLineControl::width() const return qRound(m_textLayout.lineAt(0).width()) + 1; } +inline qreal QLineControl::naturalTextWidth() const +{ + return m_textLayout.lineAt(0).naturalTextWidth(); +} + inline int QLineControl::height() const { return qRound(m_textLayout.lineAt(0).height()) + 1; diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 3065c7f..9571860 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1808,7 +1808,7 @@ void QLineEdit::paintEvent(QPaintEvent *) // (cix). int minLB = qMax(0, -fm.minLeftBearing()); int minRB = qMax(0, -fm.minRightBearing()); - int widthUsed = d->control->width() + minRB; + int widthUsed = qRound(d->control->naturalTextWidth()) + 1 + minRB; if ((minLB + widthUsed) <= lineRect.width()) { // text fits in lineRect; use hscroll for alignment switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp index d8d974f..5de5c27 100644 --- a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp +++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp @@ -341,8 +341,6 @@ QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode) QList<QByteArray> devices; - devices.append("default"); - if(mode == QAudio::AudioOutput) { WAVEOUTCAPS woc; unsigned long iNumDevs,i; @@ -365,6 +363,9 @@ QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode) } } + if(devices.count() > 0) + devices.append("default"); + return devices; } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index e24539b..e028e63 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -710,7 +710,7 @@ void QGL2PaintEngineEx::beginNativePainting() { mtx.dx(), mtx.dy(), 0, mtx.m33() } }; - const QSize sz = d->drawable.size(); + const QSize sz = d->device->size(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -1308,21 +1308,20 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) Q_D(QGL2PaintEngineEx); // qDebug("QGL2PaintEngineEx::begin()"); - d->drawable.setDevice(pdev); - d->ctx = d->drawable.context(); - - if (d->ctx->d_ptr->active_engine) { - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->ctx->d_ptr->active_engine); - QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr.data()); - p->transferMode(BrushDrawingMode); - p->drawable.doneCurrent(); - } + if (pdev->devType() == QInternal::OpenGL) + d->device = static_cast<QGLPaintDevice*>(pdev); + else + d->device = QGLPaintDevice::getDevice(pdev); + + if (!d->device) + return false; + + d->ctx = d->device->context(); d->ctx->d_ptr->active_engine = this; d->last_created_state = 0; - d->drawable.makeCurrent(); - QSize sz = d->drawable.size(); + QSize sz = d->device->size(); d->width = sz.width(); d->height = sz.height(); d->mode = BrushDrawingMode; @@ -1333,8 +1332,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->shaderManager = new QGLEngineShaderManager(d->ctx); - glViewport(0, 0, d->width, d->height); - d->brushTextureDirty = true; d->brushUniformsDirty = true; d->matrixDirty = true; @@ -1343,10 +1340,12 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->simpleShaderDepthUniformDirty = true; d->depthUniformDirty = true; d->opacityUniformDirty = true; - d->needsSync = false; - + d->needsSync = true; d->use_system_clip = !systemClip().isEmpty(); + + d->device->beginPaint(); + if (!d->inRenderText) { glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); @@ -1358,30 +1357,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) glDisable(GL_MULTISAMPLE); #endif - QGLPixmapData *source = d->drawable.copyOnBegin(); - if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) { - if (d->drawable.hasTransparentBackground()) - glClearColor(0.0, 0.0, 0.0, 0.0); - else { - const QColor &c = d->drawable.backgroundColor(); - float alpha = c.alphaF(); - glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); - } - glClear(GL_COLOR_BUFFER_BIT); - } else if (source) { - QGLContext *ctx = d->ctx; - - d->transferMode(ImageDrawingMode); - - glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - source->bind(false); - - QRect rect(0, 0, source->width(), source->height()); - d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); - d->drawTexture(QRectF(rect), QRectF(rect), rect.size(), true); - } - - d->systemStateChanged(); return true; } @@ -1389,19 +1364,11 @@ bool QGL2PaintEngineEx::end() { Q_D(QGL2PaintEngineEx); QGLContext *ctx = d->ctx; - if (ctx->d_ptr->active_engine != this) { - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine); - if (engine && engine->isActive()) { - QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr.data()); - p->transferMode(BrushDrawingMode); - p->drawable.doneCurrent(); - } - d->drawable.makeCurrent(); - } glUseProgram(0); d->transferMode(BrushDrawingMode); - d->drawable.swapBuffers(); + d->device->endPaint(); + #if defined(Q_WS_X11) // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes @@ -1410,7 +1377,6 @@ bool QGL2PaintEngineEx::end() // them here, after swapBuffers, where they can be safely deleted. ctx->d_func()->boundPixmaps.clear(); #endif - d->drawable.doneCurrent(); d->ctx->d_ptr->active_engine = 0; d->resetGLState(); @@ -1427,21 +1393,12 @@ void QGL2PaintEngineEx::ensureActive() QGLContext *ctx = d->ctx; if (isActive() && ctx->d_ptr->active_engine != this) { - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine); - if (engine && engine->isActive()) { - QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr.data()); - p->transferMode(BrushDrawingMode); - p->drawable.doneCurrent(); - } - d->drawable.context()->makeCurrent(); - d->drawable.makeCurrent(); - ctx->d_ptr->active_engine = this; d->needsSync = true; - } else { - d->drawable.context()->makeCurrent(); } + d->device->ensureActiveTarget(); + if (d->needsSync) { glViewport(0, 0, d->width, d->height); glDepthMask(false); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index cb23b11..2fbee1b 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -58,6 +58,7 @@ #include <private/qpaintengineex_p.h> #include <private/qglengineshadermanager_p.h> #include <private/qgl2pexvertexarray_p.h> +#include <private/qglpaintdevice_p.h> enum EngineMode { ImageDrawingMode, @@ -199,7 +200,7 @@ public: static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; } QGL2PaintEngineEx* q; - QGLDrawable drawable; + QGLPaintDevice* device; int width, height; QGLContext *ctx; EngineMode mode; diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 560d31f..d479c2e 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -22,13 +22,18 @@ HEADERS += qgl.h \ qglpixelbuffer.h \ qglpixelbuffer_p.h \ qglframebufferobject.h \ - qglextensions_p.h + qglframebufferobject_p.h \ + qglextensions_p.h \ + qglpaintdevice_p.h \ + SOURCES += qgl.cpp \ qglcolormap.cpp \ qglpixelbuffer.cpp \ qglframebufferobject.cpp \ qglextensions.cpp \ + qglpaintdevice.cpp \ + !contains(QT_CONFIG, opengles2) { HEADERS += qpaintengine_opengl_p.h diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 087902b..a0b2d3a 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -141,6 +141,48 @@ QGLSignalProxy *QGLSignalProxy::instance() return theSignalProxy(); } + +class QGLEngineSelector +{ +public: + QGLEngineSelector() : engineType(QPaintEngine::MaxUser) { } + + void setPreferredPaintEngine(QPaintEngine::Type type) { + if (type == QPaintEngine::OpenGL || type == QPaintEngine::OpenGL2) + engineType = type; + } + + QPaintEngine::Type preferredPaintEngine() { + if (engineType == QPaintEngine::MaxUser) { + // No user-set engine - use the defaults +#if defined(QT_OPENGL_ES_2) + engineType = QPaintEngine::OpenGL2; +#else + // We can't do this in the constructor for this object because it + // needs to be called *before* the QApplication constructor + if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) + && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty()) + engineType = QPaintEngine::OpenGL2; + else + engineType = QPaintEngine::OpenGL; +#endif + } + return engineType; + } + +private: + QPaintEngine::Type engineType; +}; + +Q_GLOBAL_STATIC(QGLEngineSelector, qgl_engine_selector) + + +bool qt_gl_preferGL2Engine() +{ + return qgl_engine_selector()->preferredPaintEngine() == QPaintEngine::OpenGL2; +} + + /*! \namespace QGL \inmodule QtOpenGL @@ -181,6 +223,32 @@ QGLSignalProxy *QGLSignalProxy::instance() \sa {Sample Buffers Example} */ +/*! + \fn void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType) + + \since 4.6 + + Sets the preferred OpenGL paint engine that is used to draw onto + QGLWidgets, QGLPixelBuffers and QGLFrameBufferObjects with QPainter + in Qt. + + The \a engineType parameter specifies which of the GL engines to + use. Only \c QPaintEngine::OpenGL and \c QPaintEngine::OpenGL2 are + valid parameters to this function. All other values are ignored. + + By default, the \c QPaintEngine::OpenGL2 engine is used if GL/GLES + version 2.0 is available, otherwise \c QPaintEngine::OpenGL is + used. + + \warning This function must be called before the QApplication + constructor is called. +*/ +void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType) +{ + qgl_engine_selector()->setPreferredPaintEngine(engineType); +} + + /***************************************************************************** QGLFormat implementation *****************************************************************************/ @@ -1331,7 +1399,6 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) crWin = false; initDone = false; sharing = false; - clear_on_painter_begin = true; max_texture_size = -1; version_flags_cached = false; version_flags = QGLFormat::OpenGL_Version_None; @@ -4186,7 +4253,7 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, } else { setAutoBufferSwap(false); // disable glClear() as a result of QPainter::begin() - d->glcx->d_func()->clear_on_painter_begin = false; + d->disable_clear_on_painter_begin = true; if (engine->type() == QPaintEngine::OpenGL2) { qt_save_gl_state(); #ifndef QT_OPENGL_ES_2 @@ -4216,7 +4283,7 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, p->end(); delete p; setAutoBufferSwap(auto_swap); - d->glcx->d_func()->clear_on_painter_begin = true; + d->disable_clear_on_painter_begin = false; if (engine->type() == QPaintEngine::OpenGL2) qt_restore_gl_state(); } @@ -4359,7 +4426,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con } else { setAutoBufferSwap(false); // disable glClear() as a result of QPainter::begin() - d->glcx->d_func()->clear_on_painter_begin = false; + d->disable_clear_on_painter_begin = true; if (engine->type() == QPaintEngine::OpenGL2) qt_save_gl_state(); p = new QPainter(this); @@ -4399,7 +4466,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con if (engine->type() == QPaintEngine::OpenGL2) qt_restore_gl_state(); setAutoBufferSwap(auto_swap); - d->glcx->d_func()->clear_on_painter_begin = true; + d->disable_clear_on_painter_begin = false; } #ifndef QT_OPENGL_ES if (engine->type() == QPaintEngine::OpenGL2) @@ -4747,6 +4814,8 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi { Q_Q(QGLWidget); + glDevice.setWidget(q); + QGLExtensions::init(); glcx = 0; autoSwap = true; @@ -4782,242 +4851,6 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name() } #endif -void QGLDrawable::setDevice(QPaintDevice *pdev) -{ - wasBound = false; - widget = 0; - buffer = 0; - fbo = 0; -#ifdef Q_WS_QWS - wsurf = 0; -#endif - -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - if (pdev->devType() == QInternal::Pixmap) { - QPixmapData *data = static_cast<QPixmap *>(pdev)->pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::OpenGLClass); - pixmapData = static_cast<QGLPixmapData *>(data); - - fbo = pixmapData->fbo(); - } -#else - Q_ASSERT(pdev->devType() != QInternal::Pixmap); -#endif - - if (pdev->devType() == QInternal::Widget) - widget = static_cast<QGLWidget *>(pdev); - else if (pdev->devType() == QInternal::Pbuffer) - buffer = static_cast<QGLPixelBuffer *>(pdev); - else if (pdev->devType() == QInternal::FramebufferObject) - fbo = static_cast<QGLFramebufferObject *>(pdev); -#ifdef Q_WS_QWS - else if (pdev->devType() == QInternal::UnknownDevice) - wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface(); -#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - else if (pdev->devType() == QInternal::UnknownDevice) - wsurf = static_cast<QGLWindowSurface *>(pdev); -#endif -} - -void QGLDrawable::swapBuffers() -{ - if (widget) { - if (widget->autoBufferSwap()) - widget->swapBuffers(); -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - } else if (pixmapData) { - pixmapData->swapBuffers(); -#endif - } else { - glFlush(); - } -} - -void QGLDrawable::makeCurrent() -{ - previous_fbo = 0; -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - if (!pixmapData && !fbo) { -#else - if (!fbo) { -#endif - QGLContext *ctx = context(); - previous_fbo = ctx->d_ptr->current_fbo; - ctx->d_ptr->current_fbo = 0; - if (previous_fbo) - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - } - - if (widget) - widget->makeCurrent(); -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - else if (pixmapData) - pixmapData->makeCurrent(); -#endif - else if (buffer) - buffer->makeCurrent(); -#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) - else if (wsurf) - wsurf->context()->makeCurrent(); -#endif - else if (fbo) { - wasBound = fbo->isBound(); - if (!wasBound) - fbo->bind(); - } -} - -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) -QGLPixmapData *QGLDrawable::copyOnBegin() const -{ - if (!pixmapData || pixmapData->isUninitialized()) - return 0; - return pixmapData; -} -#endif - -void QGLDrawable::doneCurrent() -{ -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - if (pixmapData) { - pixmapData->doneCurrent(); - return; - } -#endif - - if (previous_fbo) { - QGLContext *ctx = context(); - ctx->d_ptr->current_fbo = previous_fbo; - glBindFramebuffer(GL_FRAMEBUFFER_EXT, previous_fbo); - } - - if (fbo && !wasBound) - fbo->release(); -} - -QSize QGLDrawable::size() const -{ - if (widget) { - return QSize(widget->d_func()->glcx->device()->width(), - widget->d_func()->glcx->device()->height()); -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - } else if (pixmapData) { - return pixmapData->size(); -#endif - } else if (buffer) { - return buffer->size(); - } else if (fbo) { - return fbo->size(); - } -#ifdef Q_WS_QWS - else if (wsurf) - return wsurf->window()->frameSize(); -#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - else if (wsurf) - return QSize(wsurf->width(), wsurf->height()); -#endif - return QSize(); -} - -QGLFormat QGLDrawable::format() const -{ - if (widget) - return widget->format(); - else if (buffer) - return buffer->format(); -#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) - else if (wsurf) - return wsurf->context()->format(); -#endif - else if (fbo && QGLContext::currentContext()) { - QGLFormat fmt = QGLContext::currentContext()->format(); - fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil); - fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment); - return fmt; - } - - return QGLFormat(); -} - -GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format, - QGLContext::BindOptions options) -{ - QGLTexture *texture = 0; - options |= QGLContext::MemoryManagedBindOption; - if (widget) - texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, options); - else if (buffer) - texture = buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, options); - else if (fbo && QGLContext::currentContext()) - texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, options); -#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) - else if (wsurf) - texture = wsurf->context()->d_func()->bindTexture(image, target, format, options); -#endif - return texture->id; -} - -GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, - QGLContext::BindOptions options) -{ - QGLTexture *texture = 0; - if (widget) - texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, options); - else if (buffer) - texture = buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, options); - else if (fbo && QGLContext::currentContext()) - texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, options); -#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) - else if (wsurf) - texture = wsurf->context()->d_func()->bindTexture(pixmap, target, format, options); -#endif - return texture->id; -} - -QColor QGLDrawable::backgroundColor() const -{ - if (widget) - return widget->palette().brush(widget->backgroundRole()).color(); -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - else if (pixmapData) - return pixmapData->fillColor(); -#endif - return QApplication::palette().brush(QPalette::Background).color(); -} - -bool QGLDrawable::hasTransparentBackground() const -{ - return widget && widget->testAttribute(Qt::WA_TranslucentBackground); -} - -QGLContext *QGLDrawable::context() const -{ - if (widget) - return widget->d_func()->glcx; - else if (buffer) - return buffer->d_func()->qctx; - else if (fbo) - return const_cast<QGLContext *>(QGLContext::currentContext()); -#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) - else if (wsurf) - return wsurf->context(); -#endif - return 0; -} - -bool QGLDrawable::autoFillBackground() const -{ - if (widget) - return widget->autoFillBackground(); -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - else if (pixmapData) - return pixmapData->needsFill(); -#endif - else - return false; -} - - bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) { bool sharing = (context1 && context2 && context1->d_ptr->group == context2->d_ptr->group); return sharing; diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index daac760..151c7c4 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -43,6 +43,7 @@ #define QGL_H #include <QtGui/qwidget.h> +#include <QtGui/qpaintengine.h> #include <QtOpenGL/qglcolormap.h> #include <QtCore/qmap.h> #include <QtCore/qscopedpointer.h> @@ -130,6 +131,8 @@ class QGLContextPrivate; // Namespace class: namespace QGL { + Q_OPENGL_EXPORT void setPreferredPaintEngine(QPaintEngine::Type engineType); + enum FormatOption { DoubleBuffer = 0x0001, DepthBuffer = 0x0002, @@ -382,7 +385,6 @@ private: friend class QGLPixelBuffer; friend class QGLPixelBufferPrivate; friend class QGLWidget; - friend class QGLDrawable; friend class QGLWidgetPrivate; friend class QGLGlyphCache; friend class QOpenGLPaintEngine; @@ -404,6 +406,8 @@ private: #endif friend class QGLFramebufferObject; friend class QGLFramebufferObjectPrivate; + friend class QGLFBOGLPaintDevice; + friend class QGLPaintDevice; private: Q_DISABLE_COPY(QGLContext) }; @@ -539,6 +543,8 @@ private: friend class QGLContext; friend class QGLOverlayWidget; friend class QOpenGLPaintEngine; + friend class QGLPaintDevice; + friend class QGLWidgetGLPaintDevice; }; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index d4b7597..b10d5da 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -62,6 +62,7 @@ #include "QtCore/qatomic.h" #include "private/qwidget_p.h" #include "qcache.h" +#include "qglpaintdevice_p.h" #ifndef QT_OPENGL_ES_1_CL #define q_vertexType float @@ -174,6 +175,7 @@ class QGLWidgetPrivate : public QWidgetPrivate Q_DECLARE_PUBLIC(QGLWidget) public: QGLWidgetPrivate() : QWidgetPrivate() + , disable_clear_on_painter_begin(false) #ifdef Q_WS_QWS , wsurf(0) #endif @@ -190,11 +192,14 @@ public: void cleanupColormaps(); QGLContext *glcx; + QGLWidgetGLPaintDevice glDevice; bool autoSwap; QGLColormap cmap; QMap<QString, int> displayListCache; + bool disable_clear_on_painter_begin; + #if defined(Q_WS_WIN) void updateColormap(); QGLContext *olcx; @@ -293,7 +298,6 @@ public: uint sharing : 1; uint initDone : 1; uint crWin : 1; - uint clear_on_painter_begin : 1; uint internal_context : 1; uint version_flags_cached : 1; QPaintDevice *paintDevice; @@ -337,57 +341,6 @@ Q_SIGNALS: void aboutToDestroyContext(const QGLContext *context); }; -class QGLPixelBuffer; -class QGLFramebufferObject; -class QWSGLWindowSurface; -class QGLWindowSurface; -class QGLPixmapData; -class QGLDrawable { -public: - QGLDrawable() : widget(0), buffer(0), fbo(0) -#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)) - , wsurf(0) -#endif -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - , pixmapData(0) -#endif - {} - void setDevice(QPaintDevice *pdev); - void swapBuffers(); - void makeCurrent(); - void doneCurrent(); - QSize size() const; - QGLFormat format() const; - GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA, - QGLContext::BindOptions = QGLContext::InternalBindOption); - GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA, - QGLContext::BindOptions = QGLContext::InternalBindOption); - QColor backgroundColor() const; - QGLContext *context() const; - bool autoFillBackground() const; - bool hasTransparentBackground() const; - -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - QGLPixmapData *copyOnBegin() const; -#endif - -private: - bool wasBound; - QGLWidget *widget; - QGLPixelBuffer *buffer; - QGLFramebufferObject *fbo; -#ifdef Q_WS_QWS - QWSGLWindowSurface *wsurf; -#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - QGLWindowSurface *wsurf; -#endif - -#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) - QGLPixmapData *pixmapData; -#endif - int previous_fbo; -}; - // GL extension definitions class QGLExtensions { public: @@ -519,15 +472,7 @@ extern QPaintEngine* qt_qgl_paint_engine(); extern EGLDisplay qt_qgl_egl_display(); #endif -inline bool qt_gl_preferGL2Engine() -{ -#if defined(QT_OPENGL_ES_2) - return true; -#else - return (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) - && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty(); -#endif -} +bool qt_gl_preferGL2Engine(); inline GLenum qt_gl_preferredTextureFormat() { diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index 81985cd..a7376b2 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -1308,7 +1308,6 @@ void QGLWidget::setContext(QGLContext *context, QGLContext* oldcx = d->glcx; d->glcx = context; - if (parentWidget()) { // force creation of delay-created widgets parentWidget()->winId(); diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 452f155..9dbf5c8 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qglframebufferobject.h" +#include "qglframebufferobject_p.h" #include <qdebug.h> #include <private/qgl_p.h> @@ -74,40 +75,6 @@ extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); } \ } -#ifndef QT_OPENGL_ES -#define DEFAULT_FORMAT GL_RGBA8 -#else -#define DEFAULT_FORMAT GL_RGBA -#endif - -class QGLFramebufferObjectFormatPrivate -{ -public: - QGLFramebufferObjectFormatPrivate() - : ref(1), - samples(0), - attachment(QGLFramebufferObject::NoAttachment), - target(GL_TEXTURE_2D), - internal_format(DEFAULT_FORMAT) - { - } - QGLFramebufferObjectFormatPrivate - (const QGLFramebufferObjectFormatPrivate *other) - : ref(1), - samples(other->samples), - attachment(other->attachment), - target(other->target), - internal_format(other->internal_format) - { - } - - QAtomicInt ref; - int samples; - QGLFramebufferObject::Attachment attachment; - GLenum target; - GLenum internal_format; -}; - /*! \class QGLFramebufferObjectFormat \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL @@ -311,28 +278,59 @@ void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum inter } #endif -class QGLFramebufferObjectPrivate +/*! + Returns true if all the options of this framebuffer object format + are the same as \a other; otherwise returns false. +*/ +bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const +{ + if (d == other.d) + return true; + else + return d->equals(other.d); +} + +/*! + Returns false if all the options of this framebuffer object format + are the same as \a other; otherwise returns true. +*/ +bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const +{ + return !(*this == other); +} + +void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f) +{ + fbo = f; + m_thisFBO = fbo->d_func()->fbo; // This shouldn't be needed +} + +void QGLFBOGLPaintDevice::ensureActiveTarget() { -public: - QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), ctx(0), previous_fbo(0), engine(0) {} - ~QGLFramebufferObjectPrivate() {} - - void init(const QSize& sz, QGLFramebufferObject::Attachment attachment, - GLenum internal_format, GLenum texture_target, GLint samples = 0); - bool checkFramebufferStatus() const; - GLuint texture; - GLuint fbo; - GLuint depth_stencil_buffer; - GLuint color_buffer; - GLenum target; - QSize size; - QGLFramebufferObjectFormat format; - uint valid : 1; - QGLFramebufferObject::Attachment fbo_attachment; - QGLContextGroup *ctx; // for Windows extension ptrs - GLuint previous_fbo; - mutable QPaintEngine *engine; -}; + QGLContext* ctx = const_cast<QGLContext*>(QGLContext::currentContext()); + Q_ASSERT(ctx); + const GLuint fboId = fbo->d_func()->fbo; + if (ctx->d_func()->current_fbo != fboId) { + ctx->d_func()->current_fbo = fboId; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId); + } +} + +void QGLFBOGLPaintDevice::beginPaint() +{ + // We let QFBO track the previously bound FBO rather than doing it + // ourselves here. This has the advantage that begin/release & bind/end + // work as expected. + wasBound = fbo->isBound(); + if (!wasBound) + fbo->bind(); +} + +void QGLFBOGLPaintDevice::endPaint() +{ + if (!wasBound) + fbo->release(); +} bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const { @@ -378,11 +376,14 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const return false; } -void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment, +void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, + QGLFramebufferObject::Attachment attachment, GLenum texture_target, GLenum internal_format, GLint samples) { QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); ctx = QGLContextPrivate::contextGroup(currentContext); + glDevice.setFBO(q); + bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(currentContext))) return; @@ -395,6 +396,8 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo); + glDevice.setFBO(q); + QT_CHECK_GLERROR(); // init texture if (samples == 0) { @@ -641,7 +644,8 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target) : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(size, NoAttachment, target, DEFAULT_FORMAT); + d->glDevice.setFBO(this); + d->init(this, size, NoAttachment, target, DEFAULT_FORMAT); } #ifdef Q_MAC_COMPAT_GL_FUNCTIONS @@ -665,7 +669,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target) : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); + d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); } /*! \overload @@ -678,7 +682,8 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebuff : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(size, format.attachment(), format.textureTarget(), format.internalTextureFormat(), format.samples()); + d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(), + format.samples()); } /*! \overload @@ -691,7 +696,8 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFrame : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(QSize(width, height), format.attachment(), format.textureTarget(), format.internalTextureFormat(), format.samples()); + d->init(this, QSize(width, height), format.attachment(), format.textureTarget(), + format.internalTextureFormat(), format.samples()); } #ifdef Q_MAC_COMPAT_GL_FUNCTIONS @@ -700,7 +706,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLen : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); + d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); } #endif @@ -721,7 +727,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(QSize(width, height), attachment, target, internal_format); + d->init(this, QSize(width, height), attachment, target, internal_format); } #ifdef Q_MAC_COMPAT_GL_FUNCTIONS @@ -731,7 +737,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(QSize(width, height), attachment, target, internal_format); + d->init(this, QSize(width, height), attachment, target, internal_format); } #endif @@ -752,7 +758,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(size, attachment, target, internal_format); + d->init(this, size, attachment, target, internal_format); } #ifdef Q_MAC_COMPAT_GL_FUNCTIONS @@ -762,7 +768,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm : d_ptr(new QGLFramebufferObjectPrivate) { Q_D(QGLFramebufferObject); - d->init(size, attachment, target, internal_format); + d->init(this, size, attachment, target, internal_format); } #endif diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h index 6c1c0be..6efbb73 100644 --- a/src/opengl/qglframebufferobject.h +++ b/src/opengl/qglframebufferobject.h @@ -130,7 +130,8 @@ protected: private: Q_DISABLE_COPY(QGLFramebufferObject) QScopedPointer<QGLFramebufferObjectPrivate> d_ptr; - friend class QGLDrawable; + friend class QGLPaintDevice; + friend class QGLFBOGLPaintDevice; }; class QGLFramebufferObjectFormatPrivate; @@ -159,6 +160,9 @@ public: void setInternalTextureFormat(QMacCompatGLenum internalTextureFormat); #endif + bool operator==(const QGLFramebufferObjectFormat& other) const; + bool operator!=(const QGLFramebufferObjectFormat& other) const; + private: QGLFramebufferObjectFormatPrivate *d; diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h new file mode 100644 index 0000000..58e6505 --- /dev/null +++ b/src/opengl/qglframebufferobject_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGLFRAMEBUFFEROBJECT_P_H +#define QGLFRAMEBUFFEROBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +QT_BEGIN_INCLUDE_NAMESPACE + +#include <qglframebufferobject.h> +#include <private/qglpaintdevice_p.h> +#include <private/qgl_p.h> + +QT_END_INCLUDE_NAMESPACE + +#ifndef QT_OPENGL_ES +#define DEFAULT_FORMAT GL_RGBA8 +#else +#define DEFAULT_FORMAT GL_RGBA +#endif + +class QGLFramebufferObjectFormatPrivate +{ +public: + QGLFramebufferObjectFormatPrivate() + : ref(1), + samples(0), + attachment(QGLFramebufferObject::NoAttachment), + target(GL_TEXTURE_2D), + internal_format(DEFAULT_FORMAT) + { + } + QGLFramebufferObjectFormatPrivate + (const QGLFramebufferObjectFormatPrivate *other) + : ref(1), + samples(other->samples), + attachment(other->attachment), + target(other->target), + internal_format(other->internal_format) + { + } + bool equals(const QGLFramebufferObjectFormatPrivate *other) + { + return samples == other->samples && + attachment == other->attachment && + target == other->target && + internal_format == other->internal_format; + } + + QAtomicInt ref; + int samples; + QGLFramebufferObject::Attachment attachment; + GLenum target; + GLenum internal_format; +}; + +class QGLFBOGLPaintDevice : public QGLPaintDevice +{ +public: + virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();} + virtual QSize size() const {return fbo->size();} + virtual QGLContext* context() const {return const_cast<QGLContext *>(QGLContext::currentContext());} + virtual void ensureActiveTarget(); + virtual void beginPaint(); + virtual void endPaint(); + + void setFBO(QGLFramebufferObject* f); + +private: + bool wasBound; + QGLFramebufferObject* fbo; +}; + +class QGLFramebufferObjectPrivate +{ +public: + QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), ctx(0), previous_fbo(0), engine(0) {} + ~QGLFramebufferObjectPrivate() {} + + void init(QGLFramebufferObject *q, const QSize& sz, + QGLFramebufferObject::Attachment attachment, + GLenum internal_format, GLenum texture_target, GLint samples = 0); + bool checkFramebufferStatus() const; + GLuint texture; + GLuint fbo; + GLuint depth_stencil_buffer; + GLuint color_buffer; + GLenum target; + QSize size; + QGLFramebufferObjectFormat format; + uint valid : 1; + QGLFramebufferObject::Attachment fbo_attachment; + QGLContextGroup *ctx; // for Windows extension ptrs + GLuint previous_fbo; + mutable QPaintEngine *engine; + QGLFBOGLPaintDevice glDevice; +}; + + +QT_END_NAMESPACE + +#endif // QGLFRAMEBUFFEROBJECT_P_H diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp new file mode 100644 index 0000000..a89b884 --- /dev/null +++ b/src/opengl/qglpaintdevice.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qglpaintdevice_p.h> +#include <private/qgl_p.h> +#include <private/qglpixelbuffer_p.h> +#include <private/qglframebufferobject_p.h> +#include <private/qwindowsurface_gl_p.h> +#include <private/qpixmapdata_gl_p.h> + +QT_BEGIN_NAMESPACE + +QGLPaintDevice::QGLPaintDevice() + : m_thisFBO(0) +{ +} + +QGLPaintDevice::~QGLPaintDevice() +{ +} + + +void QGLPaintDevice::beginPaint() +{ + // Make sure our context is the current one: + QGLContext *ctx = context(); + if (ctx != QGLContext::currentContext()) + ctx->makeCurrent(); + + // Record the currently bound FBO so we can restore it again + // in endPaint() and bind this device's FBO + m_previousFBO = ctx->d_func()->current_fbo; + if (m_previousFBO != m_thisFBO) { + ctx->d_ptr->current_fbo = m_thisFBO; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO); + } +} + +void QGLPaintDevice::ensureActiveTarget() +{ + QGLContext* ctx = context(); + if (ctx != QGLContext::currentContext()) + ctx->makeCurrent(); + + if (ctx->d_ptr->current_fbo != m_thisFBO) { + ctx->d_ptr->current_fbo = m_thisFBO; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO); + } +} + +void QGLPaintDevice::endPaint() +{ + // Make sure the FBO bound at beginPaint is re-bound again here: + QGLContext *ctx = context(); + if (m_previousFBO != ctx->d_func()->current_fbo) { + ctx->d_ptr->current_fbo = m_previousFBO; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_previousFBO); + } +} + +QGLFormat QGLPaintDevice::format() const +{ + return context()->format(); +} + + + + +////////////////// QGLWidgetGLPaintDevice ////////////////// + +QGLWidgetGLPaintDevice::QGLWidgetGLPaintDevice() +{ +} + +QPaintEngine* QGLWidgetGLPaintDevice::paintEngine() const +{ + return glWidget->paintEngine(); +} + +void QGLWidgetGLPaintDevice::setWidget(QGLWidget* w) +{ + glWidget = w; +} + +void QGLWidgetGLPaintDevice::beginPaint() +{ + QGLPaintDevice::beginPaint(); + if (!glWidget->d_func()->disable_clear_on_painter_begin && glWidget->autoFillBackground()) { + if (glWidget->testAttribute(Qt::WA_TranslucentBackground)) + glClearColor(0.0, 0.0, 0.0, 0.0); + else { + const QColor &c = glWidget->palette().brush(glWidget->backgroundRole()).color(); + float alpha = c.alphaF(); + glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + } + glClear(GL_COLOR_BUFFER_BIT); + } +} + +void QGLWidgetGLPaintDevice::endPaint() +{ + if (glWidget->autoBufferSwap()) + glWidget->swapBuffers(); + QGLPaintDevice::endPaint(); +} + + +QSize QGLWidgetGLPaintDevice::size() const +{ + return glWidget->size(); +} + +QGLContext* QGLWidgetGLPaintDevice::context() const +{ + return const_cast<QGLContext*>(glWidget->context()); +} + +// returns the QGLPaintDevice for the given QPaintDevice +QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd) +{ + QGLPaintDevice* glpd = 0; + + switch(pd->devType()) { + case QInternal::Widget: + // Should not be called on a non-gl widget: + Q_ASSERT(qobject_cast<QGLWidget*>(static_cast<QWidget*>(pd))); + glpd = &(static_cast<QGLWidget*>(pd)->d_func()->glDevice); + break; + case QInternal::Pbuffer: + glpd = &(static_cast<QGLPixelBuffer*>(pd)->d_func()->glDevice); + break; + case QInternal::FramebufferObject: + glpd = &(static_cast<QGLFramebufferObject*>(pd)->d_func()->glDevice); + break; + case QInternal::Pixmap: { + QPixmapData* pmd = static_cast<QPixmap*>(pd)->pixmapData(); + Q_ASSERT(pmd->classId() == QPixmapData::OpenGLClass); + glpd = static_cast<QGLPixmapData*>(pmd)->glDevice(); + break; + } + default: + qWarning("QGLPaintDevice::getDevice() - Unknown device type %d", pd->devType()); + break; + } + + return glpd; +} + +QT_END_NAMESPACE diff --git a/src/opengl/qglpaintdevice_p.h b/src/opengl/qglpaintdevice_p.h new file mode 100644 index 0000000..32a1275 --- /dev/null +++ b/src/opengl/qglpaintdevice_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGLPAINTDEVICE_P_H +#define QGLPAINTDEVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QtOpenGL module. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + + +#include <qpaintdevice.h> +#include <qgl.h> + + +QT_BEGIN_NAMESPACE + +class QGLPaintDevice : public QPaintDevice +{ +public: + QGLPaintDevice(); + virtual ~QGLPaintDevice(); + + int devType() const {return QInternal::OpenGL;} + + virtual void beginPaint(); + virtual void ensureActiveTarget(); + virtual void endPaint(); + + virtual QGLContext* context() const = 0; + QGLFormat format() const; + virtual QSize size() const = 0; + + // returns the QGLPaintDevice for the given QPaintDevice + static QGLPaintDevice* getDevice(QPaintDevice*); + +protected: + GLuint m_previousFBO; + GLuint m_thisFBO; +}; + + +// Wraps a QGLWidget +class QGLWidget; +class QGLWidgetGLPaintDevice : public QGLPaintDevice +{ +public: + QGLWidgetGLPaintDevice(); + + virtual QPaintEngine* paintEngine() const; + + // QGLWidgets need to do swapBufers in endPaint: + virtual void beginPaint(); + virtual void endPaint(); + virtual QSize size() const; + virtual QGLContext* context() const; + + void setWidget(QGLWidget*); + +private: + friend class QGLWidget; + QGLWidget *glWidget; +}; + +QT_END_NAMESPACE + +#endif // QGLPAINTDEVICE_P_H diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index f082ff0..b6a919c 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -100,6 +100,22 @@ void qgl_cleanup_glyph_cache(QGLContext *) {} extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); + +QGLContext* QGLPBufferGLPaintDevice::context() const +{ + return pbuf->d_func()->qctx; +} + +void QGLPBufferGLPaintDevice::endPaint() { + glFlush(); + QGLPaintDevice::endPaint(); +} + +void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb) +{ + pbuf = pb; +} + void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget) { Q_Q(QGLPixelBuffer); @@ -115,6 +131,7 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form shareWidget->d_func()->glcx->d_func()->sharing = true; } + glDevice.setPBuffer(q); qctx->d_func()->paintDevice = q; qctx->d_func()->valid = true; #if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES) diff --git a/src/opengl/qglpixelbuffer.h b/src/opengl/qglpixelbuffer.h index 5e81ea3..fe313a6 100644 --- a/src/opengl/qglpixelbuffer.h +++ b/src/opengl/qglpixelbuffer.h @@ -110,6 +110,8 @@ private: QScopedPointer<QGLPixelBufferPrivate> d_ptr; friend class QGLDrawable; friend class QGLWindowSurface; + friend class QGLPaintDevice; + friend class QGLPBufferGLPaintDevice; }; QT_END_NAMESPACE diff --git a/src/opengl/qglpixelbuffer_p.h b/src/opengl/qglpixelbuffer_p.h index 74cb330..96d41d7 100644 --- a/src/opengl/qglpixelbuffer_p.h +++ b/src/opengl/qglpixelbuffer_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE QT_BEGIN_INCLUDE_NAMESPACE #include "QtOpenGL/qglpixelbuffer.h" #include <private/qgl_p.h> +#include <private/qglpaintdevice_p.h> #if defined(Q_WS_X11) && !defined(QT_OPENGL_ES) #include <GL/glx.h> @@ -135,6 +136,19 @@ QT_END_INCLUDE_NAMESPACE class QEglContext; + +class QGLPBufferGLPaintDevice : public QGLPaintDevice +{ +public: + virtual QPaintEngine* paintEngine() const {return pbuf->paintEngine();} + virtual QSize size() const {return pbuf->size();} + virtual QGLContext* context() const; + virtual void endPaint(); + void setPBuffer(QGLPixelBuffer* pb); +private: + QGLPixelBuffer* pbuf; +}; + class QGLPixelBufferPrivate { Q_DECLARE_PUBLIC(QGLPixelBuffer) public: @@ -154,6 +168,7 @@ public: QGLPixelBuffer *q_ptr; bool invalid; QGLContext *qctx; + QGLPBufferGLPaintDevice glDevice; QGLFormat format; QGLFormat req_format; diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index bf4d4b9..34fff10 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -49,6 +49,7 @@ #include "qbrush.h" #include "qgl.h" #include <private/qgl_p.h> +#include <private/qglpaintdevice_p.h> #include <private/qpainter_p.h> #include "qmap.h" #include <private/qpaintengine_opengl_p.h> @@ -75,7 +76,7 @@ #include "qgl_cl_p.h" #endif -#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(drawable.context()); +#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(device->context()); #include <stdlib.h> #include "qpaintengine_opengl_p.h" @@ -286,7 +287,7 @@ public Q_SLOTS: } private: - QGLDrawable drawable; + QGLPaintDevice* device; QGLFramebufferObject *offscreen; QGLContext *ctx; @@ -305,7 +306,13 @@ private: inline void QGLOffscreen::setDevice(QPaintDevice *pdev) { - drawable.setDevice(pdev); + if (pdev->devType() == QInternal::OpenGL) + device = static_cast<QGLPaintDevice*>(pdev); + else + device = QGLPaintDevice::getDevice(pdev); + + if (!device) + return; drawable_fbo = (pdev->devType() == QInternal::FramebufferObject); } @@ -329,12 +336,12 @@ void QGLOffscreen::initialize() activated = true; initialized = true; - int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(drawable.size().width(), drawable.size().height())))); + int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(device->size().width(), device->size().height())))); - bool shared_context = qgl_share_reg()->checkSharing(drawable.context(), ctx); + bool shared_context = qgl_share_reg()->checkSharing(device->context(), ctx); bool would_fail = last_failed_size.isValid() && - (drawable.size().width() >= last_failed_size.width() || - drawable.size().height() >= last_failed_size.height()); + (device->size().width() >= last_failed_size.width() || + device->size().height() >= last_failed_size.height()); bool needs_refresh = dim > mask_dim || !shared_context; if (needs_refresh && !would_fail) { @@ -348,13 +355,13 @@ void QGLOffscreen::initialize() delete offscreen; offscreen = 0; mask_dim = 0; - last_failed_size = drawable.size(); + last_failed_size = device->size(); } } qt_mask_texture_cache()->setOffscreenSize(offscreenSize()); - qt_mask_texture_cache()->setDrawableSize(drawable.size()); - ctx = drawable.context(); + qt_mask_texture_cache()->setDrawableSize(device->size()); + ctx = device->context(); #endif } @@ -428,11 +435,11 @@ inline void QGLOffscreen::release() DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen"); if (drawable_fbo) - drawable.makeCurrent(); + device->ensureActiveTarget(); //### else offscreen->release(); - QSize sz(drawable.size()); + QSize sz(device->size()); glViewport(0, 0, sz.width(), sz.height()); glMatrixMode(GL_PROJECTION); @@ -455,7 +462,7 @@ inline bool QGLOffscreen::isBound() const inline QSize QGLOffscreen::drawableSize() const { - return drawable.size(); + return device->size(); } inline QSize QGLOffscreen::offscreenSize() const @@ -757,7 +764,7 @@ public: GLubyte pen_color[4]; GLubyte brush_color[4]; QTransform::TransformationType txop; - QGLDrawable drawable; + QGLPaintDevice* device; QGLOffscreen offscreen; qreal inverseScale; @@ -1167,7 +1174,7 @@ void QOpenGLPaintEnginePrivate::createGradientPaletteTexture(const QGradient& g) #ifdef QT_OPENGL_ES //### Q_UNUSED(g); #else - GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, drawable.context()); + GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, device->context()); glBindTexture(GL_TEXTURE_1D, texId); grad_palette = texId; if (g.spread() == QGradient::RepeatSpread || g.type() == QGradient::ConicalGradient) @@ -1236,12 +1243,19 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) { Q_D(QOpenGLPaintEngine); - d->drawable.setDevice(pdev); + if (pdev->devType() == QInternal::OpenGL) + d->device = static_cast<QGLPaintDevice*>(pdev); + else + d->device = QGLPaintDevice::getDevice(pdev); + + if (!d->device) + return false; + d->offscreen.setDevice(pdev); d->has_fast_pen = false; d->inverseScale = 1; d->opacity = 1; - d->drawable.makeCurrent(); + d->device->beginPaint(); d->matrix = QTransform(); d->has_antialiasing = false; d->high_quality_antialiasing = false; @@ -1256,7 +1270,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) bool has_frag_program = (QGLExtensions::glExtensions & QGLExtensions::FragmentProgram) && (pdev->devType() != QInternal::Pixmap); - QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context()); + QGLContext *ctx = const_cast<QGLContext *>(d->device->context()); if (!ctx) { qWarning() << "QOpenGLPaintEngine: paint device doesn't have a valid GL context."; return false; @@ -1265,9 +1279,9 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) if (has_frag_program) has_frag_program = qt_resolve_frag_program_extensions(ctx) && qt_resolve_version_1_3_functions(ctx); - d->use_stencil_method = d->drawable.format().stencil() + d->use_stencil_method = d->device->format().stencil() && (QGLExtensions::glExtensions & QGLExtensions::StencilWrap); - if (d->drawable.format().directRendering() + if (d->device->format().directRendering() && (d->use_stencil_method && QGLExtensions::glExtensions & QGLExtensions::StencilTwoSide)) d->has_stencil_face_ext = qt_resolve_stencil_face_extension(ctx); @@ -1333,23 +1347,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) d->offscreen.begin(); - if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) { - - if (d->drawable.hasTransparentBackground()) - glClearColor(0.0, 0.0, 0.0, 0.0); - else { - const QColor &c = d->drawable.backgroundColor(); - glClearColor(c.redF(), c.greenF(), c.blueF(), 1.0); - } - - GLbitfield clearBits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; -#ifndef QT_OPENGL_ES - clearBits |= GL_ACCUM_BUFFER_BIT; -#endif - glClear(clearBits); - } - - QSize sz(d->drawable.size()); + QSize sz(d->device->size()); glViewport(0, 0, sz.width(), sz.height()); // XXX (Embedded): We need a solution for GLWidgets that draw in a part or a bigger surface... glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -1366,7 +1364,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) #ifdef QT_OPENGL_ES d->max_texture_size = ctx->d_func()->maxTextureSize(); #else - bool shared_ctx = qgl_share_reg()->checkSharing(d->drawable.context(), d->shader_ctx); + bool shared_ctx = qgl_share_reg()->checkSharing(d->device->context(), d->shader_ctx); if (shared_ctx) { d->max_texture_size = d->shader_ctx->d_func()->maxTextureSize(); @@ -1382,7 +1380,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) glDeleteTextures(1, &d->drawable_texture); ctx->makeCurrent(); } - d->shader_ctx = d->drawable.context(); + d->shader_ctx = d->device->context(); glGenTextures(1, &d->grad_palette); qt_mask_texture_cache()->clearCache(); @@ -1417,7 +1415,7 @@ bool QOpenGLPaintEngine::end() Q_D(QOpenGLPaintEngine); d->flushDrawQueue(); d->offscreen.end(); - QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context()); + QGLContext *ctx = const_cast<QGLContext *>(d->device->context()); if (!ctx->d_ptr->internal_context) { glMatrixMode(GL_TEXTURE); glPopMatrix(); @@ -1434,8 +1432,7 @@ bool QOpenGLPaintEngine::end() glPopClientAttrib(); } #endif - d->drawable.swapBuffers(); - d->drawable.doneCurrent(); + d->device->endPaint(); qt_mask_texture_cache()->maintainCache(); return true; @@ -1961,7 +1958,7 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule) const int left = rect.left(); const int width = rect.width(); - const int bottom = drawable.size().height() - (rect.bottom() + 1); + const int bottom = device->size().height() - (rect.bottom() + 1); const int height = rect.height(); glScissor(left, bottom, width, height); @@ -2242,7 +2239,7 @@ void QOpenGLPaintEnginePrivate::updateDepthClip() const int left = fastClip.left(); const int width = fastClip.width(); - const int bottom = drawable.size().height() - (fastClip.bottom() + 1); + const int bottom = device->size().height() - (fastClip.bottom() + 1); const int height = fastClip.height(); glScissor(left, bottom, width, height); @@ -2325,7 +2322,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe // clipping is only supported when a stencil or depth buffer is // available - if (!d->drawable.format().depth()) + if (!d->device->format().depth()) return; d->use_system_clip = false; @@ -2362,7 +2359,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe path.addRect(untransformedRects[0]); path = d->matrix.map(path); - if (path.contains(QRectF(QPointF(), d->drawable.size()))) + if (path.contains(QRectF(QPointF(), d->device->size()))) isScreenClip = true; } } @@ -3369,7 +3366,7 @@ void QOpenGLPaintEnginePrivate::drawOffscreenPath(const QPainterPath &path) disableClipping(); - GLuint program = qt_gl_program_cache()->getProgram(drawable.context(), + GLuint program = qt_gl_program_cache()->getProgram(device->context(), FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true); QGLPathMaskGenerator maskGenerator(path, matrix, offscreen, program); addItem(qt_mask_texture_cache()->getMask(maskGenerator, this)); @@ -3506,7 +3503,7 @@ void QOpenGLPaintEngine::drawRects(const QRectF *rects, int rectCount) if (d->has_brush) { d->disableClipping(); - GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(), + GLuint program = qt_gl_program_cache()->getProgram(d->device->context(), FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true); if (d->matrix.type() >= QTransform::TxProject) { @@ -3916,7 +3913,7 @@ void QOpenGLPaintEnginePrivate::strokeLines(const QPainterPath &path) qreal penWidth = cpen.widthF(); - GLuint program = qt_gl_program_cache()->getProgram(drawable.context(), + GLuint program = qt_gl_program_cache()->getProgram(device->context(), FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true); QGLLineMaskGenerator maskGenerator(path, matrix, penWidth == 0 ? 1.0 : penWidth, offscreen, program); @@ -4302,7 +4299,7 @@ void QOpenGLPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QR else { GLenum target = qt_gl_preferredTextureTarget(); d->flushDrawQueue(); - d->drawable.bindTexture(pm, target); + d->device->context()->bindTexture(pm, target); drawTextureRect(pm.width(), pm.height(), r, sr, target); } } @@ -4336,9 +4333,9 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con d->flushDrawQueue(); if (scaled.isNull()) - d->drawable.bindTexture(pm); + d->device->context()->bindTexture(pm); else - d->drawable.bindTexture(scaled); + d->device->context()->bindTexture(scaled); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, d->use_smooth_pixmap_transform); #ifndef QT_OPENGL_ES @@ -4404,7 +4401,7 @@ void QOpenGLPaintEngine::drawImage(const QRectF &r, const QImage &image, const Q else { GLenum target = qt_gl_preferredTextureTarget(); d->flushDrawQueue(); - d->drawable.bindTexture(image, target); + d->device->context()->bindTexture(image, target); drawTextureRect(image.width(), image.height(), r, sr, target); } } @@ -4871,7 +4868,7 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); // make sure the glyphs we want to draw are in the cache - qt_glyph_cache()->cacheGlyphs(d->drawable.context(), ti, glyphs); + qt_glyph_cache()->cacheGlyphs(d->device->context(), ti, glyphs); d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops qt_glColor4ubv(d->pen_color); @@ -4949,7 +4946,7 @@ void QOpenGLPaintEngine::drawEllipse(const QRectF &rect) glPushMatrix(); glLoadIdentity(); - GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(), + GLuint program = qt_gl_program_cache()->getProgram(d->device->context(), FRAGMENT_PROGRAM_MASK_ELLIPSE_AA, 0, true); QGLEllipseMaskGenerator maskGenerator(rect, d->matrix, @@ -5084,10 +5081,10 @@ void QOpenGLPaintEnginePrivate::copyDrawable(const QRectF &rect) QRectF screen_rect = rect.adjusted(-1, -1, 1, 1); int left = qMax(0, static_cast<int>(screen_rect.left())); - int width = qMin(drawable.size().width() - left, static_cast<int>(screen_rect.width()) + 1); + int width = qMin(device->size().width() - left, static_cast<int>(screen_rect.width()) + 1); - int bottom = qMax(0, static_cast<int>(drawable.size().height() - screen_rect.bottom())); - int height = qMin(drawable.size().height() - bottom, static_cast<int>(screen_rect.height()) + 1); + int bottom = qMax(0, static_cast<int>(device->size().height() - screen_rect.bottom())); + int height = qMin(device->size().height() - bottom, static_cast<int>(screen_rect.height()) + 1); glBindTexture(GL_TEXTURE_2D, drawable_texture); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, left, bottom, width, height); @@ -5181,9 +5178,9 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType * glActiveTexture(GL_TEXTURE0 + brush_texture_location); if (current_style == Qt::TexturePattern) - drawable.bindTexture(cbrush.textureImage()); + device->context()->bindTexture(cbrush.textureImage()); else - drawable.bindTexture(qt_imageForBrush(current_style, true)); + device->context()->bindTexture(qt_imageForBrush(current_style, true)); updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, use_smooth_pixmap_transform); } @@ -5191,7 +5188,7 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType * glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray); glEnable(GL_FRAGMENT_PROGRAM_ARB); - GLuint program = qt_gl_program_cache()->getProgram(drawable.context(), + GLuint program = qt_gl_program_cache()->getProgram(device->context(), fragment_brush, fragment_composition_mode, false); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program); @@ -5263,7 +5260,7 @@ void QOpenGLPaintEnginePrivate::drawItem(const QDrawQueueItem &item) setGradientOps(item.brush, item.location.screen_rect); composite(item.location.screen_rect, item.location.rect.topLeft() - item.location.screen_rect.topLeft() - - QPoint(0, offscreen.offscreenSize().height() - drawable.size().height())); + - QPoint(0, offscreen.offscreenSize().height() - device->size().height())); } void QOpenGLPaintEnginePrivate::flushDrawQueue() diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index d63d2ad..ae616a8 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -80,12 +80,7 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize for (int i = 0; !chosen && i < m_fbos.size(); ++i) { QGLFramebufferObject *fbo = m_fbos.at(i); - QGLFramebufferObjectFormat format = fbo->format(); - if (format.samples() == requestFormat.samples() - && format.attachment() == requestFormat.attachment() - && format.textureTarget() == requestFormat.textureTarget() - && format.internalTextureFormat() == requestFormat.internalTextureFormat()) - { + if (fbo->format() == requestFormat) { // choose the fbo with a matching format and the closest size if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo)) candidate = fbo; @@ -132,6 +127,76 @@ void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) m_fbos << fbo; } + +QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const +{ + return data->paintEngine(); +} + +void QGLPixmapGLPaintDevice::beginPaint() +{ + if (!data->isValid()) + return; + + // QGLPaintDevice::beginPaint will store the current binding and replace + // it with m_thisFBO: + m_thisFBO = data->m_renderFbo->handle(); + QGLPaintDevice::beginPaint(); + + Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2); + + // QPixmap::fill() is deferred until now, where we actually need to do the fill: + if (data->needsFill()) { + const QColor &c = data->fillColor(); + float alpha = c.alphaF(); + glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + glClear(GL_COLOR_BUFFER_BIT); + } + else if (!data->isUninitialized()) { + // If the pixmap (GL Texture) has valid content (it has been + // uploaded from an image or rendered into before), we need to + // copy it from the texture to the render FBO. + + // Pass false to tell bind to _not_ copy the FBO into the texture! + GLuint texId = data->bind(false); + + QGL2PaintEngineEx* pe = static_cast<QGL2PaintEngineEx*>(data->paintEngine()); + QRect rect(0, 0, data->width(), data->height()); + pe->drawTexture(QRectF(rect), texId, rect.size(), QRectF(rect)); + } +} + +void QGLPixmapGLPaintDevice::endPaint() +{ + if (!data->isValid()) + return; + + data->copyBackFromRenderFbo(false); + + data->m_renderFbo->release(); + qgl_fbo_pool()->release(data->m_renderFbo); + data->m_renderFbo = 0; + + // Base's endPaint will restore the previous FBO binding + QGLPaintDevice::endPaint(); +} + +QGLContext* QGLPixmapGLPaintDevice::context() const +{ + data->ensureCreated(); + return data->m_ctx; +} + +QSize QGLPixmapGLPaintDevice::size() const +{ + return data->size(); +} + +void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) +{ + data = d; +} + static int qt_gl_pixmap_serial = 0; QGLPixmapData::QGLPixmapData(PixelType type) @@ -144,6 +209,7 @@ QGLPixmapData::QGLPixmapData(PixelType type) , m_hasAlpha(false) { setSerialNumber(++qt_gl_pixmap_serial); + m_glDevice.setPixmapData(this); } QGLPixmapData::~QGLPixmapData() @@ -237,11 +303,6 @@ void QGLPixmapData::ensureCreated() const m_texture.options &= ~QGLContext::MemoryManagedBindOption; } -QGLFramebufferObject *QGLPixmapData::fbo() const -{ - return m_renderFbo; -} - void QGLPixmapData::fromImage(const QImage &image, Qt::ImageConversionFlags) { @@ -417,31 +478,6 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); } -void QGLPixmapData::swapBuffers() -{ - if (!isValid()) - return; - - copyBackFromRenderFbo(false); - m_renderFbo->release(); - - qgl_fbo_pool()->release(m_renderFbo); - - m_renderFbo = 0; -} - -void QGLPixmapData::makeCurrent() -{ - if (isValid() && m_renderFbo) - m_renderFbo->bind(); -} - -void QGLPixmapData::doneCurrent() -{ - if (isValid() && m_renderFbo) - m_renderFbo->release(); -} - bool QGLPixmapData::useFramebufferObjects() { return QGLFramebufferObject::hasOpenGLFramebufferObjects() @@ -490,6 +526,10 @@ QPaintEngine* QGLPixmapData::paintEngine() const return m_source.paintEngine(); } + +// If copyBack is true, bind will copy the contents of the render +// FBO to the texture (which is not bound to the texture, as it's +// a multisample FBO). GLuint QGLPixmapData::bind(bool copyBack) const { if (m_renderFbo && copyBack) { @@ -509,12 +549,6 @@ GLuint QGLPixmapData::bind(bool copyBack) const return id; } -GLuint QGLPixmapData::textureId() const -{ - ensureCreated(); - return m_texture.id; -} - QGLTexture* QGLPixmapData::texture() const { return &m_texture; @@ -553,4 +587,9 @@ int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const } } +QGLPaintDevice *QGLPixmapData::glDevice() const +{ + return &m_glDevice; +} + QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index ab1ff47..31ae7c7 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -57,12 +57,14 @@ #include "qgl.h" #include "private/qpixmapdata_p.h" +#include "private/qglpaintdevice_p.h" QT_BEGIN_NAMESPACE class QPaintEngine; class QGLFramebufferObject; class QGLFramebufferObjectFormat; +class QGLPixmapData; class QGLFramebufferObjectPool { @@ -76,31 +78,50 @@ private: QGLFramebufferObjectPool* qgl_fbo_pool(); + +class QGLPixmapGLPaintDevice : public QGLPaintDevice +{ +public: + QPaintEngine* paintEngine() const; + + void beginPaint(); + void endPaint(); + QGLContext* context() const; + QSize size() const; + + void setPixmapData(QGLPixmapData*); +private: + QGLPixmapData *data; +}; + + class QGLPixmapData : public QPixmapData { public: QGLPixmapData(PixelType type); ~QGLPixmapData(); - bool isValid() const; - + // Re-implemented from QPixmapData: void resize(int width, int height); - void fromImage(const QImage &image, - Qt::ImageConversionFlags flags); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags); void copy(const QPixmapData *data, const QRect &rect); - bool scroll(int dx, int dy, const QRect &rect); - void fill(const QColor &color); bool hasAlphaChannel() const; QImage toImage() const; QPaintEngine *paintEngine() const; + int metric(QPaintDevice::PaintDeviceMetric metric) const; + // For accessing as a target: + QGLPaintDevice *glDevice() const; + + // For accessing as a source: + bool isValidContext(const QGLContext *ctx) const; GLuint bind(bool copyBack = true) const; - GLuint textureId() const; QGLTexture *texture() const; - bool isValidContext(const QGLContext *ctx) const; +private: + bool isValid() const; void ensureCreated() const; @@ -109,22 +130,13 @@ public: bool needsFill() const { return m_hasFillColor; } QColor fillColor() const { return m_fillColor; } - QSize size() const { return QSize(w, h); } - - QGLFramebufferObject *fbo() const; - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); -protected: - int metric(QPaintDevice::PaintDeviceMetric metric) const; - -private: QGLPixmapData(const QGLPixmapData &other); QGLPixmapData &operator=(const QGLPixmapData &other); void copyBackFromRenderFbo(bool keepCurrentFboBound) const; + QSize size() const { return QSize(w, h); } static bool useFramebufferObjects(); @@ -145,6 +157,10 @@ private: mutable bool m_hasFillColor; mutable bool m_hasAlpha; + + mutable QGLPixmapGLPaintDevice m_glDevice; + + friend class QGLPixmapGLPaintDevice; }; QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index a85b9ae..3a6ed06 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -229,6 +229,7 @@ QGLWidget* qt_gl_share_widget() return _qt_gl_share_widget()->shareWidget(); } + struct QGLWindowSurfacePrivate { QGLFramebufferObject *fbo; @@ -248,10 +249,49 @@ struct QGLWindowSurfacePrivate QSize size; QList<QImage> buffers; + QGLWindowSurfaceGLPaintDevice glDevice; + QGLWindowSurface* q_ptr; }; QGLFormat QGLWindowSurface::surfaceFormat; +void QGLWindowSurfaceGLPaintDevice::endPaint() +{ + glFlush(); + QGLPaintDevice::endPaint(); +} + +QSize QGLWindowSurfaceGLPaintDevice::size() const +{ + return d->size; +} + +QGLContext* QGLWindowSurfaceGLPaintDevice::context() const +{ + return d->ctx; +} + + +int QGLWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const +{ + return d->q_ptr->window()->metric(m); +} + +Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_2_engine) + +#if !defined (QT_OPENGL_ES_2) +Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_engine) +#endif + +QPaintEngine *QGLWindowSurfaceGLPaintDevice::paintEngine() const +{ +#if !defined(QT_OPENGL_ES_2) + if (!qt_gl_preferGL2Engine()) + return qt_gl_window_surface_engine(); +#endif + return qt_gl_window_surface_2_engine(); +} + QGLWindowSurface::QGLWindowSurface(QWidget *window) : QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate) { @@ -263,6 +303,8 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window) d_ptr->tried_fbo = false; d_ptr->tried_pb = false; d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull(); + d_ptr->glDevice.d = d_ptr; + d_ptr->q_ptr = this; } QGLWindowSurface::~QGLWindowSurface() @@ -320,27 +362,6 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size(); } -Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_2_engine) - -#if !defined (QT_OPENGL_ES_2) -Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_engine) -#endif - -/*! \reimp */ -QPaintEngine *QGLWindowSurface::paintEngine() const -{ -#if !defined(QT_OPENGL_ES_2) - if (!qt_gl_preferGL2Engine()) - return qt_gl_window_surface_engine(); -#endif - return qt_gl_window_surface_2_engine(); -} - -int QGLWindowSurface::metric(PaintDeviceMetric m) const -{ - return window()->metric(m); -} - QGLContext *QGLWindowSurface::context() const { return d_ptr->ctx; @@ -354,7 +375,7 @@ QPaintDevice *QGLWindowSurface::paintDevice() return d_ptr->pb; if (d_ptr->ctx) - return this; + return &d_ptr->glDevice; QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext); ctx->makeCurrent(); diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h index ad583b2..7b18f2e 100644 --- a/src/opengl/qwindowsurface_gl_p.h +++ b/src/opengl/qwindowsurface_gl_p.h @@ -56,6 +56,7 @@ #include <qglobal.h> #include <qgl.h> #include <private/qwindowsurface_p.h> +#include <private/qglpaintdevice_p.h> QT_BEGIN_NAMESPACE @@ -65,7 +66,18 @@ class QRegion; class QWidget; struct QGLWindowSurfacePrivate; -class QGLWindowSurface : public QObject, public QWindowSurface, public QPaintDevice +class QGLWindowSurfaceGLPaintDevice : public QGLPaintDevice +{ +public: + QPaintEngine* paintEngine() const; + void endPaint(); + QSize size() const; + int metric(PaintDeviceMetric m) const; + QGLContext* context() const; + QGLWindowSurfacePrivate* d; +}; + +class QGLWindowSurface : public QObject, public QWindowSurface // , public QPaintDevice { Q_OBJECT public: @@ -87,11 +99,6 @@ public: static QGLFormat surfaceFormat; - QPaintEngine *paintEngine() const; - -protected: - int metric(PaintDeviceMetric metric) const; - private slots: void deleted(QObject *object); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index 6550683..f88055e 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -330,17 +330,17 @@ bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescripti #endif -void QDirectFBPixmapData::fromImage(const QImage &image, +void QDirectFBPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { - if (image.depth() == 1) { - fromImage(image.convertToFormat(screen->alphaPixmapFormat()), flags); + if (img.depth() == 1) { + fromImage(img.convertToFormat(screen->alphaPixmapFormat()), flags); return; } - if (image.hasAlphaChannel() + if (img.hasAlphaChannel() #ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION - && (flags & Qt::NoOpaqueDetection || QDirectFBPixmapData::hasAlphaChannel(image)) + && (flags & Qt::NoOpaqueDetection || QDirectFBPixmapData::hasAlphaChannel(img)) #endif ) { alpha = true; @@ -349,13 +349,37 @@ void QDirectFBPixmapData::fromImage(const QImage &image, alpha = false; imageFormat = screen->pixelFormat(); } + QImage image; + if (flags != Qt::AutoColor) { + image = img.convertToFormat(imageFormat, flags); + flags = Qt::AutoColor; + } else { + image = img; + } + + IDirectFBSurface *imageSurface = screen->createDFBSurface(image, image.format(), QDirectFBScreen::DontTrackSurface); + if (!imageSurface) { + qWarning("QDirectFBPixmapData::fromImage()"); + invalidate(); + return; + } - dfbSurface = screen->createDFBSurface(image, imageFormat, QDirectFBScreen::TrackSurface|QDirectFBScreen::NoPreallocated); + dfbSurface = screen->createDFBSurface(image.size(), imageFormat, QDirectFBScreen::TrackSurface); if (!dfbSurface) { qWarning("QDirectFBPixmapData::fromImage()"); invalidate(); return; } + + if (image.hasAlphaChannel()) { + dfbSurface->Clear(dfbSurface, 0, 0, 0, 0); + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL); + } else { + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + } + dfbSurface->Blit(dfbSurface, imageSurface, 0, 0, 0); + imageSurface->Release(imageSurface); + w = image.width(); h = image.height(); is_null = (w <= 0 || h <= 0); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h index 46d06ef..5955f27 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -66,7 +66,7 @@ QT_MODULE(Gui) #if !defined QT_DIRECTFB_IMAGECACHE && !defined QT_NO_DIRECTFB_IMAGECACHE #define QT_NO_DIRECTFB_IMAGECACHE #endif -#if !defined QT_DIRECTFB_NO_IMAGEPROVIDER && !defined QT_DIRECTFB_IMAGEPROVIDER +#if !defined QT_NO_DIRECTFB_IMAGEPROVIDER && !defined QT_DIRECTFB_IMAGEPROVIDER #define QT_DIRECTFB_IMAGEPROVIDER #endif #if !defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && !defined QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index b1ffe69..82c2f81 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -127,6 +127,8 @@ void QDirectFBWindowSurface::createWindow(const QRect &rect) qFatal("QDirectFBWindowSurface: Unable to get primary display layer!"); DFBWindowDescription description; + memset(&description, 0, sizeof(DFBWindowDescription)); + description.caps = DWCAPS_NODECORATION|DWCAPS_DOUBLEBUFFER; description.flags = DWDESC_CAPS|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY; diff --git a/src/scripttools/debugging/qscriptdebuggerbackend.cpp b/src/scripttools/debugging/qscriptdebuggerbackend.cpp index 2efff04..feaea63 100644 --- a/src/scripttools/debugging/qscriptdebuggerbackend.cpp +++ b/src/scripttools/debugging/qscriptdebuggerbackend.cpp @@ -805,13 +805,7 @@ int QScriptDebuggerBackend::contextCount() const { if (!engine()) return 0; - int count = 0; - QScriptContext *ctx = engine()->currentContext(); - while (ctx) { - ++count; - ctx = ctx->parentContext(); - } - return count; + return contextIds().count(); } /*! |