From 55512950281260b85ea40c08239e459c76b696d2 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 30 Jun 2015 13:26:25 +0200 Subject: Fix repremultiply from RGB64 to RGB30 Just like from RGB32 to RGB30 we must also repremultiply when converting from RGB64 because the alpha channel loses more precision than the other color channels. Since this is not approximated accurately in the simple blending functions and the functions are no longer needed now the main render engine supports higher accuracy, the simple blending routines for RGB30 have been removed. Change-Id: I2b7b8eb015e330a487848fc4370ad3a1e966be91 Reviewed-by: Gunnar Sletta --- src/gui/painting/qblendfunctions.cpp | 187 ----------------------------------- src/gui/painting/qdrawhelper.cpp | 67 +++++++++---- src/gui/painting/qdrawhelper_p.h | 26 ++--- 3 files changed, 62 insertions(+), 218 deletions(-) (limited to 'src') diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index dbdd82e432..0898a20998 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -395,169 +395,6 @@ void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl, } } -template -static void qt_blend_argb32pm_on_a2rgb30pm(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) -{ -#ifdef QT_DEBUG_DRAW - fprintf(stdout, "qt_blend_argb32pm_on_a2rgb30pm: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", - destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); - fflush(stdout); -#endif - - const uint *src = (const uint *) srcPixels; - uint *dst = (uint *) destPixels; - if (const_alpha == 256) { - for (int y=0; y(s) + BYTE_MUL_RGB30(dst[x], 255 - qAlpha(s)); - } - dst = (quint32 *)(((uchar *) dst) + dbpl); - src = (const quint32 *)(((const uchar *) src) + sbpl); - } - } else if (const_alpha != 0) { - const_alpha = (const_alpha * 255) >> 8; - for (int y=0; y(s), const_alpha) + BYTE_MUL_RGB30(dst[x], 255 - qt_div_255(qAlpha(s) * const_alpha)); - } - dst = (quint32 *)(((uchar *) dst) + dbpl); - src = (const quint32 *)(((const uchar *) src) + sbpl); - } - } -} - -template -static void qt_blend_rgb32_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) -{ -#ifdef QT_DEBUG_DRAW - fprintf(stdout, "qt_blend_rgb32_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", - destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); - fflush(stdout); -#endif - - if (const_alpha != 256) { - qt_blend_argb32pm_on_a2rgb30pm(destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); - return; - } - - const uint *src = (const uint *) srcPixels; - uint *dst = (uint *) destPixels; - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - dst[x] = qConvertRgb32ToRgb30(src[x]); - } - dst = (quint32 *)(((uchar *) dst) + dbpl); - src = (const quint32 *)(((const uchar *) src) + sbpl); - } -} - -static void qt_blend_a2rgb30pm_on_a2rgb30pm(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) -{ -#ifdef QT_DEBUG_DRAW - fprintf(stdout, "qt_blend_a2rgb30pm_on_a2rgb30pm: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", - destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); - fflush(stdout); -#endif - - const uint *src = (const uint *) srcPixels; - uint *dst = (uint *) destPixels; - if (const_alpha == 256) { - for (int y=0; y> 8; - for (int y=0; y> 8; - uint s = BYTE_MUL_RGB30(src[x], const_alpha255); - dst[x] = s + BYTE_MUL_RGB30(dst[x], 255 - a); - } - dst = (quint32 *)(((uchar *) dst) + dbpl); - src = (const quint32 *)(((const uchar *) src) + sbpl); - } - } -} - - -static void qt_blend_rgb30_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) -{ -#ifdef QT_DEBUG_DRAW - fprintf(stdout, "qt_blend_rgb30_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", - destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); - fflush(stdout); -#endif - - if (const_alpha != 256) { - qt_blend_a2rgb30pm_on_a2rgb30pm(destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); - return; - } - - const uint *src = (const uint *) srcPixels; - uint *dst = (uint *) destPixels; - int len = w * 4; - for (int y=0; y> 8; - for (int y=0; y> 8; - uint s = BYTE_MUL_RGB30(src[x], const_alpha255); - dst[x] = qRgbSwapRgb30(s) + BYTE_MUL_RGB30(dst[x], 255 - a); - } - dst = (quint32 *)(((uchar *) dst) + dbpl); - src = (const quint32 *)(((const uchar *) src) + sbpl); - } - } -} - struct Blend_RGB32_on_RGB32_NoAlpha { inline void write(quint32 *dst, quint32 src) { *dst = src; } @@ -772,30 +609,6 @@ void qInitBlendFunctions() qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32; qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32; #endif - qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; - qBlendFunctions[QImage::Format_BGR30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_BGR30][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; - qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; - qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; - qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; - qBlendFunctions[QImage::Format_RGB30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_RGB30][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; - qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; - qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; - qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; - qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; qTransformFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_transform_image_rgb32_on_rgb32; qTransformFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_argb32; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 07e5a3d19b..0cf7e20605 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1252,25 +1252,54 @@ static inline void qConvertARGB64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *b const __m128i cmask = _mm_set1_epi32(0x000003ff); int i = 0; __m128i vr, vg, vb, va; - for (; i < count-1; i += 2) { - __m128i vs = _mm_loadu_si128((const __m128i*)buffer); - buffer += 2; - vr = _mm_srli_epi64(vs, 6); - vg = _mm_srli_epi64(vs, 16 + 6 - 10); - vb = _mm_srli_epi64(vs, 32 + 6); - vr = _mm_and_si128(vr, cmask); - vg = _mm_and_si128(vg, gmask); - vb = _mm_and_si128(vb, cmask); - va = _mm_srli_epi64(vs, 48 + 14); - if (PixelOrder == PixelOrderRGB) - vr = _mm_slli_epi32(vr, 20); - else - vb = _mm_slli_epi32(vb, 20); - va = _mm_slli_epi32(va, 30); - __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va)); - vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0)); - _mm_storel_epi64((__m128i*)dest, vd); - dest += 2; + if (i < count && (const uintptr_t)buffer & 0x8) { + *dest++ = qConvertRgb64ToRgb30(*buffer++); + ++i; + } + + for (; i < count-15; i += 16) { + // Repremultiplying is really expensive and hard to do in SIMD without AVX2, + // so we try to avoid it by checking if it is needed 16 samples at a time. + __m128i vOr = _mm_set1_epi32(0); + __m128i vAnd = _mm_set1_epi32(0xffffffff); + for (int j = 0; j < 16; j += 2) { + __m128i vs = _mm_load_si128((const __m128i*)(buffer + j)); + vOr = _mm_or_si128(vOr, vs); + vAnd = _mm_and_si128(vAnd, vs); + } + const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7)); + const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7)); + + if (andAlpha == 0xffff) { + for (int j = 0; j < 16; j += 2) { + __m128i vs = _mm_load_si128((const __m128i*)buffer); + buffer += 2; + vr = _mm_srli_epi64(vs, 6); + vg = _mm_srli_epi64(vs, 16 + 6 - 10); + vb = _mm_srli_epi64(vs, 32 + 6); + vr = _mm_and_si128(vr, cmask); + vg = _mm_and_si128(vg, gmask); + vb = _mm_and_si128(vb, cmask); + va = _mm_srli_epi64(vs, 48 + 14); + if (PixelOrder == PixelOrderRGB) + vr = _mm_slli_epi32(vr, 20); + else + vb = _mm_slli_epi32(vb, 20); + va = _mm_slli_epi32(va, 30); + __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va)); + vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0)); + _mm_storel_epi64((__m128i*)dest, vd); + dest += 2; + } + } else if (orAlpha == 0) { + for (int j = 0; j < 16; ++j) { + *dest++ = 0; + buffer++; + } + } else { + for (int j = 0; j < 16; ++j) + *dest++ = qConvertRgb64ToRgb30(*buffer++); + } } for (; i < count; ++i) diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 2c222b97c2..0034bfdf91 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -712,18 +712,6 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) { static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; } static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; } -static Q_ALWAYS_INLINE uint BYTE_MUL_RGB30(uint x, uint a) { - uint xa = x >> 30; - uint xr = (x >> 20) & 0x3ff; - uint xg = (x >> 10) & 0x3ff; - uint xb = x & 0x3ff; - xa = qt_div_255(xa * a); - xr = qt_div_255(xr * a); - xg = qt_div_255(xg * a); - xb = qt_div_255(xb * a); - return (xa << 30) | (xr << 20) | (xg << 10) | xb; -} - static Q_ALWAYS_INLINE uint qAlphaRgb30(uint c) { uint a = c >> 30; @@ -897,6 +885,18 @@ inline QRgb qRepremultiply(QRgb p) return qPremultiply(p); } +template +inline QRgba64 qRepremultiply(QRgba64 p) +{ + const uint alpha = p.alpha(); + if (alpha == 65535 || alpha == 0) + return p; + p = p.unpremultiplied(); + Q_CONSTEXPR uint mult = 65535 / (65535 >> Shift); + p.setAlpha(mult * (alpha >> Shift)); + return p.premultiplied(); +} + template<> inline uint qConvertArgb32ToA2rgb30(QRgb c) { @@ -1000,6 +1000,7 @@ template inline unsigned int qConvertRgb64ToRgb30(QRgba64); template<> inline unsigned int qConvertRgb64ToRgb30(QRgba64 c) { + c = qRepremultiply<14>(c); const uint a = c.alpha() >> 14; const uint r = c.red() >> 6; const uint g = c.green() >> 6; @@ -1010,6 +1011,7 @@ inline unsigned int qConvertRgb64ToRgb30(QRgba64 c) template<> inline unsigned int qConvertRgb64ToRgb30(QRgba64 c) { + c = qRepremultiply<14>(c); const uint a = c.alpha() >> 14; const uint r = c.red() >> 6; const uint g = c.green() >> 6; -- cgit v1.2.3 From bf013c9e745c63cb112be4d3a37027ff997927dd Mon Sep 17 00:00:00 2001 From: Mathias Hasselmann Date: Fri, 7 Nov 2014 22:22:10 +0100 Subject: OSX: Add initial FreeType support This permits text rendering consistent with other FreeType enabled platforms, like Windows and Linux. Task-number: QTBUG-42839 Change-Id: I8c99bcaa3fb07c16e935a0c3705af467bc3da584 Reviewed-by: Paul Lemire --- src/gui/text/qtextengine.cpp | 19 ++- src/platformsupport/fontdatabases/mac/coretext.pri | 7 ++ .../fontdatabases/mac/qcoretextfontdatabase.mm | 129 ++++++++++++++++++++- .../fontdatabases/mac/qcoretextfontdatabase_p.h | 7 +- src/plugins/platforms/cocoa/main.mm | 4 +- src/plugins/platforms/cocoa/qcocoaintegration.h | 11 +- src/plugins/platforms/cocoa/qcocoaintegration.mm | 24 +++- 7 files changed, 188 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index d2174c5e06..6b98c14205 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1120,6 +1120,15 @@ QT_BEGIN_INCLUDE_NAMESPACE QT_END_INCLUDE_NAMESPACE +#if defined(Q_OS_OSX) && !defined(QT_NO_FREETYPE) +static const char *s_shapersForOsxFreeType[] = +{ + "ot", + "fallback", + Q_NULLPTR +}; +#endif + int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector &itemBoundaries, bool kerningEnabled) const { uint glyphs_shaped = 0; @@ -1172,7 +1181,15 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st }; const int num_features = 1; - bool shapedOk = hb_shape_full(hb_font, buffer, features, num_features, 0); + const char *const *shaper_list = Q_NULLPTR; +#if defined(Q_OS_OSX) && !defined(QT_NO_FREETYPE) + // What's behind QFontEngine::FaceData::user_data isn't compatible between CoreText and + // FreeType font engines - specifically functions in hb-coretext.cc would run into undefined + // behavior with data from the FreeType engine. The OpenType shaper works with that engine. + if (actualFontEngine->type() == QFontEngine::Freetype) + shaper_list = s_shapersForOsxFreeType; +#endif + bool shapedOk = hb_shape_full(hb_font, buffer, features, num_features, shaper_list); if (Q_UNLIKELY(!shapedOk)) { hb_buffer_destroy(buffer); return 0; diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri index f67f00672a..ebb64d15b4 100644 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ b/src/platformsupport/fontdatabases/mac/coretext.pri @@ -1,6 +1,13 @@ HEADERS += $$PWD/qcoretextfontdatabase_p.h $$PWD/qfontengine_coretext_p.h OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.mm +contains(QT_CONFIG, freetype) { + include($$QT_SOURCE_TREE/src/3rdparty/freetype_dependency.pri) + HEADERS += $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft_p.h + SOURCES += $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft.cpp + CONFIG += opentype +} + ios: \ # On iOS CoreText and CoreGraphics are stand-alone frameworks LIBS_PRIVATE += -framework CoreText -framework CoreGraphics diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 75c4065d66..a9ca5391e8 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -33,6 +33,8 @@ #include "qglobal.h" +#include + #if defined(Q_OS_MACX) #import #import @@ -45,6 +47,9 @@ #include #include #include +#ifndef QT_NO_FREETYPE +#include +#endif QT_BEGIN_NAMESPACE @@ -102,8 +107,12 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context) } #endif -QCoreTextFontDatabase::QCoreTextFontDatabase() +QCoreTextFontDatabase::QCoreTextFontDatabase(bool useFreeType) +#ifndef QT_NO_FREETYPE + : m_useFreeType(useFreeType) +#endif { + Q_UNUSED(useFreeType) #ifdef Q_OS_MACX QSettings appleSettings(QLatin1String("apple.com")); QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); @@ -348,10 +357,48 @@ void QCoreTextFontDatabase::releaseHandle(void *handle) CFRelease(CTFontDescriptorRef(handle)); } +#ifndef QT_NO_FREETYPE +static QByteArray filenameForCFUrl(CFURLRef url) +{ + // The on-stack buffer prevents that a QByteArray allocated for the worst case (MAXPATHLEN) + // stays around for the lifetime of the font. Additionally, it helps to move the char + // signedness cast to an acceptable place. + uchar buffer[MAXPATHLEN]; + QByteArray filename; + + if (!CFURLGetFileSystemRepresentation(url, true, buffer, sizeof(buffer))) { + qWarning("QCoreTextFontDatabase::filenameForCFUrl: could not resolve file for URL %s", + qPrintable(QString::fromCFString(CFURLGetString(url)))); + } else { + QCFType scheme = CFURLCopyScheme(url); + if (QString::fromCFString(scheme) == QLatin1String("qrc")) + filename = ":"; + + filename += reinterpret_cast(buffer); + } + + return filename; +} +#endif + extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr) { + CTFontDescriptorRef descriptor = static_cast(usrPtr); + +#ifndef QT_NO_FREETYPE + if (m_useFreeType) { + QCFType url(static_cast(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute))); + + QByteArray filename; + if (url) + filename = filenameForCFUrl(url); + + return freeTypeFontEngine(f, filename); + } +#endif + qreal scaledPointSize = f.pixelSize; // When 96 DPI is forced, the Mac plugin will use DPI 72 for some @@ -363,7 +410,6 @@ QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr) if (QGuiApplication::testAttribute(Qt::AA_Use96Dpi)) scaledPointSize = f.pointSize; - CTFontDescriptorRef descriptor = (CTFontDescriptorRef) usrPtr; CGAffineTransform matrix = qt_transform_from_fontdef(f); CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix); if (font) { @@ -385,6 +431,29 @@ static void releaseFontData(void* info, const void* data, size_t size) QFontEngine *QCoreTextFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { +#ifndef QT_NO_FREETYPE + if (m_useFreeType) { + QByteArray *fontDataCopy = new QByteArray(fontData); + QCFType dataProvider = CGDataProviderCreateWithData(fontDataCopy, + fontDataCopy->constData(), fontDataCopy->size(), releaseFontData); + QCFType cgFont(CGFontCreateWithDataProvider(dataProvider)); + + if (!cgFont) { + qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed"); + return Q_NULLPTR; + } + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + fontDef.hintingPreference = hintingPreference; + CGAffineTransform transform = qt_transform_from_fontdef(fontDef); + QCFType ctFont(CTFontCreateWithGraphicsFont(cgFont, fontDef.pixelSize, &transform, Q_NULLPTR)); + QCFType url(static_cast(CTFontCopyAttribute(ctFont, kCTFontURLAttribute))); + return freeTypeFontEngine(fontDef, filenameForCFUrl(url), fontData); + } +#endif + Q_UNUSED(hintingPreference); QByteArray* fontDataCopy = new QByteArray(fontData); @@ -556,10 +625,36 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo } #if HAVE_CORETEXT -static CFArrayRef createDescriptorArrayForFont(CTFontRef font) +static CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName = QString()) { CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(array, QCFType(CTFontCopyFontDescriptor(font))); + QCFType descriptor = CTFontCopyFontDescriptor(font); + + Q_UNUSED(fileName) +#ifndef QT_NO_FREETYPE + // The physical font source URL (usually a local file or Qt resource) is only required for + // FreeType, when using non-system fonts, and needs some hackery to attach in a format + // agreeable to OSX. + if (!fileName.isEmpty()) { + QCFType fontURL; + + if (fileName.startsWith(QLatin1String(":/"))) { + // QUrl::fromLocalFile() doesn't accept qrc pseudo-paths like ":/fonts/myfont.ttf". + // Therefore construct from QString with the qrc:// scheme -> "qrc:///fonts/myfont.ttf". + fontURL = QUrl(QStringLiteral("qrc://") + fileName.mid(1)).toCFURL(); + } else if (!fileName.isEmpty()) { + // At this point we hope that filename is in a format that QUrl can handle. + fontURL = QUrl::fromLocalFile(fileName).toCFURL(); + } + + QCFType attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(attributes, kCTFontURLAttribute, fontURL); + descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes); + } +#endif + + CFArrayAppendValue(array, descriptor); return array; } #endif @@ -580,7 +675,11 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData if (cgFont) { if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) { QCFType font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); - fonts = createDescriptorArrayForFont(font); + fonts = createDescriptorArrayForFont(font +#ifndef QT_NO_FREETYPE + , m_useFreeType ? fileName : QString() +#endif + ); m_applicationFonts.append(QVariant::fromValue(QCFType::constructFromGet(cgFont))); } } @@ -880,5 +979,25 @@ void QCoreTextFontDatabase::removeApplicationFonts() #endif } +#ifndef QT_NO_FREETYPE +QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename, + const QByteArray &fontData) +{ + QFontEngine::FaceId faceId; + faceId.filename = filename; + const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); + const QFontEngineFT::GlyphFormat format = antialias ? QFontEngineFT::Format_A8 + : QFontEngineFT::Format_Mono; + + QScopedPointer engine(new QFontEngineFT(fontDef)); + if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) { + qWarning() << "QCoreTextFontDatabase::freeTypefontEngine Failed to create engine"; + return Q_NULLPTR; + } + + return engine.take(); +} +#endif + QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index a423ed5ae2..95af1210b3 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE class QCoreTextFontDatabase : public QPlatformFontDatabase { public: - QCoreTextFontDatabase(); + QCoreTextFontDatabase(bool useFreeType = false); ~QCoreTextFontDatabase(); void populateFontDatabase() Q_DECL_OVERRIDE; void populateFamily(const QString &familyName) Q_DECL_OVERRIDE; @@ -95,6 +95,11 @@ public: private: void populateFromDescriptor(CTFontDescriptorRef font); +#ifndef QT_NO_FREETYPE + bool m_useFreeType; + QFontEngine *freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename, + const QByteArray &fontData = QByteArray()); +#endif mutable QString defaultFontName; void removeApplicationFonts(); diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm index e6c1ed79b2..43ff715161 100644 --- a/src/plugins/platforms/cocoa/main.mm +++ b/src/plugins/platforms/cocoa/main.mm @@ -50,11 +50,9 @@ public: QPlatformIntegration * QCocoaIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - Q_UNUSED(paramList); - QMacAutoReleasePool pool; if (system.compare(QLatin1String("cocoa"), Qt::CaseInsensitive) == 0) - return new QCocoaIntegration; + return new QCocoaIntegration(paramList); return 0; } diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 3b8730151e..9e5dd3747e 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -97,10 +97,16 @@ public: class QCocoaIntegration : public QPlatformIntegration { public: - QCocoaIntegration(); + enum Option { + UseFreeTypeFontEngine = 0x1 + }; + Q_DECLARE_FLAGS(Options, Option) + + QCocoaIntegration(const QStringList ¶mList); ~QCocoaIntegration(); static QCocoaIntegration *instance(); + Options options() const; bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; @@ -141,6 +147,7 @@ public: void setApplicationIcon(const QIcon &icon) const Q_DECL_OVERRIDE; private: static QCocoaIntegration *mInstance; + Options mOptions; QScopedPointer mFontDb; @@ -160,6 +167,8 @@ private: QList m_popupWindowStack; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QCocoaIntegration::Options) + QT_END_NAMESPACE #endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 545e920057..0b9a38b560 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -244,10 +244,25 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height return windowPixmap; } +static QCocoaIntegration::Options parseOptions(const QStringList ¶mList) +{ + QCocoaIntegration::Options options; + foreach (const QString ¶m, paramList) { +#ifndef QT_NO_FREETYPE + if (param == QLatin1String("fontengine=freetype")) + options |= QCocoaIntegration::UseFreeTypeFontEngine; + else +#endif + qWarning() << "Unknown option" << param; + } + return options; +} + QCocoaIntegration *QCocoaIntegration::mInstance = 0; -QCocoaIntegration::QCocoaIntegration() - : mFontDb(new QCoreTextFontDatabase()) +QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) + : mOptions(parseOptions(paramList)) + , mFontDb(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))) #ifndef QT_NO_ACCESSIBILITY , mAccessibility(new QCocoaAccessibility) #endif @@ -345,6 +360,11 @@ QCocoaIntegration *QCocoaIntegration::instance() return mInstance; } +QCocoaIntegration::Options QCocoaIntegration::options() const +{ + return mOptions; +} + /*! \brief Synchronizes the screen list, adds new screens, removes deleted ones */ -- cgit v1.2.3 From 70da0b71fb99992d2467dafb36b523b637cca4f7 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Thu, 6 Aug 2015 16:51:15 +0300 Subject: QNetworkReplyImpl: remove unused declarations Change-Id: I844864d53d4644d57f3ca5f20b4a3f30a95fead3 Reviewed-by: Ulf Hermann --- src/network/access/qnetworkreplyimpl_p.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 088cb80653..3e720ef597 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -115,8 +115,6 @@ public: QNetworkReplyImplPrivate(); void _q_startOperation(); - void _q_sourceReadyRead(); - void _q_sourceReadChannelFinished(); void _q_copyReadyRead(); void _q_copyReadChannelFinished(); void _q_bufferOutgoingData(); -- cgit v1.2.3 From 670cb2edbcdc13b33cebe45a682a6dc10f17b616 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 27 Jul 2015 10:46:06 +0200 Subject: Move Q_ALWAYS_INLINE next to Q_NEVER_INLINE in qglobal.h. Change-Id: I7e3b7ecca6b5f142fa6cb5db2e9521ed3212afe8 Reviewed-by: Lars Knoll --- src/corelib/global/qglobal.h | 3 ++ src/corelib/thread/qgenericatomic.h | 81 +++++++++++++++++-------------------- src/gui/painting/qdrawhelper_p.h | 3 -- 3 files changed, 39 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 51dd64c7cc..f8f306f614 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -496,10 +496,13 @@ typedef qptrdiff qintptr; #ifdef Q_CC_MSVC # define Q_NEVER_INLINE __declspec(noinline) +# define Q_ALWAYS_INLINE __forceinline #elif defined(Q_CC_GNU) # define Q_NEVER_INLINE __attribute__((noinline)) +# define Q_ALWAYS_INLINE inline __attribute__((always_inline)) #else # define Q_NEVER_INLINE +# define Q_ALWAYS_INLINE inline #endif //defines the type for the WNDPROC on windows diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h index a9a790c14c..d3e7d51efd 100644 --- a/src/corelib/thread/qgenericatomic.h +++ b/src/corelib/thread/qgenericatomic.h @@ -46,13 +46,6 @@ QT_END_NAMESPACE #pragma qt_sync_stop_processing #endif -#ifdef Q_CC_GNU -// lowercase is fine, we'll undef it below -#define always_inline __attribute__((always_inline, gnu_inline)) -#else -#define always_inline -#endif - template struct QAtomicOpsSupport { enum { IsSupported = 0 }; }; template<> struct QAtomicOpsSupport<4> { enum { IsSupported = 1 }; }; @@ -84,19 +77,19 @@ template struct QGenericAtomicOps { } - template static inline always_inline + template static Q_ALWAYS_INLINE T load(const T &_q_value) Q_DECL_NOTHROW { return _q_value; } - template static inline always_inline + template static Q_ALWAYS_INLINE void store(T &_q_value, X newValue) Q_DECL_NOTHROW { _q_value = newValue; } - template static inline always_inline + template static Q_ALWAYS_INLINE T loadAcquire(const T &_q_value) Q_DECL_NOTHROW { T tmp = *static_cast(&_q_value); @@ -104,7 +97,7 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE void storeRelease(T &_q_value, X newValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); @@ -115,13 +108,13 @@ template struct QGenericAtomicOps { return BaseClass::isFetchAndAddNative(); } static inline Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree() Q_DECL_NOTHROW { return BaseClass::isFetchAndAddWaitFree(); } - template static inline always_inline + template static Q_ALWAYS_INLINE bool ref(T &_q_value) Q_DECL_NOTHROW { return BaseClass::fetchAndAddRelaxed(_q_value, 1) != T(-1); } - template static inline always_inline + template static Q_ALWAYS_INLINE bool deref(T &_q_value) Q_DECL_NOTHROW { return BaseClass::fetchAndAddRelaxed(_q_value, -1) != 1; @@ -138,7 +131,7 @@ template struct QGenericAtomicOps bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW; #endif - template static inline always_inline + template static Q_ALWAYS_INLINE bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW { bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); @@ -146,21 +139,21 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE bool testAndSetRelease(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); } - template static inline always_inline + template static Q_ALWAYS_INLINE bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); } - template static inline always_inline + template static Q_ALWAYS_INLINE bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW { bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue); @@ -168,14 +161,14 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE bool testAndSetRelease(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue); } - template static inline always_inline + template static Q_ALWAYS_INLINE bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); @@ -185,7 +178,7 @@ template struct QGenericAtomicOps static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return false; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return false; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndStoreRelaxed(T &_q_value, X newValue) Q_DECL_NOTHROW { // implement fetchAndStore on top of testAndSet @@ -196,7 +189,7 @@ template struct QGenericAtomicOps } } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndStoreAcquire(T &_q_value, X newValue) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndStoreRelaxed(_q_value, newValue); @@ -204,14 +197,14 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndStoreRelease(T &_q_value, X newValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndStoreRelaxed(_q_value, newValue); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndStoreOrdered(T &_q_value, X newValue) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); @@ -220,7 +213,7 @@ template struct QGenericAtomicOps static inline Q_DECL_CONSTEXPR bool isFetchAndAddNative() Q_DECL_NOTHROW { return false; } static inline Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() Q_DECL_NOTHROW { return false; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType::AdditiveT valueToAdd) Q_DECL_NOTHROW { // implement fetchAndAdd on top of testAndSet @@ -231,7 +224,7 @@ template struct QGenericAtomicOps } } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAddAcquire(T &_q_value, typename QAtomicAdditiveType::AdditiveT valueToAdd) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd); @@ -239,28 +232,28 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAddRelease(T &_q_value, typename QAtomicAdditiveType::AdditiveT valueToAdd) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAddOrdered(T &_q_value, typename QAtomicAdditiveType::AdditiveT valueToAdd) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndSubRelaxed(T &_q_value, typename QAtomicAdditiveType::AdditiveT operand) Q_DECL_NOTHROW { // implement fetchAndSub on top of fetchAndAdd return fetchAndAddRelaxed(_q_value, -operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndSubAcquire(T &_q_value, typename QAtomicAdditiveType::AdditiveT operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndSubRelaxed(_q_value, operand); @@ -268,21 +261,21 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndSubRelease(T &_q_value, typename QAtomicAdditiveType::AdditiveT operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndSubRelaxed(_q_value, operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndSubOrdered(T &_q_value, typename QAtomicAdditiveType::AdditiveT operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndSubRelaxed(_q_value, operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAndRelaxed(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { // implement fetchAndAnd on top of testAndSet @@ -293,7 +286,7 @@ template struct QGenericAtomicOps } } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAndAcquire(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand); @@ -301,21 +294,21 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAndRelease(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndAndRelaxed(_q_value, operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndAndOrdered(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndAndRelaxed(_q_value, operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndOrRelaxed(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { // implement fetchAndOr on top of testAndSet @@ -326,7 +319,7 @@ template struct QGenericAtomicOps } } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndOrAcquire(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand); @@ -334,21 +327,21 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndOrRelease(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndOrRelaxed(_q_value, operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndOrOrdered(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndOrRelaxed(_q_value, operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndXorRelaxed(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { // implement fetchAndXor on top of testAndSet @@ -359,7 +352,7 @@ template struct QGenericAtomicOps } } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndXorAcquire(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand); @@ -367,14 +360,14 @@ template struct QGenericAtomicOps return tmp; } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndXorRelease(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndXorRelaxed(_q_value, operand); } - template static inline always_inline + template static Q_ALWAYS_INLINE T fetchAndXorOrdered(T &_q_value, typename QtPrivate::QEnableIf::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); @@ -382,7 +375,5 @@ template struct QGenericAtomicOps } }; -#undef always_inline - QT_END_NAMESPACE #endif // QGENERICATOMIC_H diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 0034bfdf91..2fb9e7760c 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -62,15 +62,12 @@ QT_BEGIN_NAMESPACE #if defined(Q_CC_GNU) # define Q_STATIC_TEMPLATE_FUNCTION static -# define Q_ALWAYS_INLINE inline __attribute__((always_inline)) # define Q_DECL_RESTRICT __restrict__ #elif defined(Q_CC_MSVC) # define Q_STATIC_TEMPLATE_FUNCTION static -# define Q_ALWAYS_INLINE __forceinline # define Q_DECL_RESTRICT __restrict #else # define Q_STATIC_TEMPLATE_FUNCTION static -# define Q_ALWAYS_INLINE inline # define Q_DECL_RESTRICT #endif -- cgit v1.2.3 From d44ca1ed0b70a64113cce270d4dad45a1fef7235 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 27 Jul 2015 10:59:39 +0200 Subject: Remove type punning from QRgba64. In C++, type punning with a union is not allowed. It will result in compiler defined behavior at best, and undefined behavior at worst. Specifically, if QRgba64 is passed to a function by value, the different members of a struct might be passed in separate registers. This means that any write to the quint64 might not blank out the values of the struct whenever the compiler looses track with TBAA. Change-Id: I991b5492fe4bb13a14bb670fef5bf13dacbe6c0a Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qrgba64.h | 117 ++++++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h index 290501047d..b701b224be 100644 --- a/src/gui/painting/qrgba64.h +++ b/src/gui/painting/qrgba64.h @@ -40,35 +40,43 @@ QT_BEGIN_NAMESPACE class QRgba64 { - struct qrgba_t { - quint16 red; - quint16 green; - quint16 blue; - quint16 alpha; + quint64 rgba; + + // Make sure that the representation always has the order: red green blue alpha, independent + // of byte order. This way, vector operations that assume 4 16-bit values see the correct ones. + enum { +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + RedShift = 48, + GreenShift = 32, + BlueShift = 16, + AlphaShift = 0 +#else // little endian: + RedShift = 0, + GreenShift = 16, + BlueShift = 32, + AlphaShift = 48 +#endif }; - union { - struct qrgba_t c; - quint64 rgba; - }; public: // No constructors are allowed, since this needs to be usable in a union in no-c++11 mode. // When c++11 is mandatory, we can add all but a copy constructor. - Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha) + Q_DECL_RELAXED_CONSTEXPR static + QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha) { QRgba64 rgba64 #ifdef Q_COMPILER_UNIFORM_INIT = {} #endif ; - - rgba64.c.red = red; - rgba64.c.green = green; - rgba64.c.blue = blue; - rgba64.c.alpha = alpha; + rgba64.rgba = quint64(red) << RedShift + | quint64(green) << GreenShift + | quint64(blue) << BlueShift + | quint64(alpha) << AlphaShift; return rgba64; } - Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba64(quint64 c) + Q_DECL_RELAXED_CONSTEXPR static + QRgba64 fromRgba64(quint64 c) { QRgba64 rgba64 #ifdef Q_COMPILER_UNIFORM_INIT @@ -85,42 +93,49 @@ public: rgb64.rgba |= rgb64.rgba << 8; return rgb64; } - Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromArgb32(uint rgb) + Q_DECL_RELAXED_CONSTEXPR static + QRgba64 fromArgb32(uint rgb) { return fromRgba(rgb >> 16, rgb >> 8, rgb, rgb >> 24); } - Q_DECL_CONSTEXPR bool isOpaque() const { return c.alpha == 0xffff; } - Q_DECL_CONSTEXPR bool isTransparent() const { return c.alpha == 0; } - - Q_DECL_CONSTEXPR quint16 red() const { return c.red; } - Q_DECL_CONSTEXPR quint16 green() const { return c.green; } - Q_DECL_CONSTEXPR quint16 blue() const { return c.blue; } - Q_DECL_CONSTEXPR quint16 alpha() const { return c.alpha; } - void setRed(quint16 _red) { c.red = _red; } - void setGreen(quint16 _green) { c.green = _green; } - void setBlue(quint16 _blue) { c.blue = _blue; } - void setAlpha(quint16 _alpha) { c.alpha = _alpha; } - - Q_DECL_CONSTEXPR quint8 red8() const { return div_257(c.red); } - Q_DECL_CONSTEXPR quint8 green8() const { return div_257(c.green); } - Q_DECL_CONSTEXPR quint8 blue8() const { return div_257(c.blue); } - Q_DECL_CONSTEXPR quint8 alpha8() const { return div_257(c.alpha); } + Q_DECL_CONSTEXPR bool isOpaque() const + { + return (rgba & alphaMask()) == alphaMask(); + } + Q_DECL_CONSTEXPR bool isTransparent() const + { + return (rgba & alphaMask()) == 0; + } + + Q_DECL_CONSTEXPR quint16 red() const { return rgba >> RedShift; } + Q_DECL_CONSTEXPR quint16 green() const { return rgba >> GreenShift; } + Q_DECL_CONSTEXPR quint16 blue() const { return rgba >> BlueShift; } + Q_DECL_CONSTEXPR quint16 alpha() const { return rgba >> AlphaShift; } + void setRed(quint16 _red) { *this = fromRgba64(_red, green(), blue(), alpha()); } + void setGreen(quint16 _green) { *this = fromRgba64(red(), _green, blue(), alpha()); } + void setBlue(quint16 _blue) { *this = fromRgba64(red(), green(), _blue, alpha()); } + void setAlpha(quint16 _alpha) { *this = fromRgba64(red(), green(), blue(), _alpha); } + + Q_DECL_CONSTEXPR quint8 red8() const { return div_257(red()); } + Q_DECL_CONSTEXPR quint8 green8() const { return div_257(green()); } + Q_DECL_CONSTEXPR quint8 blue8() const { return div_257(blue()); } + Q_DECL_CONSTEXPR quint8 alpha8() const { return div_257(alpha()); } Q_DECL_CONSTEXPR uint toArgb32() const { return (alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8(); } Q_DECL_CONSTEXPR ushort toRgb16() const { - return (c.red & 0xf800) | ((c.green >> 10) << 5) | (c.blue >> 11); + return (red() & 0xf800) | ((green() >> 10) << 5) | (blue() >> 11); } Q_DECL_RELAXED_CONSTEXPR QRgba64 premultiplied() const { - const quint32 a = c.alpha; - const quint16 r = div_65535(c.red * a); - const quint16 g = div_65535(c.green * a); - const quint16 b = div_65535(c.blue * a); + const quint32 a = alpha(); + const quint16 r = div_65535(red() * a); + const quint16 g = div_65535(green() * a); + const quint16 b = div_65535(blue() * a); return fromRgba64(r, g, b, a); } @@ -145,27 +160,31 @@ public: } private: + static Q_DECL_CONSTEXPR quint64 alphaMask() { return quint64(0xffff) << AlphaShift; } + static Q_DECL_CONSTEXPR uint div_257_floor(uint x) { return (x - (x >> 8)) >> 8; } static Q_DECL_CONSTEXPR uint div_257(uint x) { return div_257_floor(x + 128); } static Q_DECL_CONSTEXPR uint div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; } Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied_32bit() const { - if (c.alpha == 0xffff || c.alpha == 0) + const quint16 a = alpha(); + if (a == 0xffff || a == 0) return *this; - const quint16 r = (quint32(c.red) * 0xffff + c.alpha/2) / c.alpha; - const quint16 g = (quint32(c.green) * 0xffff + c.alpha/2) / c.alpha; - const quint16 b = (quint32(c.blue) * 0xffff + c.alpha/2) / c.alpha; - return fromRgba64(r, g, b, c.alpha); + const quint16 r = (quint32(red()) * 0xffff + a/2) / a; + const quint16 g = (quint32(green()) * 0xffff + a/2) / a; + const quint16 b = (quint32(blue()) * 0xffff + a/2) / a; + return fromRgba64(r, g, b, a); } Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied_64bit() const { - if (c.alpha == 0xffff || c.alpha == 0) + const quint16 a = alpha(); + if (a == 0xffff || a == 0) return *this; - const quint64 fa = (Q_UINT64_C(0xffff00008000) + c.alpha/2) / c.alpha; - const quint16 r = (c.red * fa + 0x80000000) >> 32; - const quint16 g = (c.green * fa + 0x80000000) >> 32; - const quint16 b = (c.blue * fa + 0x80000000) >> 32; - return fromRgba64(r, g, b, c.alpha); + const quint64 fa = (Q_UINT64_C(0xffff00008000) + a/2) / a; + const quint16 r = (red() * fa + 0x80000000) >> 32; + const quint16 g = (green() * fa + 0x80000000) >> 32; + const quint16 b = (blue() * fa + 0x80000000) >> 32; + return fromRgba64(r, g, b, a); } }; -- cgit v1.2.3 From fc410c13980378223fa501b60cc47d08d5b3d8f5 Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Tue, 2 Jun 2015 09:21:14 +0200 Subject: Android: Add support for EnterKey QAndroidInputContext now sends along the EnterKey type provided by the EnterKey input method query enabling the QtActivityDelegate to set the imeOptions for the TextView accordingly. Change-Id: Ic96077ab4b11cf6dec52283ecf66b2cabe7af665 Reviewed-by: BogDan Vatra --- .../qtproject/qt5/android/QtActivityDelegate.java | 42 ++++++++++++++++++++-- .../src/org/qtproject/qt5/android/QtNative.java | 5 +-- src/plugins/platforms/android/androidjniinput.cpp | 10 +++--- src/plugins/platforms/android/androidjniinput.h | 2 +- .../platforms/android/qandroidinputcontext.cpp | 4 ++- 5 files changed, 52 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index ba3ecfecd6..ee196f1aef 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -203,6 +203,16 @@ public class QtActivityDelegate private final int ImhUrlCharactersOnly = 0x400000; private final int ImhLatinOnly = 0x800000; + // enter key type - must be kept in sync with QTDIR/src/corelib/global/qnamespace.h + private final int EnterKeyDefault = 0; + private final int EnterKeyReturn = 1; + private final int EnterKeyDone = 2; + private final int EnterKeyGo = 3; + private final int EnterKeySend = 4; + private final int EnterKeySearch = 5; + private final int EnterKeyNext = 6; + private final int EnterKeyPrevious = 7; + // application state private final int ApplicationSuspended = 0x0; private final int ApplicationHidden = 0x1; @@ -239,7 +249,7 @@ public class QtActivityDelegate }, 5); } - public void showSoftwareKeyboard(int x, int y, int width, int height, int inputHints) + public void showSoftwareKeyboard(int x, int y, int width, int height, int inputHints, int enterKeyType) { if (m_imm == null) return; @@ -252,7 +262,31 @@ public class QtActivityDelegate m_activity.getWindow().setSoftInputMode(m_softInputMode); int initialCapsMode = 0; + int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE; + + switch (enterKeyType) { + case EnterKeyReturn: + imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION; + break; + case EnterKeyGo: + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO; + break; + case EnterKeySend: + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEND; + break; + case EnterKeySearch: + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH; + break; + case EnterKeyNext: + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT; + break; + case EnterKeyPrevious: + if (Build.VERSION.SDK_INT > 10) + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS; + break; + } + int inputType = android.text.InputType.TYPE_CLASS_TEXT; if ((inputHints & (ImhPreferNumbers | ImhDigitsOnly | ImhFormattedNumbersOnly)) != 0) { @@ -278,7 +312,9 @@ public class QtActivityDelegate if ((inputHints & (ImhEmailCharactersOnly | ImhUrlCharactersOnly)) != 0) { if ((inputHints & ImhUrlCharactersOnly) != 0) { inputType |= android.text.InputType.TYPE_TEXT_VARIATION_URI; - imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO; + + if (enterKeyType == 0) // not explicitly overridden + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO; } else if ((inputHints & ImhEmailCharactersOnly) != 0) { inputType |= android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; } @@ -305,7 +341,7 @@ public class QtActivityDelegate } } - if ((inputHints & ImhMultiLine) != 0) + if (enterKeyType == 0 && (inputHints & ImhMultiLine) != 0) imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION; m_editText.setInitialCapsMode(initialCapsMode); diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index 5d7918ea54..a1e7dac4d4 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -389,12 +389,13 @@ public class QtNative final int y, final int width, final int height, - final int inputHints ) + final int inputHints, + final int enterKeyType) { runAction(new Runnable() { @Override public void run() { - m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints); + m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType); } }); } diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index be5e969d2b..b410e5f68e 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -70,18 +70,20 @@ namespace QtAndroidInput candidatesEnd); } - void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints) + void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType) { QJNIObjectPrivate::callStaticMethod(applicationClass(), "showSoftwareKeyboard", - "(IIIII)V", + "(IIIIII)V", left, top, width, height, - inputHints); + inputHints, + enterKeyType + ); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL - qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints; + qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType; #endif } diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h index b5a2ef06e4..d737dc9c98 100644 --- a/src/plugins/platforms/android/androidjniinput.h +++ b/src/plugins/platforms/android/androidjniinput.h @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE namespace QtAndroidInput { // Software keyboard support - void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints); + void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints, int enterKeyType); void resetSoftwareKeyboard(); void hideSoftwareKeyboard(); bool isSoftwareKeyboardVisible(); diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index d264f74d66..b44340106d 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -545,7 +545,9 @@ void QAndroidInputContext::showInputPanel() rect.top(), rect.width(), rect.height(), - query->value(Qt::ImHints).toUInt()); + query->value(Qt::ImHints).toUInt(), + query->value(Qt::ImEnterKeyType).toUInt() + ); } void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state) -- cgit v1.2.3 From 0ec809e027c643e42103b12340855c438b9a775b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 14 Mar 2015 00:21:35 -0700 Subject: forkfd: Add support for FreeBSD's pdfork(2) system call pdfork(2) has semantics very close to what we want in forkfd, but not quite. Differences: - we still get SIGCHLD and need to do a wait4 - no support for atomic FD_CLOEXEC and O_NONBLOCK On the SIGCHLD case: this commit is an improvement over the generic Unix case, since we no longer need to install a SIGCHLD handler and do not need to keep the arrays for matching PIDs and file descriptors. That matching is done entirely inside the kernel. However, since SIGCHLD is still sent to the process, an uncooperative SIGCHLD handler can still "steal" our response. At least Glib is documented not to reap children it wasn't explicitly asked to watch for (source code matches), but other libraries are known to do waitpid(-1) (e.g., EFL's Ecore). At least now the behavior is consistent: we will never install a handler, so the behavior won't depend on the order in which the handlers are installed. Change-Id: Iee8cbc07c4434ce9b560ffff13cb4c63306e43ef Reviewed-by: Oswald Buddenhagen Reviewed-by: Rafael Roquetto Reviewed-by: Thiago Macieira --- src/3rdparty/forkfd/forkfd.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'src') diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index e942db2717..51223aef1f 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -54,6 +54,9 @@ # define HAVE_PIPE2 1 # endif #endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 9 +# include +#endif #if _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500 # define HAVE_WAITID 1 @@ -506,6 +509,46 @@ static int create_pipe(int filedes[], int flags) return ret; } +#if defined(FORKFD_NO_SPAWNFD) && defined(__FreeBSD__) && __FreeBSD__ >= 9 +# if __FreeBSD__ == 9 +/* PROCDESC is an optional feature in the kernel and wasn't enabled + * by default on FreeBSD 9. So we need to check for it at runtime. */ +static ffd_atomic_int system_has_forkfd = FFD_ATOMIC_INIT(1); +# else +/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option + * anymore and can't be disabled. */ +static const int system_has_forkfd = 1; +# endif + +static int system_forkfd(int flags, pid_t *ppid) +{ + int ret; + pid_t pid; + pid = pdfork(&ret, PD_DAEMON); + if (__builtin_expect(pid == -1, 0)) { +# if __FreeBSD__ == 9 + if (errno == ENOSYS) { + /* PROCDESC wasn't compiled into the kernel: don't try it again. */ + ffd_atomic_store(&system_has_forkfd, 0, FFD_ATOMIC_RELAXED); + } +# endif + return -1; + } + if (pid == 0) { + /* child process */ + return FFD_CHILD_PROCESS; + } + + /* parent process */ + if (flags & FFD_CLOEXEC) + fcntl(ret, F_SETFD, FD_CLOEXEC); + if (flags & FFD_NONBLOCK) + fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK); + if (ppid) + *ppid = pid; + return ret; +} +#else static const int system_has_forkfd = 0; static int system_forkfd(int flags, pid_t *ppid) { @@ -513,6 +556,7 @@ static int system_forkfd(int flags, pid_t *ppid) (void)ppid; return -1; } +#endif #ifndef FORKFD_NO_FORKFD /** @@ -748,6 +792,26 @@ int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage) struct pipe_payload payload; int ret; + if (system_has_forkfd) { +#if defined(__FreeBSD__) && __FreeBSD__ >= 9 + pid_t pid; + int status; + int options = WEXITED; + + ret = pdgetpid(ffd, &pid); + if (ret == -1) + return ret; + ret = fcntl(ffd, F_GETFL); + if (ret == -1) + return ret; + options |= (ret & O_NONBLOCK) ? WNOHANG : 0; + ret = wait4(pid, &status, options, rusage); + if (ret != -1 && info) + convertStatusToForkfdInfo(status, info); + return ret == -1 ? -1 : 0; +#endif + } + ret = read(ffd, &payload, sizeof(payload)); if (ret == -1) return ret; /* pass errno, probably EINTR, EBADF or EWOULDBLOCK */ -- cgit v1.2.3 From 6c09b9e5530f959eebbe33ba7faa9548d85bd884 Mon Sep 17 00:00:00 2001 From: David Faure Date: Wed, 12 Aug 2015 11:10:27 +0200 Subject: QStandardPaths: on Windows, add APPDIR and APPDIR/data for GenericDataLocation This allows multiple applications installed into the same directory, to share data files without polluting a more global directory like C:/ProgramData. Change-Id: Id5f4f9bc9d2ccb7ec677babcc08c1c5a641178f6 Reviewed-by: Samuel Gaist Reviewed-by: Thiago Macieira --- src/corelib/io/qstandardpaths.cpp | 2 +- src/corelib/io/qstandardpaths_win.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index 04848a38e5..8828e09e8f 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -182,7 +182,7 @@ QT_BEGIN_NAMESPACE \li "C:/Users//AppData/Local//cache" \row \li GenericDataLocation \li "~/Library/Application Support", "/Library/Application Support" - \li "C:/Users//AppData/Local", "C:/ProgramData" + \li "C:/Users//AppData/Local", "C:/ProgramData", "", "/data" \row \li RuntimeLocation \li "~/Library/Application Support" \li "C:/Users/" diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index b1d5821a97..0a13f94f05 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/src/corelib/io/qstandardpaths_win.cpp @@ -212,10 +212,8 @@ QStringList QStandardPaths::standardLocations(StandardLocation type) } dirs.append(result); #ifndef QT_BOOTSTRAPPED - if (type != GenericDataLocation) { - dirs.append(QCoreApplication::applicationDirPath()); - dirs.append(QCoreApplication::applicationDirPath() + QLatin1String("/data")); - } + dirs.append(QCoreApplication::applicationDirPath()); + dirs.append(QCoreApplication::applicationDirPath() + QLatin1String("/data")); #endif } break; -- cgit v1.2.3 From cea03fa3e3274023f4238de7fa5139275d4737fb Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 5 Aug 2015 09:02:47 +0300 Subject: ANGLE: check for out of date swap chain even when size is empty This allows the XAML swap chain to work properly, as otherwise it never got a resize after it was passed into ANGLE with an empty size. This is fixed by upstream commit 3799c3014a9e4ba4a3853c014a7127254ec19d50, so no patch is necessary for Qt's local copy. Change-Id: I43b030fa74f6b30c2aa42a36db2031a84eedf60b Reviewed-by: Oliver Wolff --- src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp (limited to 'src') diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp old mode 100644 new mode 100755 index 4a87488014..84515f4c6c --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp @@ -203,6 +203,7 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) if (width == 0 || height == 0) { + checkForOutOfDateSwapChain(); return egl::Error(EGL_SUCCESS); } -- cgit v1.2.3 From 130083a7fc07fb8f98e4199832b6c20685a1ea70 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Sat, 8 Aug 2015 21:42:03 +0300 Subject: ANGLE: Use pixel sizes in the XAML swap chain This is necessary for Qt applications, as they render to GL in physical pixels. This is consistent with the CoreWindow swap chain behavior. This includes a partial revert of "ANGLE: Improve Windows Phone Support" as the modifications to SwapChain11 are incompatible with the XAML swap chain. This change only affects Windows Runtime targets. Change-Id: I401ae81028a9dfdb9da37f51c60844467c476f76 Reviewed-by: Oliver Wolff --- .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 46 --- .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 21 -- .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 4 +- .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 21 ++ .../d3d/d3d11/winrt/InspectableNativeWindow.h | 10 +- .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 30 +- .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.h | 7 +- ...LE-Use-pixel-sizes-in-the-XAML-swap-chain.patch | 361 +++++++++++++++++++++ 8 files changed, 410 insertions(+), 90 deletions(-) create mode 100644 src/angle/patches/0008-ANGLE-Use-pixel-sizes-in-the-XAML-swap-chain.patch (limited to 'src') diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp index dc539cf66e..0af2cf12c6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp @@ -154,14 +154,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - const int textureLength = std::max(backbufferWidth, backbufferHeight); - offscreenTextureDesc.Width = textureLength; - offscreenTextureDesc.Height = textureLength; -#else offscreenTextureDesc.Width = backbufferWidth; offscreenTextureDesc.Height = backbufferHeight; -#endif offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; offscreenTextureDesc.MipLevels = 1; offscreenTextureDesc.ArraySize = 1; @@ -241,14 +235,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei if (mDepthBufferFormat != GL_NONE) { D3D11_TEXTURE2D_DESC depthStencilTextureDesc; -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - const int textureLength = std::max(backbufferWidth, backbufferHeight); - depthStencilTextureDesc.Width = textureLength; - depthStencilTextureDesc.Height = textureLength; -#else depthStencilTextureDesc.Width = backbufferWidth; depthStencilTextureDesc.Height = backbufferHeight; -#endif depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; depthStencilTextureDesc.MipLevels = 1; depthStencilTextureDesc.ArraySize = 1; @@ -349,7 +337,6 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) return EGL_SUCCESS; } -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) // Can only call resize if we have already created our swap buffer and resources ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); @@ -392,12 +379,6 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) } return resetOffscreenTexture(backbufferWidth, backbufferHeight); -#else - // Do nothing on Windows Phone apart from updating the internal buffer/width height - mWidth = backbufferWidth; - mHeight = backbufferHeight; - return EGL_SUCCESS; -#endif } EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) @@ -552,27 +533,6 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - // Create a quad in homogeneous coordinates - float x1 = -1.0f; - float y1 = -1.0f; - float x2 = 1.0f; - float y2 = 1.0f; - - const float dim = std::max(mWidth, mHeight); - float u1 = 0; - float v1 = 0; - float u2 = float(width) / dim; - float v2 = float(height) / dim; - - const NativeWindow::RotationFlags flags = mNativeWindow.rotationFlags(); - const bool rotateL = flags == NativeWindow::RotateLeft; - const bool rotateR = flags == NativeWindow::RotateRight; - d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); - d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); - d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); - d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); -#else // Create a quad in homogeneous coordinates float x1 = (x / float(mWidth)) * 2.0f - 1.0f; float y1 = (y / float(mHeight)) * 2.0f - 1.0f; @@ -588,7 +548,6 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); -#endif deviceContext->Unmap(mQuadVB, 0); @@ -618,13 +577,8 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) D3D11_VIEWPORT viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - viewport.Width = (rotateL || rotateR) ? height : width; - viewport.Height = (rotateL || rotateR) ? width : height; -#else viewport.Width = mWidth; viewport.Height = mHeight; -#endif viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; deviceContext->RSSetViewports(1, &viewport); diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp index fa9a69c5a1..f45a077d97 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp @@ -191,25 +191,4 @@ HRESULT GetCoreWindowSizeInPixels(const ComPtr displayProperties; - float dpi = 96.0f; - - if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) - { - if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) - { - return dpi; - } - } - return dpi; -} - -long ConvertDipsToPixels(float dips) -{ - static const float dipsPerInch = 96.0f; - return lround((dips * GetLogicalDpi() / dipsPerInch)); -} } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h index 59df9d5a6c..87cdfe6f22 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h @@ -19,7 +19,6 @@ typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CGraphics__CD namespace rx { -long ConvertDipsToPixels(float dips); class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this { @@ -64,8 +63,7 @@ class CoreWindowSizeChangedHandler : ABI::Windows::Foundation::Size windowSize; if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) { - SIZE windowSizeInPixels = { ConvertDipsToPixels(windowSize.Width), ConvertDipsToPixels(windowSize.Height) }; - host->setNewClientSize(windowSizeInPixels); + host->setNewClientSize(windowSize); } } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp index 2bf48c5d94..e83f47929f 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp @@ -288,4 +288,25 @@ HRESULT GetOptionalSizePropertyValue(const ComPtr displayProperties; + float dpi = 96.0f; + + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) + { + if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) + { + return dpi; + } + } + return dpi; +} + +long ConvertDipsToPixels(float dips) +{ + static const float dipsPerInch = 96.0f; + return lround((dips * GetLogicalDpi() / dipsPerInch)); +} } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h index 575bdf8a58..f0534077ae 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h @@ -26,6 +26,8 @@ using namespace ABI::Windows::Foundation::Collections; namespace rx { +long ConvertDipsToPixels(float dips); + class InspectableNativeWindow { public: @@ -45,7 +47,7 @@ class InspectableNativeWindow virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; virtual bool registerForSizeChangeEvents() = 0; virtual void unregisterForSizeChangeEvents() = 0; - virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; } + virtual HRESULT scaleSwapChain(const Size& newSize) { return S_OK; } bool getClientRect(RECT *rect) { @@ -59,11 +61,11 @@ class InspectableNativeWindow return true; } - void setNewClientSize(const SIZE &newSize) + void setNewClientSize(const Size &newSize) { - if (mSupportsSwapChainResize && !mRequiresSwapChainScaling) + if (mSupportsSwapChainResize) { - mNewClientRect = { 0, 0, newSize.cx, newSize.cy }; + mNewClientRect = { 0, 0, ConvertDipsToPixels(newSize.Width), ConvertDipsToPixels(newSize.Height) }; mClientRectChanged = true; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp index 53899dbb30..0b48b54334 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp @@ -66,7 +66,7 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert } else { - result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect); + result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect, &mRequiresSwapChainScaling); } } @@ -139,7 +139,6 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa ComPtr newSwapChain; ComPtr swapChainPanelNative; - RECT currentPanelSize = {}; HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); @@ -167,13 +166,13 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa // first reading the current size of the swapchain panel, then scaling if (SUCCEEDED(result) && mRequiresSwapChainScaling) { - result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize); - } + ComPtr uiElement; + result = mSwapChainPanel.As(&uiElement); + ASSERT(SUCCEEDED(result)); - // Scale the swapchain to fit inside the contents of the panel. - if (SUCCEEDED(result) && mRequiresSwapChainScaling) - { - SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom }; + Size currentSize; + result = uiElement->get_RenderSize(¤tSize); + ASSERT(SUCCEEDED(result)); result = scaleSwapChain(currentSize); } @@ -190,9 +189,9 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa return result; } -HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) +HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &newSize) { - ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom }; + ABI::Windows::Foundation::Size renderScale = { newSize.Width / mNewClientRect.right, newSize.Height / mNewClientRect.bottom }; // Setup a scale matrix for the swap chain DXGI_MATRIX_3X2_F scaleMatrix = {}; scaleMatrix._11 = renderScale.Width; @@ -208,7 +207,7 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) return result; } -HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize) +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize, bool *scalingActive) { ComPtr uiElement; ABI::Windows::Foundation::Size renderSize = { 0, 0 }; @@ -220,7 +219,14 @@ HRESULT GetSwapChainPanelSize(const ComPtr mSwapChainPanel; @@ -62,8 +62,7 @@ class SwapChainPanelSizeChangedHandler : HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize); if (SUCCEEDED(result)) { - SIZE windowSize = { lround(newSize.Width), lround(newSize.Height) }; - host->setNewClientSize(windowSize); + host->setNewClientSize(newSize); } } @@ -74,6 +73,6 @@ class SwapChainPanelSizeChangedHandler : std::weak_ptr mHost; }; -HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize); +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize, bool *scalingActive = nullptr); } #endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ diff --git a/src/angle/patches/0008-ANGLE-Use-pixel-sizes-in-the-XAML-swap-chain.patch b/src/angle/patches/0008-ANGLE-Use-pixel-sizes-in-the-XAML-swap-chain.patch new file mode 100644 index 0000000000..cf383d7106 --- /dev/null +++ b/src/angle/patches/0008-ANGLE-Use-pixel-sizes-in-the-XAML-swap-chain.patch @@ -0,0 +1,361 @@ +From 333bb863e5c3e04fcc513e4750208fa3742be7a1 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Sat, 8 Aug 2015 21:42:03 +0300 +Subject: [PATCH 2/4] ANGLE: Use pixel sizes in the XAML swap chain + +This is necessary for Qt applications, as they render to GL in physical +pixels. This is consistent with the CoreWindow swap chain behavior. + +This includes a partial revert of "ANGLE: Improve Windows Phone Support" +as the modifications to SwapChain11 are incompatible with the XAML swap +chain. + +This change only affects Windows Runtime targets. + +Change-Id: I401ae81028a9dfdb9da37f51c60844467c476f76 +--- + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 46 ---------------------- + .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 21 ---------- + .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 4 +- + .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 21 ++++++++++ + .../d3d/d3d11/winrt/InspectableNativeWindow.h | 10 +++-- + .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 30 ++++++++------ + .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.h | 7 ++-- + 7 files changed, 49 insertions(+), 90 deletions(-) + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +index dc539cf..0af2cf1 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +@@ -154,14 +154,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); + + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; +-#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +- const int textureLength = std::max(backbufferWidth, backbufferHeight); +- offscreenTextureDesc.Width = textureLength; +- offscreenTextureDesc.Height = textureLength; +-#else + offscreenTextureDesc.Width = backbufferWidth; + offscreenTextureDesc.Height = backbufferHeight; +-#endif + offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; + offscreenTextureDesc.MipLevels = 1; + offscreenTextureDesc.ArraySize = 1; +@@ -241,14 +235,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + if (mDepthBufferFormat != GL_NONE) + { + D3D11_TEXTURE2D_DESC depthStencilTextureDesc; +-#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +- const int textureLength = std::max(backbufferWidth, backbufferHeight); +- depthStencilTextureDesc.Width = textureLength; +- depthStencilTextureDesc.Height = textureLength; +-#else + depthStencilTextureDesc.Width = backbufferWidth; + depthStencilTextureDesc.Height = backbufferHeight; +-#endif + depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; + depthStencilTextureDesc.MipLevels = 1; + depthStencilTextureDesc.ArraySize = 1; +@@ -349,7 +337,6 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) + return EGL_SUCCESS; + } + +-#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + // Can only call resize if we have already created our swap buffer and resources + ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); + +@@ -392,12 +379,6 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); +-#else +- // Do nothing on Windows Phone apart from updating the internal buffer/width height +- mWidth = backbufferWidth; +- mHeight = backbufferHeight; +- return EGL_SUCCESS; +-#endif + } + + EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +@@ -552,27 +533,6 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + + d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); + +-#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +- // Create a quad in homogeneous coordinates +- float x1 = -1.0f; +- float y1 = -1.0f; +- float x2 = 1.0f; +- float y2 = 1.0f; +- +- const float dim = std::max(mWidth, mHeight); +- float u1 = 0; +- float v1 = 0; +- float u2 = float(width) / dim; +- float v2 = float(height) / dim; +- +- const NativeWindow::RotationFlags flags = mNativeWindow.rotationFlags(); +- const bool rotateL = flags == NativeWindow::RotateLeft; +- const bool rotateR = flags == NativeWindow::RotateRight; +- d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); +- d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); +- d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); +- d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); +-#else + // Create a quad in homogeneous coordinates + float x1 = (x / float(mWidth)) * 2.0f - 1.0f; + float y1 = (y / float(mHeight)) * 2.0f - 1.0f; +@@ -588,7 +548,6 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); +-#endif + + deviceContext->Unmap(mQuadVB, 0); + +@@ -618,13 +577,8 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; +-#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +- viewport.Width = (rotateL || rotateR) ? height : width; +- viewport.Height = (rotateL || rotateR) ? width : height; +-#else + viewport.Width = mWidth; + viewport.Height = mHeight; +-#endif + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +index fa9a69c..f45a077 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +@@ -191,25 +191,4 @@ HRESULT GetCoreWindowSizeInPixels(const ComPtr displayProperties; +- float dpi = 96.0f; +- +- if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) +- { +- if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) +- { +- return dpi; +- } +- } +- return dpi; +-} +- +-long ConvertDipsToPixels(float dips) +-{ +- static const float dipsPerInch = 96.0f; +- return lround((dips * GetLogicalDpi() / dipsPerInch)); +-} + } +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h +index 59df9d5..87cdfe6 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h +@@ -19,7 +19,6 @@ typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CGraphics__CD + + namespace rx + { +-long ConvertDipsToPixels(float dips); + + class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this + { +@@ -64,8 +63,7 @@ class CoreWindowSizeChangedHandler : + ABI::Windows::Foundation::Size windowSize; + if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) + { +- SIZE windowSizeInPixels = { ConvertDipsToPixels(windowSize.Width), ConvertDipsToPixels(windowSize.Height) }; +- host->setNewClientSize(windowSizeInPixels); ++ host->setNewClientSize(windowSize); + } + } + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp +index 2bf48c5..e83f479 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp +@@ -288,4 +288,25 @@ HRESULT GetOptionalSizePropertyValue(const ComPtr displayProperties; ++ float dpi = 96.0f; ++ ++ if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) ++ { ++ if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) ++ { ++ return dpi; ++ } ++ } ++ return dpi; ++} ++ ++long ConvertDipsToPixels(float dips) ++{ ++ static const float dipsPerInch = 96.0f; ++ return lround((dips * GetLogicalDpi() / dipsPerInch)); ++} + } +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h +index 575bdf8..f053407 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h +@@ -26,6 +26,8 @@ using namespace ABI::Windows::Foundation::Collections; + + namespace rx + { ++long ConvertDipsToPixels(float dips); ++ + class InspectableNativeWindow + { + public: +@@ -45,7 +47,7 @@ class InspectableNativeWindow + virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; + virtual bool registerForSizeChangeEvents() = 0; + virtual void unregisterForSizeChangeEvents() = 0; +- virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; } ++ virtual HRESULT scaleSwapChain(const Size& newSize) { return S_OK; } + + bool getClientRect(RECT *rect) + { +@@ -59,11 +61,11 @@ class InspectableNativeWindow + return true; + } + +- void setNewClientSize(const SIZE &newSize) ++ void setNewClientSize(const Size &newSize) + { +- if (mSupportsSwapChainResize && !mRequiresSwapChainScaling) ++ if (mSupportsSwapChainResize) + { +- mNewClientRect = { 0, 0, newSize.cx, newSize.cy }; ++ mNewClientRect = { 0, 0, ConvertDipsToPixels(newSize.Width), ConvertDipsToPixels(newSize.Height) }; + mClientRectChanged = true; + } + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp +index 53899db..0b48b54 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp +@@ -66,7 +66,7 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert + } + else + { +- result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect); ++ result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect, &mRequiresSwapChainScaling); + } + } + +@@ -139,7 +139,6 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa + + ComPtr newSwapChain; + ComPtr swapChainPanelNative; +- RECT currentPanelSize = {}; + + HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + +@@ -167,13 +166,13 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa + // first reading the current size of the swapchain panel, then scaling + if (SUCCEEDED(result) && mRequiresSwapChainScaling) + { +- result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize); +- } ++ ComPtr uiElement; ++ result = mSwapChainPanel.As(&uiElement); ++ ASSERT(SUCCEEDED(result)); + +- // Scale the swapchain to fit inside the contents of the panel. +- if (SUCCEEDED(result) && mRequiresSwapChainScaling) +- { +- SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom }; ++ Size currentSize; ++ result = uiElement->get_RenderSize(¤tSize); ++ ASSERT(SUCCEEDED(result)); + result = scaleSwapChain(currentSize); + } + +@@ -190,9 +189,9 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa + return result; + } + +-HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) ++HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &newSize) + { +- ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom }; ++ ABI::Windows::Foundation::Size renderScale = { newSize.Width / mNewClientRect.right, newSize.Height / mNewClientRect.bottom }; + // Setup a scale matrix for the swap chain + DXGI_MATRIX_3X2_F scaleMatrix = {}; + scaleMatrix._11 = renderScale.Width; +@@ -208,7 +207,7 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) + return result; + } + +-HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize) ++HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize, bool *scalingActive) + { + ComPtr uiElement; + ABI::Windows::Foundation::Size renderSize = { 0, 0 }; +@@ -220,7 +219,14 @@ HRESULT GetSwapChainPanelSize(const ComPtr mSwapChainPanel; +@@ -62,8 +62,7 @@ class SwapChainPanelSizeChangedHandler : + HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize); + if (SUCCEEDED(result)) + { +- SIZE windowSize = { lround(newSize.Width), lround(newSize.Height) }; +- host->setNewClientSize(windowSize); ++ host->setNewClientSize(newSize); + } + } + +@@ -74,6 +73,6 @@ class SwapChainPanelSizeChangedHandler : + std::weak_ptr mHost; + }; + +-HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize); ++HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize, bool *scalingActive = nullptr); + } + #endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ +-- +1.9.5.msysgit.1 + -- cgit v1.2.3 From ebc2b963aa9e8ce2e983ef08c9b503ccc1702fdb Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 5 Aug 2015 08:15:06 +0300 Subject: winrtmain: Start in XAML mode This allows the platform plugin to start using XAML interfaces in the windowing system. Change-Id: Ifcd29b8b8d83b138af69786dfc6a1adec21be37e Reviewed-by: Maurice Kalinowski --- src/winmain/qtmain_winrt.cpp | 263 ++++++++++++++++++++++++------------------- 1 file changed, 148 insertions(+), 115 deletions(-) (limited to 'src') diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp index 141e3ed135..d9f8c8f991 100644 --- a/src/winmain/qtmain_winrt.cpp +++ b/src/winmain/qtmain_winrt.cpp @@ -49,38 +49,44 @@ entry point within the newly created GUI thread. */ +#if _MSC_VER < 1900 #include typedef struct { int newmode; } _startupinfo; +#endif // _MSC_VER < 1900 extern "C" { +#if _MSC_VER < 1900 int __getmainargs(int *argc, char ***argv, char ***env, int expandWildcards, _startupinfo *info); +#endif int main(int, char **); } #include #include -#include -#include #include #include +#include #include #include +#include +#include using namespace ABI::Windows::ApplicationModel; +using namespace ABI::Windows::ApplicationModel::Activation; +using namespace ABI::Windows::ApplicationModel::Core; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::UI; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; #define qHString(x) Wrappers::HString::MakeReference(x).Get() #define CoreApplicationClass RuntimeClass_Windows_ApplicationModel_Core_CoreApplication -typedef ITypedEventHandler ActivatedHandler; - -static int g_mainExitCode; +typedef ITypedEventHandler ActivatedHandler; static QtMessageHandler defaultMessageHandler; static void devMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) @@ -103,53 +109,112 @@ static void devMessageHandler(QtMsgType type, const QMessageLogContext &context, defaultMessageHandler(type, context, message); } -class AppContainer : public Microsoft::WRL::RuntimeClass +class AppContainer : public RuntimeClass { public: - AppContainer(int argc, char *argv[]) : m_argc(argc), m_deleteArgv0(false) + AppContainer() { - m_argv.reserve(argc); - for (int i = 0; i < argc; ++i) { - // Workaround for empty argv[0] which occurs when WMAppManifest's ImageParams is used - // The second argument is taken to be the executable - if (i == 0 && argc >= 2 && !qstrlen(argv[0])) { - const QByteArray argv0 = QDir::current() - .absoluteFilePath(QString::fromLatin1(argv[1])).toUtf8(); - m_argv.append(qstrdup(argv0.constData())); - m_argc -= 1; - m_deleteArgv0 = true; - ++i; - continue; - } - m_argv.append(argv[i]); - } + ComPtr applicationFactory; + HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Application).Get(), + IID_PPV_ARGS(&applicationFactory)); + Q_ASSERT_SUCCEEDED(hr); + + hr = applicationFactory->CreateInstance(this, &base, &core); + RETURN_VOID_IF_FAILED("Failed to create application container instance"); } ~AppContainer() { - if (m_deleteArgv0) - delete[] m_argv[0]; - for (int i = m_argc; i < m_argv.size(); ++i) - delete[] m_argv[i]; } - // IFrameworkView Methods - HRESULT __stdcall Initialize(Core::ICoreApplicationView *view) + int exec(int argc, char **argv) { - view->add_Activated(Callback(this, &AppContainer::onActivated).Get(), - &m_activationToken); - return S_OK; + args.reserve(argc); + for (int i = 0; i < argc; ++i) + args.append(argv[i]); + + mainThread = CreateThread(NULL, 0, [](void *param) -> DWORD { + AppContainer *app = reinterpret_cast(param); + int argc = app->args.count(); + char **argv = app->args.data(); + return main(argc, argv); + }, this, CREATE_SUSPENDED, nullptr); + + HRESULT hr; + ComPtr appStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Application).Get(), + IID_PPV_ARGS(&appStatics)); + Q_ASSERT_SUCCEEDED(hr); + hr = appStatics->Start(Callback([](Xaml::IApplicationInitializationCallbackParams *) { + return S_OK; + }).Get()); + Q_ASSERT_SUCCEEDED(hr); + + DWORD exitCode; + GetExitCodeThread(mainThread, &exitCode); + return exitCode; + } + +private: + HRESULT __stdcall OnActivated(IActivatedEventArgs *args) Q_DECL_OVERRIDE + { + return base->OnActivated(args); } - HRESULT __stdcall SetWindow(ABI::Windows::UI::Core::ICoreWindow *) { return S_OK; } - HRESULT __stdcall Load(HSTRING) { return S_OK; } - HRESULT __stdcall Run() + + HRESULT __stdcall OnLaunched(ILaunchActivatedEventArgs *launchArgs) Q_DECL_OVERRIDE { +#if _MSC_VER >= 1900 + commandLine = QString::fromWCharArray(GetCommandLine()).toUtf8(); +#endif + HString launchCommandLine; + launchArgs->get_Arguments(launchCommandLine.GetAddressOf()); + if (launchCommandLine.IsValid()) { + quint32 launchCommandLineLength; + const wchar_t *launchCommandLineBuffer = launchCommandLine.GetRawBuffer(&launchCommandLineLength); + if (!commandLine.isEmpty() && launchCommandLineLength) + commandLine += ' '; + if (launchCommandLineLength) + commandLine += QString::fromWCharArray(launchCommandLineBuffer, launchCommandLineLength).toUtf8(); + } + if (!commandLine.isEmpty()) + args.append(commandLine.data()); + + bool quote = false; + bool escape = false; + for (int i = 0; i < commandLine.size(); ++i) { + switch (commandLine.at(i)) { + case '\\': + escape = true; + break; + case '"': + if (escape) { + escape = false; + break; + } + quote = !quote; + commandLine[i] = '\0'; + break; + case ' ': + if (quote) + break; + commandLine[i] = '\0'; + if (args.last()[0] != '\0') + args.append(commandLine.data() + i + 1); + // fall through + default: + if (args.last()[0] == '\0') + args.last() = commandLine.data() + i; + escape = false; // only quotes are escaped + break; + } + } + bool develMode = false; bool debugWait = false; - foreach (const QByteArray &arg, m_argv) { - if (arg == "-qdevel") + foreach (const char *arg, args) { + if (strcmp(arg, "-qdevel") == 0) develMode = true; - if (arg == "-qdebug") + if (strcmp(arg, "-qdebug") == 0) debugWait = true; } if (develMode) { @@ -173,98 +238,70 @@ public: while (!IsDebuggerPresent()) WaitForSingleObjectEx(GetCurrentThread(), 1, true); } - g_mainExitCode = main(m_argv.count(), m_argv.data()); + + ResumeThread(mainThread); return S_OK; } - HRESULT __stdcall Uninitialize() { return S_OK; } -private: - // Activation handler - HRESULT onActivated(Core::ICoreApplicationView *, Activation::IActivatedEventArgs *args) + HRESULT __stdcall OnFileActivated(IFileActivatedEventArgs *args) Q_DECL_OVERRIDE { - Activation::ILaunchActivatedEventArgs *launchArgs; - if (SUCCEEDED(args->QueryInterface(&launchArgs))) { - for (int i = m_argc; i < m_argv.size(); ++i) - delete[] m_argv[i]; - m_argv.resize(m_argc); - HString arguments; - launchArgs->get_Arguments(arguments.GetAddressOf()); - if (arguments.IsValid()) { - foreach (const QByteArray &arg, QString::fromWCharArray( - arguments.GetRawBuffer(nullptr)).toLocal8Bit().split(' ')) { - m_argv.append(qstrdup(arg.constData())); - } - } - } + Q_UNUSED(args); return S_OK; } - int m_argc; - QVector m_argv; - bool m_deleteArgv0; - EventRegistrationToken m_activationToken; -}; + HRESULT __stdcall OnSearchActivated(ISearchActivatedEventArgs *args) Q_DECL_OVERRIDE + { + Q_UNUSED(args); + return S_OK; + } -class AppViewSource : public Microsoft::WRL::RuntimeClass -{ -public: - AppViewSource(int argc, char **argv) : m_argc(argc), m_argv(argv) { } - HRESULT __stdcall CreateView(Core::IFrameworkView **frameworkView) + HRESULT __stdcall OnShareTargetActivated(IShareTargetActivatedEventArgs *args) Q_DECL_OVERRIDE { - return (*frameworkView = Make(m_argc, m_argv).Detach()) ? S_OK : E_OUTOFMEMORY; + Q_UNUSED(args); + return S_OK; } -private: - int m_argc; - char **m_argv; + + HRESULT __stdcall OnFileOpenPickerActivated(IFileOpenPickerActivatedEventArgs *args) Q_DECL_OVERRIDE + { + Q_UNUSED(args); + return S_OK; + } + + HRESULT __stdcall OnFileSavePickerActivated(IFileSavePickerActivatedEventArgs *args) Q_DECL_OVERRIDE + { + Q_UNUSED(args); + return S_OK; + } + + HRESULT __stdcall OnCachedFileUpdaterActivated(ICachedFileUpdaterActivatedEventArgs *args) Q_DECL_OVERRIDE + { + Q_UNUSED(args); + return S_OK; + } + + HRESULT __stdcall OnWindowCreated(Xaml::IWindowCreatedEventArgs *args) Q_DECL_OVERRIDE + { + Q_UNUSED(args); + return S_OK; + } + + ComPtr base; + ComPtr core; + QByteArray commandLine; + QVarLengthArray args; + HANDLE mainThread; }; // Main entry point for Appx containers int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { -#if _MSC_VER < 1900 int argc = 0; - char **argv, **env; + char **argv = 0, **env = 0; +#if _MSC_VER < 1900 _startupinfo info = { _query_new_mode() }; if (int init = __getmainargs(&argc, &argv, &env, false, &info)) return init; -#else - QByteArray commandLine = QString::fromWCharArray(GetCommandLine()).toUtf8(); - QVarLengthArray args; - args.append(commandLine.data()); - bool quote = false; - bool escape = false; - for (int i = 0; i < commandLine.size(); ++i) { - switch (commandLine.at(i)) { - case '\\': - escape = true; - break; - case '"': - if (escape) { - escape = false; - break; - } - quote = !quote; - commandLine[i] = '\0'; - break; - case ' ': - if (quote) - break; - commandLine[i] = '\0'; - if (args.last()[0] != '\0') - args.append(commandLine.data() + i + 1); - // fall through - default: - if (args.last()[0] == '\0') - args.last() = commandLine.data() + i; - escape = false; // only quotes are escaped - break; - } - } - int argc = args.size(); - char **argv = args.data(); - char **env = Q_NULLPTR; #endif // _MSC_VER >= 1900 - for (int i = 0; env && env[i]; ++i) { QByteArray var(env[i]); int split = var.indexOf('='); @@ -275,10 +312,6 @@ int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) if (FAILED(RoInitialize(RO_INIT_MULTITHREADED))) return 1; - Core::ICoreApplication *appFactory; - if (FAILED(RoGetActivationFactory(qHString(CoreApplicationClass), IID_PPV_ARGS(&appFactory)))) - return 2; - - appFactory->Run(Make(argc, argv).Get()); - return g_mainExitCode; + ComPtr app = Make(); + return app->exec(argc, argv); } -- cgit v1.2.3 From 807ec8ea48281d5dbe365895fd9679da5b6753a5 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 12 Aug 2015 12:43:54 +0300 Subject: winrt: Refactor platform plugin for XAML support By using XAML as the platform compositor, many benefits are possible: - Better input context handling for tablets - Better multiple window support (including non-fullscreen windows) - Support for transparent windows and window opacity - Integration with native platform controls - Simpler orientation handling on Windows Phone with built-in transitions This patch applies only the minimal parts to make XAML mode work just as the raw D3D mode. It does this by: - Moving all OpenGL parts into QWinRTEGLContext. This will allow us to have non-OpenGL windows later (e.g. Direct2D raster surfaces). - Moving more window-specific parts into QWinRTWindow. Each window creates a SwapChainPanel which can then be used for ANGLE (or Direct2D) content. - Moving non screen-specific parts into QWinRTIntegration. - Having QWinRTScreen create the base XAML element Canvas. - Running certain calls on the UI thread where necessary. The following code parts were removed: - The UIAutomationCore code in QWinRTInputContext, as this is incompatible with XAML automation. - The D3D Trim and device blacklist, as these have been fixed in ANGLE. - Core dispatcher processing in QEventDispatcherWinRT. Now there is only one native event dispatcher; it is always running and never needs to be pumped. Future commits should address: - Maintaining the window stack list and visibility using the XAML Canvas. - Allowing for windows (e.g. popups) to be sized and positioned instead of fullscreen. - Using the XAML automation API to improve the platform input context. [ChangeLog][QPA][winrt] Windows Store apps are now composited inside a XAML container, allowing for tighter integration with the native UI layer. Change-Id: I285c6dea657c5dab2fda2b1bd8e8e5dd15882c72 Reviewed-by: Oliver Wolff --- src/corelib/kernel/qeventdispatcher_winrt.cpp | 108 +++---- src/corelib/kernel/qeventdispatcher_winrt_p.h | 4 + src/plugins/platforms/winrt/qwinrtcursor.cpp | 23 +- src/plugins/platforms/winrt/qwinrteglcontext.cpp | 133 +++++++-- src/plugins/platforms/winrt/qwinrteglcontext.h | 22 +- src/plugins/platforms/winrt/qwinrtinputcontext.cpp | 131 +-------- src/plugins/platforms/winrt/qwinrtinputcontext.h | 29 +- src/plugins/platforms/winrt/qwinrtintegration.cpp | 173 +++++++++++- src/plugins/platforms/winrt/qwinrtintegration.h | 43 ++- src/plugins/platforms/winrt/qwinrtscreen.cpp | 312 +++++---------------- src/plugins/platforms/winrt/qwinrtscreen.h | 33 +-- src/plugins/platforms/winrt/qwinrtwindow.cpp | 160 +++++++++-- src/plugins/platforms/winrt/qwinrtwindow.h | 8 +- 13 files changed, 623 insertions(+), 556 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index eceba8d002..f771974a24 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,23 @@ struct WinRTTimerInfo : public QAbstractEventDispatcher::TimerInfo { quint64 targetTime; }; +class AgileDispatchedHandler : public RuntimeClass, IDispatchedHandler, IAgileObject> +{ +public: + AgileDispatchedHandler(const std::function &delegate) + : delegate(delegate) + { + } + + HRESULT __stdcall Invoke() + { + return delegate(); + } + +private: + std::function delegate; +}; + class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate { Q_DECLARE_PUBLIC(QEventDispatcherWinRT) @@ -80,8 +98,6 @@ public: private: ComPtr timerFactory; - ComPtr coreDispatcher; - QPointer thread; QHash timerIdToObject; QVector timerInfos; @@ -136,40 +152,11 @@ private: } return true; } - - void fetchCoreDispatcher() - { - ComPtr application; - HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&application)); - RETURN_VOID_IF_FAILED("Failed to get the application factory"); - - static ComPtr view; - if (view) - return; - - hr = application->get_MainView(&view); - RETURN_VOID_IF_FAILED("Failed to get the main view"); - - ComPtr view2; - hr = view.As(&view2); - RETURN_VOID_IF_FAILED("Failed to cast the main view"); - - hr = view2->get_Dispatcher(&coreDispatcher); - if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) // expected in thread pool cases - return; - RETURN_VOID_IF_FAILED("Failed to get core dispatcher"); - - thread = QThread::currentThread(); - } }; QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent) : QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent) { - Q_D(QEventDispatcherWinRT); - - d->fetchCoreDispatcher(); } QEventDispatcherWinRT::QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent) @@ -180,25 +167,43 @@ QEventDispatcherWinRT::~QEventDispatcherWinRT() { } +HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function &delegate) +{ + static __declspec(thread) ICoreDispatcher *dispatcher = nullptr; + if (!dispatcher) { + HRESULT hr; + ComPtr application; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&application)); + ComPtr view; + hr = application->get_MainView(&view); + Q_ASSERT_SUCCEEDED(hr); + ComPtr window; + hr = view->get_CoreWindow(&window); + Q_ASSERT_SUCCEEDED(hr); + hr = window->get_Dispatcher(&dispatcher); + Q_ASSERT_SUCCEEDED(hr); + } + + HRESULT hr; + boolean onXamlThread; + hr = dispatcher->get_HasThreadAccess(&onXamlThread); + Q_ASSERT_SUCCEEDED(hr); + if (onXamlThread) // Already there + return delegate(); + + ComPtr op; + hr = dispatcher->RunAsync(CoreDispatcherPriority_Normal, Make(delegate).Get(), &op); + if (FAILED(hr)) + return hr; + return QWinRTFunctions::await(op); +} + bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherWinRT); - if (d->thread && d->thread != QThread::currentThread()) - d->fetchCoreDispatcher(); - do { - // Process native events - if (d->coreDispatcher) { - boolean hasThreadAccess; - HRESULT hr = d->coreDispatcher->get_HasThreadAccess(&hasThreadAccess); - if (SUCCEEDED(hr) && hasThreadAccess) { - hr = d->coreDispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent); - if (FAILED(hr)) - qErrnoWarning(hr, "Failed to process events"); - } - } - // Additional user events have to be handled before timer events, but the function may not // return yet. const bool userEventsSent = sendPostedEvents(flags); @@ -284,10 +289,11 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy TimeSpan period; period.Duration = interval ? (interval * 10000) : 1; // TimeSpan is based on 100-nanosecond units - IThreadPoolTimer *timer; const HANDLE handle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE | EVENT_MODIFY_STATE); const HANDLE cancelHandle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE|EVENT_MODIFY_STATE); - HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion( + HRESULT hr = runOnXamlThread([&]() { + IThreadPoolTimer *timer; + HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion( Callback([handle, cancelHandle](IThreadPoolTimer *timer) { DWORD cancelResult = WaitForSingleObjectEx(cancelHandle, 0, TRUE); if (cancelResult == WAIT_OBJECT_0) { @@ -306,13 +312,15 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy CloseHandle(cancelHandle); return S_OK; }).Get(), &timer); + RETURN_HR_IF_FAILED("Failed to create periodic timer"); + + d->addTimer(timerId, interval, timerType, object, handle, cancelHandle); + return hr; + }); if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to create periodic timer"); CloseHandle(handle); CloseHandle(cancelHandle); - return; } - d->addTimer(timerId, interval, timerType, object, handle, cancelHandle); } bool QEventDispatcherWinRT::unregisterTimer(int timerId) diff --git a/src/corelib/kernel/qeventdispatcher_winrt_p.h b/src/corelib/kernel/qeventdispatcher_winrt_p.h index fd3d259c96..073aa1c121 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt_p.h +++ b/src/corelib/kernel/qeventdispatcher_winrt_p.h @@ -50,6 +50,8 @@ #include +namespace std { template class function; } + QT_BEGIN_NAMESPACE quint64 qt_msectime(); @@ -65,6 +67,8 @@ public: explicit QEventDispatcherWinRT(QObject *parent = 0); ~QEventDispatcherWinRT(); + static HRESULT runOnXamlThread(const std::function &delegate); + bool processEvents(QEventLoop::ProcessEventsFlags flags); bool hasPendingEvents(); diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index 94ce23bd2c..707f3bf0ba 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -36,11 +36,13 @@ #include "qwinrtcursor.h" #include "qwinrtscreen.h" +#include #include #include #include +#include #include #include #include @@ -77,12 +79,17 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) { Q_D(QWinRTCursor); + HRESULT hr; ICoreWindow *coreWindow = static_cast(window->screen()->handle())->coreWindow(); CoreCursorType type; switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) { case Qt::BlankCursor: - coreWindow->put_PointerCursor(Q_NULLPTR); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow]() { + coreWindow->put_PointerCursor(Q_NULLPTR); + return S_OK; + }); + RETURN_VOID_IF_FAILED("Failed to set blank native cursor"); return; default: case Qt::OpenHandCursor: @@ -142,11 +149,13 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) } ComPtr cursor; - HRESULT hr = d->cursorFactory->CreateCursor(type, 0, &cursor); + hr = d->cursorFactory->CreateCursor(type, 0, &cursor); RETURN_VOID_IF_FAILED("Failed to create native cursor."); - hr = coreWindow->put_PointerCursor(cursor.Get()); - RETURN_VOID_IF_FAILED("Failed to set native cursor."); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &cursor]() { + return coreWindow->put_PointerCursor(cursor.Get()); + }); + RETURN_VOID_IF_FAILED("Failed to set native cursor"); } #endif // QT_NO_CURSOR @@ -154,8 +163,12 @@ QPoint QWinRTCursor::pos() const { ICoreWindow *coreWindow = static_cast(QGuiApplication::primaryScreen()->handle())->coreWindow(); + HRESULT hr; Point point; - coreWindow->get_PointerPosition(&point); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point]() { + return coreWindow->get_PointerPosition(&point); + }); + RETURN_IF_FAILED("Failed to get native cursor position", QPoint()); return QPoint(point.X, point.Y); } diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 42ffe8f716..44aab266ca 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -35,38 +35,131 @@ ****************************************************************************/ #include "qwinrteglcontext.h" +#include "qwinrtwindow.h" +#include +#include + +#include #define EGL_EGLEXT_PROTOTYPES -#include "EGL/eglext.h" +#include + +#include +#include QT_BEGIN_NAMESPACE -QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config) - : QEGLPlatformContext(format, share, display, &config), m_eglSurface(surface) +class QWinRTEGLContextPrivate +{ +public: + QSurfaceFormat format; + EGLDisplay eglDisplay; + EGLConfig eglConfig; + EGLContext eglContext; + QHash surfaceForWindow; +}; + +QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context) + : d_ptr(new QWinRTEGLContextPrivate) +{ + Q_D(QWinRTEGLContext); + d->format = context->format(); + d->format.setRenderableType(QSurfaceFormat::OpenGLES); +} + +QWinRTEGLContext::~QWinRTEGLContext() { + Q_D(QWinRTEGLContext); + foreach (const EGLSurface &surface, d->surfaceForWindow) + eglDestroySurface(d->eglDisplay, surface); + if (d->eglContext != EGL_NO_CONTEXT) + eglDestroyContext(d->eglDisplay, d->eglContext); + if (d->eglDisplay != EGL_NO_DISPLAY) + eglTerminate(d->eglDisplay); } -void QWinRTEGLContext::swapBuffers(QPlatformSurface *surface) +void QWinRTEGLContext::initialize() { -#ifdef Q_OS_WINPHONE - const QSize size = surface->surface()->size(); - eglPostSubBufferNV(eglDisplay(), eglSurfaceForPlatformSurface(surface), - 0, 0, size.width(), size.height()); -#else - eglSwapBuffers(eglDisplay(), eglSurfaceForPlatformSurface(surface)); -#endif + Q_D(QWinRTEGLContext); + + eglBindAPI(EGL_OPENGL_ES_API); + d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (d->eglDisplay == EGL_NO_DISPLAY) + qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); + + if (!eglInitialize(d->eglDisplay, nullptr, nullptr)) + qCritical("Failed to initialize EGL: 0x%x", eglGetError()); + + d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->format); + + const EGLint flags = d->format.testOption(QSurfaceFormat::DebugContext) + ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0; + const EGLint attributes[] = { + EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(), + EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(), + EGL_CONTEXT_FLAGS_KHR, flags, + EGL_NONE + }; + d->eglContext = eglCreateContext(d->eglDisplay, d->eglConfig, nullptr, attributes); + if (d->eglContext == EGL_NO_CONTEXT) { + qWarning("QEGLPlatformContext: Failed to create context: %x", eglGetError()); + return; + } } -EGLSurface QWinRTEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +bool QWinRTEGLContext::makeCurrent(QPlatformSurface *windowSurface) { - if (surface->surface()->surfaceClass() == QSurface::Window) { - // All windows use the same surface - return m_eglSurface; - } else { - // TODO: return EGL surfaces for offscreen surfaces - qWarning("This plugin does not support offscreen surfaces."); - return EGL_NO_SURFACE; + Q_D(QWinRTEGLContext); + Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface); + + EGLSurface surface = d->surfaceForWindow.value(windowSurface); + if (surface == EGL_NO_SURFACE) { + QWinRTWindow *window = static_cast(windowSurface); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, window, &surface]() { + surface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, + reinterpret_cast(window->winId()), + nullptr); + if (surface == EGL_NO_SURFACE) { + qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); + return E_FAIL; + } + return S_OK; + }); + if (FAILED(hr)) + return false; + d->surfaceForWindow.insert(windowSurface, surface); } + + const bool ok = eglMakeCurrent(d->eglDisplay, surface, surface, d->eglContext); + if (!ok) { + qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError()); + return false; + } + + eglSwapInterval(d->eglDisplay, d->format.swapInterval()); + return true; +} + +void QWinRTEGLContext::doneCurrent() +{ + Q_D(const QWinRTEGLContext); + const bool ok = eglMakeCurrent(d->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError()); +} + +void QWinRTEGLContext::swapBuffers(QPlatformSurface *windowSurface) +{ + Q_D(QWinRTEGLContext); + Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface); + + eglSwapBuffers(d->eglDisplay, d->surfaceForWindow.value(windowSurface)); +} + +QSurfaceFormat QWinRTEGLContext::format() const +{ + Q_D(const QWinRTEGLContext); + return d->format; } QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName) @@ -221,7 +314,7 @@ QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName) if (i != standardFuncs.end()) return i.value(); - return QEGLPlatformContext::getProcAddress(procName); + return eglGetProcAddress(procName.constData()); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index 958d623c4c..31a2124b03 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -37,23 +37,29 @@ #ifndef QWINDOWSEGLCONTEXT_H #define QWINDOWSEGLCONTEXT_H -#include +#include QT_BEGIN_NAMESPACE -class QWinRTEGLContext : public QEGLPlatformContext +class QWinRTEGLContextPrivate; +class QWinRTEGLContext : public QPlatformOpenGLContext { public: - explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config); + explicit QWinRTEGLContext(QOpenGLContext *context); + ~QWinRTEGLContext(); - void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + void initialize() Q_DECL_OVERRIDE; + + bool makeCurrent(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE; -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + QSurfaceFormat format() const Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; private: - EGLSurface m_eglSurface; + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QWinRTEGLContext) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index c94b53ef1c..7bd9e87ca6 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -182,135 +182,6 @@ void QWinRTInputContext::hideInputPanel() qErrnoWarning(hr, "Failed to hide input panel."); } -#else // Q_OS_WINPHONE - -// IRawElementProviderSimple -HRESULT QWinRTInputContext::get_ProviderOptions(ProviderOptions *retVal) -{ - *retVal = ProviderOptions_ServerSideProvider|ProviderOptions_UseComThreading; - return S_OK; -} - -HRESULT QWinRTInputContext::GetPatternProvider(PATTERNID id, IUnknown **retVal) -{ - switch (id) { - case 10002: //UIA_ValuePatternId - return QueryInterface(__uuidof(IValueProvider), (void**)retVal); - break; - case 10014: //UIA_TextPatternId: - return QueryInterface(__uuidof(ITextProvider), (void**)retVal); - case 10029: //UIA_TextChildPatternId: - *retVal = nullptr; - break; - default: - qWarning("Unhandled pattern ID: %d", id); - break; - } - return S_OK; -} - -HRESULT QWinRTInputContext::GetPropertyValue(PROPERTYID idProp, VARIANT *retVal) -{ - switch (idProp) { - case 30003: //UIA_ControlTypePropertyId - retVal->vt = VT_I4; - retVal->lVal = 50025; //UIA_CustomControlTypeId - break; - case 30008: //UIA_IsKeyboardFocusablePropertyId - case 30009: //UIA_HasKeyboardFocusPropertyId - // These are probably never actually called - case 30016: //UIA_IsControlElementPropertyId - case 30017: //UIA_IsContentElementPropertyId - retVal->vt = VT_BOOL; - retVal->boolVal = VARIANT_TRUE; - break; - case 30019: //UIA_IsPasswordPropertyId - retVal->vt = VT_BOOL; - retVal->boolVal = VARIANT_FALSE; - break; - case 30020: //UIA_NativeWindowHandlePropertyId - retVal->vt = VT_PTR; - retVal->punkVal = m_screen->coreWindow(); - break; - } - return S_OK; -} - -HRESULT QWinRTInputContext::get_HostRawElementProvider(IRawElementProviderSimple **retVal) -{ - // Return the window's element provider - IInspectable *hostProvider; - HRESULT hr = m_screen->coreWindow()->get_AutomationHostProvider(&hostProvider); - if (SUCCEEDED(hr)) { - hr = hostProvider->QueryInterface(IID_PPV_ARGS(retVal)); - hostProvider->Release(); - } - return hr; -} - -// ITextProvider -HRESULT QWinRTInputContext::GetSelection(SAFEARRAY **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::GetVisibleRanges(SAFEARRAY **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::RangeFromPoint(UiaPoint, ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::get_DocumentRange(ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::get_SupportedTextSelection(SupportedTextSelection *) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -// IValueProvider -HRESULT QWinRTInputContext::SetValue(LPCWSTR) -{ - // To be useful, requires listening to the focus object for a value change and raising an event - // May be useful for inputPanel autocomplete, etc. - return S_OK; -} - -HRESULT QWinRTInputContext::get_Value(BSTR *) -{ - // To be useful, requires listening to the focus object for a value change and raising an event - // May be useful for inputPanel autocomplete, etc. - return S_OK; -} - -HRESULT QWinRTInputContext::get_IsReadOnly(BOOL *isReadOnly) -{ - // isReadOnly dictates keyboard opening behavior when view is tapped. - // We need to decide if the user tapped within a control which is about to receive focus... - // Since this isn't possible (this function gets called before we receive the touch event), - // the most platform-aligned option is to show the keyboard if an editable item has focus, - // and close the keyboard if it is already open. - *isReadOnly = m_isInputPanelVisible || !inputMethodAccepted(); - return S_OK; -} - -#endif // !Q_OS_WINPHONE +#endif // Q_OS_WINPHONE QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h index ce7fbabf49..cc3bce435f 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.h +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.h @@ -41,9 +41,6 @@ #include #include -#ifndef Q_OS_WINPHONE -# include -#endif namespace ABI { namespace Windows { @@ -63,11 +60,6 @@ QT_BEGIN_NAMESPACE class QWinRTScreen; class QWinRTInputContext : public QPlatformInputContext -#ifndef Q_OS_WINPHONE - , public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IRawElementProviderSimple, ITextProvider, IValueProvider> -#endif // !Q_OS_WINPHONE { public: explicit QWinRTInputContext(QWinRTScreen *); @@ -79,26 +71,7 @@ public: #ifdef Q_OS_WINPHONE void showInputPanel(); void hideInputPanel(); -#else // Q_OS_WINPHONE - // IRawElementProviderSimple - HRESULT __stdcall get_ProviderOptions(ProviderOptions *retVal); - HRESULT __stdcall GetPatternProvider(PATTERNID, IUnknown **); - HRESULT __stdcall GetPropertyValue(PROPERTYID idProp, VARIANT *retVal); - HRESULT __stdcall get_HostRawElementProvider(IRawElementProviderSimple **retVal); - - // ITextProvider - HRESULT __stdcall GetSelection(SAFEARRAY **); - HRESULT __stdcall GetVisibleRanges(SAFEARRAY **); - HRESULT __stdcall RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **); - HRESULT __stdcall RangeFromPoint(UiaPoint, ITextRangeProvider **); - HRESULT __stdcall get_DocumentRange(ITextRangeProvider **); - HRESULT __stdcall get_SupportedTextSelection(SupportedTextSelection *); - - // IValueProvider - HRESULT __stdcall SetValue(LPCWSTR); - HRESULT __stdcall get_Value(BSTR *); - HRESULT __stdcall get_IsReadOnly(BOOL *); -#endif // !Q_OS_WINPHONE +#endif private: HRESULT onShowing(ABI::Windows::UI::ViewManagement::IInputPane *, diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 70ee6dbe6a..7079d46523 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -45,37 +45,138 @@ #include "qwinrtfontdatabase.h" #include "qwinrttheme.h" +#include +#include #include +#include +#include #include +#include +#include +#include #include #include -#include +#include +#ifdef Q_OS_WINPHONE +# include +#endif using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::ApplicationModel; +using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::UI; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::ViewManagement; +using namespace ABI::Windows::Graphics::Display; using namespace ABI::Windows::ApplicationModel::Core; +#ifdef Q_OS_WINPHONE +using namespace ABI::Windows::Phone::UI::Input; +#endif + +typedef IEventHandler ResumeHandler; +typedef IEventHandler SuspendHandler; +#ifdef Q_OS_WINPHONE +typedef IEventHandler BackPressedHandler; +#endif QT_BEGIN_NAMESPACE -QWinRTIntegration::QWinRTIntegration() - : m_success(false) - , m_fontDatabase(new QWinRTFontDatabase) - , m_services(new QWinRTServices) +typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); +uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#ifdef Q_OS_WINPHONE +typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); +uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#endif + +class QWinRTIntegrationPrivate +{ +public: + QPlatformFontDatabase *fontDatabase; + QPlatformServices *platformServices; + QWinRTScreen *mainScreen; + QScopedPointer inputContext; + + ComPtr application; + QHash applicationTokens; +#ifdef Q_OS_WINPHONE + ComPtr hardwareButtons; + QHash buttonsTokens; +#endif +}; + +QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) { - m_screen = new QWinRTScreen; - screenAdded(m_screen); + Q_D(QWinRTIntegration); + + d->fontDatabase = new QWinRTFontDatabase; + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&d->application)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Suspending(Callback(this, &QWinRTIntegration::onSuspended).Get(), + &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Resuming(Callback(this, &QWinRTIntegration::onResume).Get(), + &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); - m_success = true; +#ifdef Q_OS_WINPHONE + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), + IID_PPV_ARGS(&d->hardwareButtons)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->hardwareButtons->add_BackPressed(Callback(this, &QWinRTIntegration::onBackButtonPressed).Get(), + &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); + Q_ASSERT_SUCCEEDED(hr); +#endif // Q_OS_WINPHONE + + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr windowStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Window).Get(), + IID_PPV_ARGS(&windowStatics)); + Q_ASSERT_SUCCEEDED(hr); + ComPtr window; + hr = windowStatics->get_Current(&window); + Q_ASSERT_SUCCEEDED(hr); + hr = window->Activate(); + Q_ASSERT_SUCCEEDED(hr); + + d->mainScreen = new QWinRTScreen(window.Get()); + d->inputContext.reset(new QWinRTInputContext(d->mainScreen)); + screenAdded(d->mainScreen); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); } QWinRTIntegration::~QWinRTIntegration() { + Q_D(QWinRTIntegration); + HRESULT hr; +#ifdef Q_OS_WINPHONE + for (QHash::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) { + hr = (d->hardwareButtons.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } +#endif + for (QHash::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) { + hr = (d->application.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + destroyScreen(d->mainScreen); Windows::Foundation::Uninitialize(); } +bool QWinRTIntegration::succeeded() const +{ + Q_D(const QWinRTIntegration); + return d->mainScreen; +} + QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const { return new QWinRTEventDispatcher; @@ -112,28 +213,31 @@ QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *wi QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - QWinRTScreen *screen = static_cast(context->screen()->handle()); - return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface(), screen->eglConfig()); + return new QWinRTEGLContext(context); } QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const { - return m_fontDatabase; + Q_D(const QWinRTIntegration); + return d->fontDatabase; } QPlatformInputContext *QWinRTIntegration::inputContext() const { - return m_screen->inputContext(); + Q_D(const QWinRTIntegration); + return d->inputContext.data(); } QPlatformServices *QWinRTIntegration::services() const { - return m_services; + Q_D(const QWinRTIntegration); + return d->platformServices; } Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const { - return m_screen->keyboardModifiers(); + Q_D(const QWinRTIntegration); + return d->mainScreen->keyboardModifiers(); } QStringList QWinRTIntegration::themeNames() const @@ -149,4 +253,45 @@ name) const return 0; } + +// System-level integration points + +#ifdef Q_OS_WINPHONE +HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) +{ + Q_D(QWinRTIntegration); + + QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); + QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); + backPress.setAccepted(false); + backRelease.setAccepted(false); + + QWindow *window = d->mainScreen->topWindow(); + QObject *receiver = window ? static_cast(window) + : static_cast(QCoreApplication::instance()); + + // If the event is ignored, the app go to the background + QCoreApplication::sendEvent(receiver, &backPress); + QCoreApplication::sendEvent(receiver, &backRelease); + args->put_Handled(backPress.isAccepted() || backRelease.isAccepted()); + + return S_OK; +} +#endif // Q_OS_WINPHONE + +HRESULT QWinRTIntegration::onSuspended(IInspectable *, ISuspendingEventArgs *) +{ + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); + QWindowSystemInterface::flushWindowSystemEvents(); + return S_OK; +} + +HRESULT QWinRTIntegration::onResume(IInspectable *, IInspectable *) +{ + // First the system invokes onResume and then changes + // the visibility of the screen to be active. + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden); + return S_OK; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index bbd6c1e41b..0115e034b5 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -39,11 +39,33 @@ #include +namespace ABI { + namespace Windows { + namespace ApplicationModel { + struct ISuspendingEventArgs; + } + namespace Foundation { + struct IAsyncAction; + } +#ifdef Q_OS_WINPHONE + namespace Phone { + namespace UI { + namespace Input { + struct IBackPressedEventArgs; + } + } + } +#endif + } +} +struct IAsyncInfo; +struct IInspectable; + QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; -class QWinRTScreen; +class QWinRTIntegrationPrivate; class QWinRTIntegration : public QPlatformIntegration { private: @@ -53,10 +75,12 @@ public: static QWinRTIntegration *create() { - QWinRTIntegration *integration = new QWinRTIntegration; - return integration->m_success ? integration : 0; + QScopedPointer integration(new QWinRTIntegration); + return integration->succeeded() ? integration.take() : nullptr; } + bool succeeded() const; + bool hasCapability(QPlatformIntegration::Capability cap) const; QVariant styleHint(StyleHint hint) const; @@ -71,11 +95,16 @@ public: QStringList themeNames() const; QPlatformTheme *createPlatformTheme(const QString &name) const; + private: - bool m_success; - QWinRTScreen *m_screen; - QPlatformFontDatabase *m_fontDatabase; - QPlatformServices *m_services; +#ifdef Q_OS_WINPHONE + HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); +#endif + HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); + HRESULT onResume(IInspectable *, IInspectable *); + + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QWinRTIntegration) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 1d36bb31f6..89ad33657b 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -36,26 +36,18 @@ #include "qwinrtscreen.h" -#define EGL_EGLEXT_PROTOTYPES -#include -#include -#include -#ifndef Q_OS_WINPHONE -#include -#endif - #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" -#include "qwinrteglcontext.h" +#include #include #include -#include #include #include #include +#include #include #include #include @@ -64,12 +56,10 @@ #include #include #include +#include #include #include #include -#ifdef Q_OS_WINPHONE -#include -#endif using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -77,17 +67,13 @@ using namespace ABI::Windows::ApplicationModel; using namespace ABI::Windows::ApplicationModel::Core; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::System; +using namespace ABI::Windows::UI; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::Input; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::Devices::Input; using namespace ABI::Windows::Graphics::Display; -#ifdef Q_OS_WINPHONE -using namespace ABI::Windows::Phone::UI::Input; -#endif -typedef IEventHandler ResumeHandler; -typedef IEventHandler SuspendHandler; typedef ITypedEventHandler ActivatedHandler; typedef ITypedEventHandler ClosedHandler; typedef ITypedEventHandler CharacterReceivedHandler; @@ -96,11 +82,7 @@ typedef ITypedEventHandler KeyHandler; typedef ITypedEventHandler PointerHandler; typedef ITypedEventHandler SizeChangedHandler; typedef ITypedEventHandler VisibilityChangedHandler; -typedef ITypedEventHandler AutomationProviderRequestedHandler; typedef ITypedEventHandler DisplayInformationHandler; -#ifdef Q_OS_WINPHONE -typedef IEventHandler BackPressedHandler; -#endif QT_BEGIN_NAMESPACE @@ -419,33 +401,23 @@ static inline Qt::Key qKeyFromCode(quint32 code, int mods) return static_cast(code & 0xff); } -typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); -uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken); uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken); uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#ifdef Q_OS_WINPHONE -typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); -uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#endif class QWinRTScreenPrivate { public: - ComPtr application; + QTouchDevice *touchDevice; ComPtr coreWindow; + ComPtr canvas; + ComPtr view; ComPtr displayInformation; -#ifdef Q_OS_WINPHONE - ComPtr hardwareButtons; -#endif QScopedPointer cursor; -#ifdef Q_OS_WINPHONE - QScopedPointer inputContext; -#else - ComPtr inputContext; -#endif + + QHash touchPoints; QSizeF logicalSize; QSurfaceFormat surfaceFormat; @@ -458,68 +430,30 @@ public: #ifndef Q_OS_WINPHONE QHash> activeKeys; #endif - QTouchDevice *touchDevice; - QHash touchPoints; - EGLDisplay eglDisplay; - EGLSurface eglSurface; - EGLConfig eglConfig; - - QHash applicationTokens; QHash windowTokens; QHash displayTokens; -#ifdef Q_OS_WINPHONE - QHash buttonsTokens; -#endif }; -QWinRTScreen::QWinRTScreen() +// To be called from the XAML thread +QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow) : d_ptr(new QWinRTScreenPrivate) { Q_D(QWinRTScreen); d->orientation = Qt::PrimaryOrientation; d->touchDevice = Q_NULLPTR; - d->eglDisplay = EGL_NO_DISPLAY; - // Obtain the WinRT Application, view, and window HRESULT hr; - hr = RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&d->application)); - Q_ASSERT_SUCCEEDED(hr); - hr = d->application->add_Suspending(Callback(this, &QWinRTScreen::onSuspended).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); - Q_ASSERT_SUCCEEDED(hr); - hr = d->application->add_Resuming(Callback(this, &QWinRTScreen::onResume).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); - Q_ASSERT_SUCCEEDED(hr); - - ComPtr view; - hr = d->application->GetCurrentView(&view); - Q_ASSERT_SUCCEEDED(hr); - hr = view->get_CoreWindow(&d->coreWindow); + hr = xamlWindow->get_CoreWindow(&d->coreWindow); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->Activate(); Q_ASSERT_SUCCEEDED(hr); -#ifdef Q_OS_WINPHONE - d->inputContext.reset(new QWinRTInputContext(this)); -#else - d->inputContext = Make(this); -#endif - Rect rect; hr = d->coreWindow->get_Bounds(&rect); Q_ASSERT_SUCCEEDED(hr); d->logicalSize = QSizeF(rect.Width, rect.Height); - d->surfaceFormat.setAlphaBufferSize(0); - d->surfaceFormat.setRedBufferSize(8); - d->surfaceFormat.setGreenBufferSize(8); - d->surfaceFormat.setBlueBufferSize(8); - d->surfaceFormat.setDepthBufferSize(24); - d->surfaceFormat.setStencilBufferSize(8); - d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); - d->surfaceFormat.setSamples(1); - d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - hr = d->coreWindow->add_KeyDown(Callback(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_KeyUp(Callback(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]); @@ -538,24 +472,14 @@ QWinRTScreen::QWinRTScreen() Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_PointerWheelChanged(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); Q_ASSERT_SUCCEEDED(hr); -#ifndef Q_OS_WINPHONE hr = d->coreWindow->add_SizeChanged(Callback(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); Q_ASSERT_SUCCEEDED(hr); -#endif hr = d->coreWindow->add_Activated(Callback(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_Closed(Callback(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_VisibilityChanged(Callback(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]); Q_ASSERT_SUCCEEDED(hr); - hr = d->coreWindow->add_AutomationProviderRequested(Callback(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &d->windowTokens[&ICoreWindow::remove_AutomationProviderRequested]); - Q_ASSERT_SUCCEEDED(hr); -#ifdef Q_OS_WINPHONE - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), IID_PPV_ARGS(&d->hardwareButtons)); - Q_ASSERT_SUCCEEDED(hr); - hr = d->hardwareButtons->add_BackPressed(Callback(this, &QWinRTScreen::onBackButtonPressed).Get(), &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); - Q_ASSERT_SUCCEEDED(hr); -#endif // Q_OS_WINPHONE // Orientation handling ComPtr displayInformationStatics; @@ -583,45 +507,34 @@ QWinRTScreen::QWinRTScreen() d->orientation = d->nativeOrientation; onOrientationChanged(Q_NULLPTR, Q_NULLPTR); - d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (d->eglDisplay == EGL_NO_DISPLAY) - qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); - - if (!eglInitialize(d->eglDisplay, NULL, NULL)) - qCritical("Failed to initialize EGL: 0x%x", eglGetError()); - - // Check that the device properly supports depth/stencil rendering, and disable them if not - ComPtr d3dDevice; - const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); - if (ok && d3dDevice) { - ComPtr dxgiDevice; - hr = d3dDevice.As(&dxgiDevice); - if (SUCCEEDED(hr)) { - ComPtr dxgiAdapter; - hr = dxgiDevice->GetAdapter(&dxgiAdapter); - if (SUCCEEDED(hr)) { - ComPtr dxgiAdapter2; - hr = dxgiAdapter.As(&dxgiAdapter2); - if (SUCCEEDED(hr)) { - DXGI_ADAPTER_DESC2 desc; - hr = dxgiAdapter2->GetDesc2(&desc); - if (SUCCEEDED(hr)) { - // The following GPUs do not render properly with depth/stencil - if ((desc.VendorId == 0x4d4f4351 && desc.DeviceId == 0x32303032)) { // Qualcomm Adreno 225 - d->surfaceFormat.setDepthBufferSize(-1); - d->surfaceFormat.setStencilBufferSize(-1); - } - } - } - } - } - } + ComPtr applicationViewStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), + IID_PPV_ARGS(&applicationViewStatics)); + RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics"); - d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat); - d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat); - d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), NULL); - if (d->eglSurface == EGL_NO_SURFACE) - qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); + hr = applicationViewStatics->GetForCurrentView(&d->view); + RETURN_VOID_IF_FAILED("Could not access currentView"); + + // Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added + ComPtr canvas; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas); + Q_ASSERT_SUCCEEDED(hr); + ComPtr frameworkElement; + hr = canvas.As(&frameworkElement); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Width(d->logicalSize.width()); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Height(d->logicalSize.height()); + Q_ASSERT_SUCCEEDED(hr); + ComPtr uiElement; + hr = canvas.As(&uiElement); + Q_ASSERT_SUCCEEDED(hr); + hr = xamlWindow->put_Content(uiElement.Get()); + Q_ASSERT_SUCCEEDED(hr); + hr = canvas.As(&d->canvas); + Q_ASSERT_SUCCEEDED(hr); + + d->cursor.reset(new QWinRTCursor); } QWinRTScreen::~QWinRTScreen() @@ -629,16 +542,20 @@ QWinRTScreen::~QWinRTScreen() Q_D(QWinRTScreen); // Unregister callbacks - for (QHash::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) - (d->application.Get()->*i.key())(i.value()); - for (QHash::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) - (d->coreWindow.Get()->*i.key())(i.value()); - for (QHash::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) - (d->displayInformation.Get()->*i.key())(i.value()); -#ifdef Q_OS_WINPHONE - for (QHash::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) - (d->hardwareButtons.Get()->*i.key())(i.value()); -#endif + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + for (QHash::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) { + hr = (d->coreWindow.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + for (QHash::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) { + hr = (d->displayInformation.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + return hr; + }); + RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks"); } QRect QWinRTScreen::geometry() const @@ -657,12 +574,6 @@ QImage::Format QWinRTScreen::format() const return QImage::Format_ARGB32_Premultiplied; } -QSurfaceFormat QWinRTScreen::surfaceFormat() const -{ - Q_D(const QWinRTScreen); - return d->surfaceFormat; -} - QSizeF QWinRTScreen::physicalSize() const { Q_D(const QWinRTScreen); @@ -682,21 +593,9 @@ qreal QWinRTScreen::scaleFactor() const return d->scaleFactor; } -QWinRTInputContext *QWinRTScreen::inputContext() const -{ - Q_D(const QWinRTScreen); -#ifdef Q_OS_WINPHONE - return d->inputContext.data(); -#else - return d->inputContext.Get(); -#endif -} - QPlatformCursor *QWinRTScreen::cursor() const { Q_D(const QWinRTScreen); - if (!d->cursor) - const_cast(d)->cursor.reset(new QWinRTCursor); return d->cursor.data(); } @@ -744,22 +643,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const return d->coreWindow.Get(); } -EGLDisplay QWinRTScreen::eglDisplay() const -{ - Q_D(const QWinRTScreen); - return d->eglDisplay; -} - -EGLSurface QWinRTScreen::eglSurface() const -{ - Q_D(const QWinRTScreen); - return d->eglSurface; -} - -EGLConfig QWinRTScreen::eglConfig() const +Xaml::IDependencyObject *QWinRTScreen::canvas() const { Q_D(const QWinRTScreen); - return d->eglConfig; + return d->canvas.Get(); } QWindow *QWinRTScreen::topWindow() const @@ -809,6 +696,20 @@ void QWinRTScreen::lower(QWindow *window) handleExpose(); } +void QWinRTScreen::updateWindowTitle() +{ + Q_D(QWinRTScreen); + + QWindow *window = topWindow(); + if (!window) + return; + + const QString title = window->title(); + HStringReference titleRef(reinterpret_cast(title.utf16()), title.length()); + HRESULT hr = d->view->put_Title(titleRef.Get()); + RETURN_VOID_IF_FAILED("Unable to set window title"); +} + void QWinRTScreen::handleExpose() { Q_D(QWinRTScreen); @@ -1055,17 +956,6 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) return S_OK; } -HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) -{ -#ifndef Q_OS_WINPHONE - Q_D(const QWinRTScreen); - args->put_AutomationProvider(d->inputContext.Get()); -#else - Q_UNUSED(args) -#endif - return S_OK; -} - HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *) { Q_D(QWinRTScreen); @@ -1075,18 +965,14 @@ HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs * hr = d->coreWindow->get_Bounds(&size); RETURN_OK_IF_FAILED("Failed to get window bounds"); QSizeF logicalSize = QSizeF(size.Width, size.Height); -#ifndef Q_OS_WINPHONE // This handler is called from orientation changed, in which case we should always update the size if (d->logicalSize == logicalSize) return S_OK; -#endif d->logicalSize = logicalSize; - if (d->eglDisplay) { - const QRect newGeometry = geometry(); - QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); - QPlatformScreen::resizeMaximizedWindows(); - handleExpose(); - } + const QRect newGeometry = geometry(); + QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); + QPlatformScreen::resizeMaximizedWindows(); + handleExpose(); return S_OK; } @@ -1110,31 +996,6 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args return S_OK; } -HRESULT QWinRTScreen::onSuspended(IInspectable *, ISuspendingEventArgs *) -{ -#ifndef Q_OS_WINPHONE - Q_D(QWinRTScreen); - ComPtr d3dDevice; - const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); - if (ok && d3dDevice) { - ComPtr dxgiDevice; - if (SUCCEEDED(d3dDevice.As(&dxgiDevice))) - dxgiDevice->Trim(); - } -#endif - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); - QWindowSystemInterface::flushWindowSystemEvents(); - return S_OK; -} - -HRESULT QWinRTScreen::onResume(IInspectable *, IInspectable *) -{ - // First the system invokes onResume and then changes - // the visibility of the screen to be active. - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden); - return S_OK; -} - HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *) { foreach (QWindow *w, QGuiApplication::topLevelWindows()) @@ -1165,10 +1026,6 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable * d->orientation = newOrientation; QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } - -#ifdef Q_OS_WINPHONE // The size changed handler is ignored in favor of this callback - onSizeChanged(Q_NULLPTR, Q_NULLPTR); -#endif return S_OK; } @@ -1205,27 +1062,4 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) return S_OK; } -#ifdef Q_OS_WINPHONE -HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) -{ - Q_D(QWinRTScreen); - - QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); - QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); - backPress.setAccepted(false); - backRelease.setAccepted(false); - - QObject *receiver = d->visibleWindows.isEmpty() - ? static_cast(QGuiApplication::instance()) - : static_cast(d->visibleWindows.first()); - - // If the event is ignored, the app will suspend - QGuiApplication::sendEvent(receiver, &backPress); - QGuiApplication::sendEvent(receiver, &backRelease); - args->put_Handled(backPress.isAccepted() || backRelease.isAccepted()); - - return S_OK; -} -#endif // Q_OS_WINPHONE - QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index d34ce75748..796e6abb80 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -40,8 +40,6 @@ #include #include -#include - namespace ABI { namespace Windows { namespace ApplicationModel { @@ -59,21 +57,16 @@ namespace ABI { struct IWindowActivatedEventArgs; struct IWindowSizeChangedEventArgs; } + namespace Xaml { + struct IDependencyObject; + struct IWindow; + } } namespace Graphics { namespace Display { struct IDisplayInformation; } } -#ifdef Q_OS_WINPHONE - namespace Phone { - namespace UI { - namespace Input { - struct IBackPressedEventArgs; - } - } - } -#endif } } struct IInspectable; @@ -81,23 +74,20 @@ struct IInspectable; QT_BEGIN_NAMESPACE class QTouchDevice; -class QWinRTEGLContext; class QWinRTCursor; class QWinRTInputContext; class QWinRTScreenPrivate; class QWinRTScreen : public QPlatformScreen { public: - explicit QWinRTScreen(); + explicit QWinRTScreen(ABI::Windows::UI::Xaml::IWindow *xamlWindow); ~QWinRTScreen(); QRect geometry() const; int depth() const; QImage::Format format() const; - QSurfaceFormat surfaceFormat() const; QSizeF physicalSize() const Q_DECL_OVERRIDE; QDpi logicalDpi() const Q_DECL_OVERRIDE; qreal scaleFactor() const; - QWinRTInputContext *inputContext() const; QPlatformCursor *cursor() const; Qt::KeyboardModifiers keyboardModifiers() const; @@ -110,10 +100,10 @@ public: void raise(QWindow *window); void lower(QWindow *window); + void updateWindowTitle(); + ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; - EGLDisplay eglDisplay() const; // To opengl context - EGLSurface eglSurface() const; // To window - EGLConfig eglConfig() const; + ABI::Windows::UI::Xaml::IDependencyObject *canvas() const; private: void handleExpose(); @@ -127,20 +117,13 @@ private: HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *); - HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); - HRESULT onResume(IInspectable *, IInspectable *); HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *); HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *); - HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *); HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -#ifdef Q_OS_WINPHONE - HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); -#endif - QScopedPointer d_ptr; Q_DECLARE_PRIVATE(QWinRTScreen) }; diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index adc5dfb776..634d62ef24 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -36,47 +36,138 @@ #include "qwinrtwindow.h" #include "qwinrtscreen.h" +#include -#include +#include +#define EGL_EGLEXT_PROTOTYPES +#include + +#include #include +#include #include -#include #include +#include +#include -#include -#include +#include #include +#include +#include +#include +#include +#include using namespace ABI::Windows::UI::ViewManagement; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI; QT_BEGIN_NAMESPACE +class QWinRTWindowPrivate +{ +public: + QWinRTScreen *screen; + + QSurfaceFormat surfaceFormat; + QString windowTitle; + + ComPtr swapChainPanel; +}; + QWinRTWindow::QWinRTWindow(QWindow *window) : QPlatformWindow(window) - , m_screen(static_cast(screen())) + , d_ptr(new QWinRTWindowPrivate) { + Q_D(QWinRTWindow); + + d->screen = static_cast(screen()); setWindowFlags(window->flags()); setWindowState(window->windowState()); setWindowTitle(window->title()); handleContentOrientationChange(window->contentOrientation()); + + d->surfaceFormat.setAlphaBufferSize(0); + d->surfaceFormat.setRedBufferSize(8); + d->surfaceFormat.setGreenBufferSize(8); + d->surfaceFormat.setBlueBufferSize(8); + d->surfaceFormat.setDepthBufferSize(24); + d->surfaceFormat.setStencilBufferSize(8); + d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); + d->surfaceFormat.setSamples(1); + d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + // Create a new swapchain and place it inside the canvas + HRESULT hr; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_SwapChainPanel).Get(), + &d->swapChainPanel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr uiElement; + hr = d->swapChainPanel.As(&uiElement); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr canvas = d->screen->canvas(); + ComPtr panel; + hr = canvas.As(&panel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr> children; + hr = panel->get_Children(&children); + Q_ASSERT_SUCCEEDED(hr); + hr = children->Append(uiElement.Get()); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + setGeometry(window->geometry()); } QWinRTWindow::~QWinRTWindow() { - m_screen->removeWindow(window()); + Q_D(QWinRTWindow); + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([d]() { + HRESULT hr; + ComPtr canvas = d->screen->canvas(); + ComPtr panel; + hr = canvas.As(&panel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr> children; + hr = panel->get_Children(&children); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr uiElement; + hr = d->swapChainPanel.As(&uiElement); + Q_ASSERT_SUCCEEDED(hr); + quint32 index; + boolean found; + hr = children->IndexOf(uiElement.Get(), &index, &found); + Q_ASSERT_SUCCEEDED(hr); + if (found) { + hr = children->RemoveAt(index); + Q_ASSERT_SUCCEEDED(hr); + } + return S_OK; + }); + RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down"); } QSurfaceFormat QWinRTWindow::format() const { - return m_screen->surfaceFormat(); + Q_D(const QWinRTWindow); + return d->surfaceFormat; } bool QWinRTWindow::isActive() const { - return m_screen->topWindow() == window(); + Q_D(const QWinRTWindow); + return d->screen->topWindow() == window(); } bool QWinRTWindow::isExposed() const @@ -87,55 +178,70 @@ bool QWinRTWindow::isExposed() const void QWinRTWindow::setGeometry(const QRect &rect) { + Q_D(QWinRTWindow); + if (window()->isTopLevel()) { - QPlatformWindow::setGeometry(m_screen->geometry()); + QPlatformWindow::setGeometry(d->screen->geometry()); QWindowSystemInterface::handleGeometryChange(window(), geometry()); } else { QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); } + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr frameworkElement; + hr = d->swapChainPanel.As(&frameworkElement); + Q_ASSERT_SUCCEEDED(hr); + const QSizeF size = QSizeF(geometry().size()) / d->screen->scaleFactor(); + hr = frameworkElement->put_Width(size.width()); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Height(size.height()); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); } void QWinRTWindow::setVisible(bool visible) { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; if (visible) - m_screen->addWindow(window()); + d->screen->addWindow(window()); else - m_screen->removeWindow(window()); + d->screen->removeWindow(window()); } void QWinRTWindow::setWindowTitle(const QString &title) { - ComPtr statics; - HRESULT hr; - - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), - IID_PPV_ARGS(&statics)); - RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics"); - - ComPtr view; - hr = statics->GetForCurrentView(&view); - RETURN_VOID_IF_FAILED("Could not access currentView"); - - HStringReference str(reinterpret_cast(title.utf16()), title.length()); - hr = view->put_Title(str.Get()); - RETURN_VOID_IF_FAILED("Unable to set window title"); + Q_D(QWinRTWindow); + d->windowTitle = title; + d->screen->updateWindowTitle(); } void QWinRTWindow::raise() { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - m_screen->raise(window()); + d->screen->raise(window()); } void QWinRTWindow::lower() { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - m_screen->lower(window()); + d->screen->lower(window()); +} + +WId QWinRTWindow::winId() const +{ + Q_D(const QWinRTWindow); + return WId(d->swapChainPanel.Get()); } qreal QWinRTWindow::devicePixelRatio() const diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 3cfe346ab2..88c149b080 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -42,8 +42,7 @@ QT_BEGIN_NAMESPACE -class QWinRTScreen; - +class QWinRTWindowPrivate; class QWinRTWindow : public QPlatformWindow { public: @@ -59,10 +58,13 @@ public: void raise(); void lower(); + WId winId() const Q_DECL_OVERRIDE; + qreal devicePixelRatio() const Q_DECL_OVERRIDE; private: - QWinRTScreen *m_screen; + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QWinRTWindow) }; QT_END_NAMESPACE -- cgit v1.2.3 From 194403a3483b7317cc9511bc8b2ab307775643c5 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 22 Dec 2014 18:25:13 +0100 Subject: Remove temporary string allocations when reading prepared statement. Instead, we use the binary MySQL encoding and copy the data directly into the QVariant of the desired type. This gets rid of the temporary string allocations and greatly improves the performance of the added benchmark. On my machine, the results are: Before: 0.562 msecs per iteration (total: 563, iterations: 1000) 1,922,479.330 instructions per iteration (total: 1,922,479,330, iterations: 1000) After: 0.381 msecs per iteration (total: 381, iterations: 1000) 774,132.957 instructions per iteration (total: 774,132,958, iterations: 1000) Note that the same could be applied to floating point data types in the future. Additionally, special support for MYSQL_TIME structure coult be added to get rid of the string conversions there. To ensure everything keeps working, a new auto test is added as well that verifies the select statements and insertions of integral data into a MySql table works as intended. [ChangeLog][QtSql] Improve performance when reading integer values from MySQL databases via prepared statements. Change-Id: I21dd9277661971ded934546f09535014b63f8eb8 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/sql/drivers/mysql/qsql_mysql.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp index 086a232746..ea8a918dcf 100644 --- a/src/sql/drivers/mysql/qsql_mysql.cpp +++ b/src/sql/drivers/mysql/qsql_mysql.cpp @@ -237,7 +237,11 @@ static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags) QVariant::Type type; switch (mysqltype) { case FIELD_TYPE_TINY : + type = static_cast((flags & UNSIGNED_FLAG) ? QMetaType::UChar : QMetaType::Char); + break; case FIELD_TYPE_SHORT : + type = static_cast((flags & UNSIGNED_FLAG) ? QMetaType::UShort : QMetaType::Short); + break; case FIELD_TYPE_LONG : case FIELD_TYPE_INT24 : type = (flags & UNSIGNED_FLAG) ? QVariant::UInt : QVariant::Int; @@ -316,14 +320,12 @@ static bool qIsBlob(int t) static bool qIsInteger(int t) { - return t == MYSQL_TYPE_TINY - || t == MYSQL_TYPE_SHORT - || t == MYSQL_TYPE_LONG - || t == MYSQL_TYPE_LONGLONG - || t == MYSQL_TYPE_INT24; + return t == QMetaType::Char || t == QMetaType::UChar + || t == QMetaType::Short || t == QMetaType::UShort + || t == QMetaType::Int || t == QMetaType::UInt + || t == QMetaType::LongLong || t == QMetaType::ULongLong; } - void QMYSQLResultPrivate::bindBlobs() { int i; @@ -371,14 +373,9 @@ bool QMYSQLResultPrivate::bindInValues() // after mysql_stmt_exec() in QMYSQLResult::exec() fieldInfo->length = 0; hasBlobs = true; + } else if (qIsInteger(f.type)) { + fieldInfo->length = 8; } else { - // fieldInfo->length specifies the display width, which may be too - // small to hold valid integer values (see - // http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html ), so - // always use the MAX_BIGINT_WIDTH for integer types - if (qIsInteger(fieldInfo->type)) { - fieldInfo->length = MAX_BIGINT_WIDTH; - } fieldInfo->type = MYSQL_TYPE_STRING; } bind = &inBinds[i]; @@ -598,6 +595,9 @@ QVariant QMYSQLResult::data(int field) if (f.nullIndicator) return QVariant(f.type); + if (qIsInteger(f.type)) + return QVariant(f.type, f.outField); + if (f.type != QVariant::ByteArray) val = toUnicode(d->driver->d_func()->tc, f.outField, f.bufLength); } else { @@ -605,18 +605,24 @@ QVariant QMYSQLResult::data(int field) // NULL value return QVariant(f.type); } + fieldLength = mysql_fetch_lengths(d->result)[field]; + if (f.type != QVariant::ByteArray) val = toUnicode(d->driver->d_func()->tc, d->row[field], fieldLength); } - switch(f.type) { + switch (static_cast(f.type)) { case QVariant::LongLong: return QVariant(val.toLongLong()); case QVariant::ULongLong: return QVariant(val.toULongLong()); + case QMetaType::Char: + case QMetaType::Short: case QVariant::Int: return QVariant(val.toInt()); + case QMetaType::UChar: + case QMetaType::UShort: case QVariant::UInt: return QVariant(val.toUInt()); case QVariant::Double: { -- cgit v1.2.3 From 6fca88607b0300cf4ddd81af924d7ef25abd7bd1 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Wed, 15 Jul 2015 18:11:38 +0300 Subject: QAbstractSocket::canReadLine(): remove code duplication Contents of the QIODevice's buffer is handled in the base implementation. Change-Id: I5a3d68e4e8dcb16d7f5ad695ac43127b8047a061 Reviewed-by: Thiago Macieira --- src/network/socket/qabstractsocket.cpp | 4 ++-- src/network/socket/qabstractsocket.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 35b541d739..371b9e0264 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -1810,12 +1810,12 @@ QString QAbstractSocket::peerName() const */ bool QAbstractSocket::canReadLine() const { - bool hasLine = d_func()->buffer.canReadLine(); + bool hasLine = QIODevice::canReadLine(); #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::canReadLine() == %s, buffer size = %lld, size = %lld", hasLine ? "true" : "false", d_func()->buffer.size(), d_func()->buffer.size()); #endif - return hasLine || QIODevice::canReadLine(); + return hasLine; } /*! diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index b433c7e97f..23f0d26cbd 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -149,7 +149,7 @@ public: qint64 bytesAvailable() const Q_DECL_OVERRIDE; qint64 bytesToWrite() const Q_DECL_OVERRIDE; - bool canReadLine() const Q_DECL_OVERRIDE; + bool canReadLine() const Q_DECL_OVERRIDE; // ### Qt6: remove me quint16 localPort() const; QHostAddress localAddress() const; -- cgit v1.2.3 From c65b8381bb55951993f10698427e7fbbe56f37af Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 26 Mar 2015 10:20:11 +0100 Subject: Use QScopedPointer for library paths This way we can remove some life cycle management code. Change-Id: I8e0c9db0a8c5f0941bbd834380d3e3b3a9d2f306 Reviewed-by: Adam Majer Reviewed-by: Thiago Macieira --- src/corelib/kernel/qcoreapplication.cpp | 52 +++++++++++++-------------------- 1 file changed, 21 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index e08f709cd2..687ff6d9a0 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -323,17 +323,9 @@ uint QCoreApplicationPrivate::attribs = (1 << Qt::AA_SynthesizeMouseForUnhandled struct QCoreApplicationData { QCoreApplicationData() Q_DECL_NOTHROW { -#ifndef QT_NO_LIBRARY - app_libpaths = 0; - manual_libpaths = 0; -#endif applicationNameSet = false; } ~QCoreApplicationData() { -#ifndef QT_NO_LIBRARY - delete app_libpaths; - delete manual_libpaths; -#endif #ifndef QT_NO_QOBJECT // cleanup the QAdoptedThread created for the main() thread if (QCoreApplicationPrivate::theMainThread) { @@ -377,8 +369,8 @@ struct QCoreApplicationData { bool applicationNameSet; // true if setApplicationName was called #ifndef QT_NO_LIBRARY - QStringList *app_libpaths; - QStringList *manual_libpaths; + QScopedPointer app_libpaths; + QScopedPointer manual_libpaths; #endif }; @@ -571,9 +563,9 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() { #ifndef QT_NO_LIBRARY - QStringList *app_libpaths = coreappdata()->app_libpaths; + QStringList *app_libpaths = coreappdata()->app_libpaths.data(); if (!app_libpaths) - coreappdata()->app_libpaths = app_libpaths = new QStringList; + coreappdata()->app_libpaths.reset(app_libpaths = new QStringList); QString app_location = QCoreApplication::applicationFilePath(); app_location.truncate(app_location.lastIndexOf(QLatin1Char('/'))); #ifdef Q_OS_WINRT @@ -774,16 +766,14 @@ void QCoreApplication::init() // Reset the lib paths, so that they will be recomputed, taking the availability of argv[0] // into account. If necessary, recompute right away and replay the manual changes on top of the // new lib paths. - QStringList *appPaths = coreappdata()->app_libpaths; - QStringList *manualPaths = coreappdata()->manual_libpaths; + QStringList *appPaths = coreappdata()->app_libpaths.take(); + QStringList *manualPaths = coreappdata()->manual_libpaths.take(); if (appPaths) { - coreappdata()->app_libpaths = 0; if (manualPaths) { // Replay the delta. As paths can only be prepended to the front or removed from // anywhere in the list, we can just linearly scan the lists and find the items that // have been removed. Once the original list is exhausted we know all the remaining // items have been added. - coreappdata()->manual_libpaths = 0; QStringList newPaths(libraryPaths()); for (int i = manualPaths->length(), j = appPaths->length(); i > 0 || j > 0; qt_noop()) { if (--j < 0) { @@ -796,7 +786,7 @@ void QCoreApplication::init() } } delete manualPaths; - coreappdata()->manual_libpaths = new QStringList(newPaths); + coreappdata()->manual_libpaths.reset(new QStringList(newPaths)); } delete appPaths; } @@ -872,10 +862,8 @@ QCoreApplication::~QCoreApplication() #endif #ifndef QT_NO_LIBRARY - delete coreappdata()->app_libpaths; - coreappdata()->app_libpaths = 0; - delete coreappdata()->manual_libpaths; - coreappdata()->manual_libpaths = 0; + coreappdata()->app_libpaths.reset(); + coreappdata()->manual_libpaths.reset(); #endif } @@ -2540,7 +2528,8 @@ QStringList QCoreApplication::libraryPaths() return *(coreappdata()->manual_libpaths); if (!coreappdata()->app_libpaths) { - QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList; + QStringList *app_libpaths = new QStringList; + coreappdata()->app_libpaths.reset(app_libpaths); QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); if (QFile::exists(installPathPlugins)) { // Make sure we convert from backslashes to slashes. @@ -2591,9 +2580,10 @@ void QCoreApplication::setLibraryPaths(const QStringList &paths) if (!coreappdata()->app_libpaths) libraryPaths(); - if (!coreappdata()->manual_libpaths) - coreappdata()->manual_libpaths = new QStringList; - *(coreappdata()->manual_libpaths) = paths; + if (coreappdata()->manual_libpaths) + *(coreappdata()->manual_libpaths) = paths; + else + coreappdata()->manual_libpaths.reset(new QStringList(paths)); locker.unlock(); QFactoryLoader::refreshAll(); @@ -2625,18 +2615,18 @@ void QCoreApplication::addLibraryPath(const QString &path) QMutexLocker locker(libraryPathMutex()); - QStringList *libpaths = coreappdata()->manual_libpaths; + QStringList *libpaths = coreappdata()->manual_libpaths.data(); if (libpaths) { if (libpaths->contains(canonicalPath)) return; } else { // make sure that library paths are initialized libraryPaths(); - QStringList *app_libpaths = coreappdata()->app_libpaths; + QStringList *app_libpaths = coreappdata()->app_libpaths.data(); if (app_libpaths->contains(canonicalPath)) return; - libpaths = coreappdata()->manual_libpaths = new QStringList(*app_libpaths); + coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths)); } libpaths->prepend(canonicalPath); @@ -2664,18 +2654,18 @@ void QCoreApplication::removeLibraryPath(const QString &path) QMutexLocker locker(libraryPathMutex()); - QStringList *libpaths = coreappdata()->manual_libpaths; + QStringList *libpaths = coreappdata()->manual_libpaths.data(); if (libpaths) { if (libpaths->removeAll(canonicalPath) == 0) return; } else { // make sure that library paths is initialized libraryPaths(); - QStringList *app_libpaths = coreappdata()->app_libpaths; + QStringList *app_libpaths = coreappdata()->app_libpaths.data(); if (!app_libpaths->contains(canonicalPath)) return; - libpaths = coreappdata()->manual_libpaths = new QStringList(*app_libpaths); + coreappdata()->manual_libpaths.reset(libpaths = new QStringList(*app_libpaths)); libpaths->removeAll(canonicalPath); } -- cgit v1.2.3 From ce651b961d6b53a34b11664317e8da8022d48cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 23 Jan 2015 10:55:20 +0100 Subject: Remove Q_DEAD_CODE_FROM_QT4_MAC sections The native OS X color dialog wrapper is now implemented in qcocoadialoghelper.mm in the Cocoa platform plugin. Change-Id: Idc4088df93960dd68507d11a9895277e34a18b96 Reviewed-by: Jake Petroules --- src/widgets/dialogs/qcolordialog.cpp | 51 +----------------------------------- 1 file changed, 1 insertion(+), 50 deletions(-) (limited to 'src') diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index 914ee8ec9c..2ebbaaee10 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -159,23 +159,6 @@ public: QWindow dummyTransparentWindow; #endif -#ifdef Q_DEAD_CODE_FROM_QT4_MAC - void openCocoaColorPanel(const QColor &initial, - QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options); - void closeCocoaColorPanel(); - void releaseCocoaColorPanelDelegate(); - void setCocoaPanelColor(const QColor &color); - - inline void done(int result) { q_func()->done(result); } - inline QColorDialog *colorDialog() { return q_func(); } - - void *delegate; - - static bool sharedColorPanelAvailable; - - void _q_macRunNativeAppModalPanel(); - void mac_nativeDialogModalHelp(); -#endif private: virtual void initHelper(QPlatformDialogHelper *h) Q_DECL_OVERRIDE; virtual void helperPrepareShow(QPlatformDialogHelper *h) Q_DECL_OVERRIDE; @@ -1731,9 +1714,6 @@ void QColorDialogPrivate::init(const QColor &initial) if (!nativeDialogInUse) initWidgets(); -#ifdef Q_DEAD_CODE_FROM_QT4_MAC - delegate = 0; -#endif #ifdef Q_OS_WIN32 dummyTransparentWindow.resize(1, 1); dummyTransparentWindow.setFlags(Qt::Tool | Qt::FramelessWindowHint); @@ -2135,11 +2115,6 @@ QColorDialog::ColorDialogOptions QColorDialog::options() const \sa color, colorSelected() */ -#ifdef Q_DEAD_CODE_FROM_QT4_MAC -// can only have one Cocoa color panel active -bool QColorDialogPrivate::sharedColorPanelAvailable = true; -#endif - /*! \fn void QColorDialog::colorSelected(const QColor &color); @@ -2166,23 +2141,6 @@ void QColorDialog::setVisible(bool visible) if (visible) d->selectedQColor = QColor(); -#if defined(Q_DEAD_CODE_FROM_QT4_MAC) - if (visible) { - if (d->delegate || (QColorDialogPrivate::sharedColorPanelAvailable && - !(testAttribute(Qt::WA_DontShowOnScreen) || (d->opts & DontUseNativeDialog)))){ - d->openCocoaColorPanel(currentColor(), parentWidget(), windowTitle(), options()); - QColorDialogPrivate::sharedColorPanelAvailable = false; - setAttribute(Qt::WA_DontShowOnScreen); - } - setWindowFlags(windowModality() == Qt::WindowModal ? Qt::Sheet : DefaultWindowFlags); - } else { - if (d->delegate) { - d->closeCocoaColorPanel(); - setAttribute(Qt::WA_DontShowOnScreen, false); - } - } -#else - if (d->nativeDialogInUse) { d->setNativeDialogVisible(visible); // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below @@ -2191,7 +2149,6 @@ void QColorDialog::setVisible(bool visible) } else { setAttribute(Qt::WA_DontShowOnScreen, false); } -#endif QDialog::setVisible(visible); } @@ -2267,13 +2224,7 @@ QRgb QColorDialog::getRgba(QRgb initial, bool *ok, QWidget *parent) QColorDialog::~QColorDialog() { -#if defined(Q_DEAD_CODE_FROM_QT4_MAC) - Q_D(QColorDialog); - if (d->delegate) { - d->releaseCocoaColorPanelDelegate(); - QColorDialogPrivate::sharedColorPanelAvailable = true; - } -#endif + } /*! -- cgit v1.2.3 From 8f747efcc14e2f3114821c2c2bfbc3991610890e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 6 Aug 2015 22:42:18 +0200 Subject: Make QT_SCALE_FACTOR work on Wayland Propagate the line stride when creating the high-dpi backing store image. Change-Id: I15f41965d8eaf1d01ddac0a1a012b71148f757e3 Reviewed-by: Paul Olav Tvete --- src/gui/painting/qbackingstore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 68ed3eae6e..8a5a6d4fcf 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -182,7 +182,8 @@ void QBackingStore::beginPaint(const QRegion ®ion) qCDebug(lcScaling) << "QBackingStore::beginPaint new backingstore for" << d_ptr->window; qCDebug(lcScaling) << " source size" << source->size() << "dpr" << source->devicePixelRatio(); d_ptr->highDpiBackingstore.reset( - new QImage(source->bits(), source->width(), source->height(), source->format())); + new QImage(source->bits(), source->width(), source->height(), source->bytesPerLine(), source->format())); + qreal targetDevicePixelRatio = d_ptr->window->devicePixelRatio(); d_ptr->highDpiBackingstore->setDevicePixelRatio(targetDevicePixelRatio); qCDebug(lcScaling) <<" destination size" << d_ptr->highDpiBackingstore->size() -- cgit v1.2.3 From a50db99d1590c05d4dd1a9f2b58a10e6ade55d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 6 Aug 2015 22:44:09 +0200 Subject: Add QPlatformWindow::windowFrameGeometry() Convenience accessor for use by the Wayland platform plugin. Change-Id: I420209138cfc285f8396913548b9e158a35ee9c1 Reviewed-by: Paul Olav Tvete --- src/gui/kernel/qplatformwindow.cpp | 8 ++++++++ src/gui/kernel/qplatformwindow.h | 1 + 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index d10bd1e9eb..0430d5a4c6 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -689,6 +689,14 @@ QRect QPlatformWindow::windowGeometry() const return QHighDpi::toNativePixels(window()->geometry(), window()); } +/*! + Returns the QWindow frame geometry. +*/ +QRect QPlatformWindow::windowFrameGeometry() const +{ + return QHighDpi::toNativePixels(window()->frameGeometry(), window()); +} + /*! Returns the closest acceptable geometry for a given geometry before a resize/move event for platforms that support it, for example to diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 692ae862db..1b283dbb4f 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -138,6 +138,7 @@ public: QSize windowBaseSize() const; QSize windowSizeIncrement() const; QRect windowGeometry() const; + QRect windowFrameGeometry() const; QRectF windowClosestAcceptableGeometry(const QRectF &nativeRect) const; protected: -- cgit v1.2.3 From e5d54c8af778782da13322ddaf1b385c87d51f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sat, 22 Nov 2014 15:10:34 +0100 Subject: Propagate event accepted state to platform plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add en "eventAccepted" field to WindowSystemEvent, where the event subclasses can record the event acceptance status. Make handleWindowSystemEvent() return the accepted status. This works for synchronous event processing only. If the event is placed on the QPA event queue then there is no way to return the accepted state immediately. In the latter case handleWindowSystemEvent() always returns "true". Change-Id: I081aecc54f43588d42d3aaeec7f8458f06937601 Reviewed-by: Jørgen Lind --- src/gui/kernel/qwindowsysteminterface.cpp | 5 ++++- src/gui/kernel/qwindowsysteminterface_p.h | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 3ab2f59661..8c429150a8 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -441,10 +441,12 @@ void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *e windowSystemEventQueue.remove(event); } -void QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev) +bool QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev) { + bool accepted = true; if (synchronousWindowSystemEvents) { QGuiApplicationPrivate::processWindowSystemEvent(ev); + accepted = ev->eventAccepted; delete ev; } else { windowSystemEventQueue.append(ev); @@ -452,6 +454,7 @@ void QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfa if (dispatcher) dispatcher->wakeUp(); } + return accepted; } void QWindowSystemInterface::registerTouchDevice(QTouchDevice *device) diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index cbc3bad7cd..cc0ca6bf81 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -101,7 +101,7 @@ public: }; explicit WindowSystemEvent(EventType t) - : type(t), flags(0) { } + : type(t), flags(0), eventAccepted(true) { } virtual ~WindowSystemEvent() { } bool synthetic() const { return flags & Synthetic; } @@ -109,6 +109,7 @@ public: EventType type; int flags; + bool eventAccepted; }; class CloseEvent : public WindowSystemEvent { @@ -480,7 +481,7 @@ public: static WindowSystemEvent *getNonUserInputWindowSystemEvent(); static WindowSystemEvent *peekWindowSystemEvent(EventType t); static void removeWindowSystemEvent(WindowSystemEvent *event); - static void handleWindowSystemEvent(WindowSystemEvent *ev); + static bool handleWindowSystemEvent(WindowSystemEvent *ev); static QElapsedTimer eventTime; static bool synchronousWindowSystemEvents; -- cgit v1.2.3 From 65cbf263a38bc84c531c4b7789ef942c0f6fd767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sat, 22 Nov 2014 15:11:36 +0100 Subject: Propagate keyboard event accept status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the accepted bit on the QWindowsystemInterface keyboard event after processing the key event. Change-Id: I2d8c9382f14840e464153870dff909000e64ddcd Reviewed-by: Jørgen Lind --- src/gui/kernel/qguiapplication.cpp | 1 + src/gui/kernel/qwindowsysteminterface.cpp | 10 +++++----- src/gui/kernel/qwindowsysteminterface.h | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index f240153f9f..5e2a5b86a4 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1935,6 +1935,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE } } #endif + e->eventAccepted = ev.isAccepted(); } void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e) diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 8c429150a8..7db38b5909 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -303,24 +303,24 @@ bool QWindowSystemInterface::tryHandleExtendedShortcutEvent(QWindow *w, ulong ti } -void QWindowSystemInterface::handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { +bool QWindowSystemInterface::handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleKeyEvent(w, time, t, k, mods, text, autorep, count); + return handleKeyEvent(w, time, t, k, mods, text, autorep, count); } -void QWindowSystemInterface::handleKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) +bool QWindowSystemInterface::handleKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { // This is special handling needed for OS X which eventually will call sendEvent(), on other platforms // this might not be safe, e.g., on Android. See: QGuiApplicationPrivate::processKeyEvent() for // shortcut overriding on other platforms. #if defined(Q_OS_OSX) if (t == QEvent::KeyPress && QWindowSystemInterface::tryHandleShortcutEvent(tlw, timestamp, k, mods, text)) - return; + return true; #endif // Q_OS_OSX QWindowSystemInterfacePrivate::KeyEvent * e = new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, t, k, mods, text, autorep, count); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } void QWindowSystemInterface::handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 453dbe81cf..ace1a4fe24 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -95,8 +95,8 @@ public: quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString & text = QString(), bool autorep = false, ushort count = 1); - static void handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); - static void handleKeyEvent(QWindow *w, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); + static bool handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); + static bool handleKeyEvent(QWindow *w, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); static void handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, -- cgit v1.2.3 From 7a0222fba3124729171c2bf2a288c371118681e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 4 Dec 2014 21:18:04 +0100 Subject: Call sendWindowSystemEvents() on deferred flush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling it directly is less confusing than calling it indirectly via the "else" branch in flushWindowSystemEvents. Change-Id: I085deff09162137606922a5af7ead23e21497b11 Reviewed-by: Jørgen Lind --- src/gui/kernel/qwindowsysteminterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 7db38b5909..88cf2dac93 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -614,7 +614,7 @@ void QWindowSystemInterface::deferredFlushWindowSystemEvents(QEventLoop::Process Q_ASSERT(QThread::currentThread() == QGuiApplication::instance()->thread()); QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex); - flushWindowSystemEvents(flags); + sendWindowSystemEvents(flags); QWindowSystemInterfacePrivate::eventsFlushed.wakeOne(); } -- cgit v1.2.3 From b71b36fa226cb7dd0ca06558bd0ce3aec1a942e6 Mon Sep 17 00:00:00 2001 From: Andreas Hartmetz Date: Thu, 4 Jun 2015 18:07:30 +0200 Subject: Move setter for QFont::HintingPreference to QFontEngineFT. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparation for also using it from QCoreTextFontDatabase. Change-Id: I9cbef59c21f343a88a5cb3fdbee1ed4791d7a36e Reviewed-by: Morten Johan Sørvig --- src/gui/text/qfontengine_ft.cpp | 31 ++++++++++++++++++---- src/gui/text/qfontengine_ft_p.h | 2 +- .../fontdatabases/basic/qbasicfontdatabase.cpp | 22 ++------------- 3 files changed, 29 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 37be0afccf..246df127ad 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -99,6 +99,13 @@ static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *leng static QFontEngineFT::Glyph emptyGlyph = {0, 0, 0, 0, 0, 0, 0, 0}; +static const QFontEngine::HintStyle ftInitialDefaultHintStyle = +#ifdef Q_OS_WIN + QFontEngineFT::HintFull; +#else + QFontEngineFT::HintNone; +#endif + // -------------------------- Freetype support ------------------------------ class QtFreetypeData @@ -629,11 +636,7 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd) antialias = true; freetype = 0; default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; -#ifndef Q_OS_WIN - default_hint_style = HintNone; -#else - default_hint_style = HintFull; -#endif + default_hint_style = ftInitialDefaultHintStyle; subpixelType = Subpixel_None; lcdFilterType = 0; #if defined(FT_LCD_FILTER_H) @@ -760,6 +763,24 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, return true; } +void QFontEngineFT::setQtDefaultHintStyle(QFont::HintingPreference hintingPreference) +{ + switch (hintingPreference) { + case QFont::PreferNoHinting: + setDefaultHintStyle(HintNone); + break; + case QFont::PreferFullHinting: + setDefaultHintStyle(HintFull); + break; + case QFont::PreferVerticalHinting: + setDefaultHintStyle(HintLight); + break; + case QFont::PreferDefaultHinting: + setDefaultHintStyle(ftInitialDefaultHintStyle); + break; + } +} + void QFontEngineFT::setDefaultHintStyle(HintStyle style) { default_hint_style = style; diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 7b28a4064f..4b32f078e5 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -281,7 +281,7 @@ private: virtual int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) Q_DECL_OVERRIDE; - + void setQtDefaultHintStyle(QFont::HintingPreference hintingPreference); virtual void setDefaultHintStyle(HintStyle style) Q_DECL_OVERRIDE; virtual QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp index c41061a9fd..b04ae8ee52 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp @@ -76,24 +76,6 @@ void QBasicFontDatabase::populateFontDatabase() } } -inline static void setHintingPreference(QFontEngine *engine, QFont::HintingPreference hintingPreference) -{ - switch (hintingPreference) { - case QFont::PreferNoHinting: - engine->setDefaultHintStyle(QFontEngineFT::HintNone); - break; - case QFont::PreferFullHinting: - engine->setDefaultHintStyle(QFontEngineFT::HintFull); - break; - case QFont::PreferVerticalHinting: - engine->setDefaultHintStyle(QFontEngineFT::HintLight); - break; - case QFont::PreferDefaultHinting: - // Leave it as it is - break; - } -} - QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr) { FontFile *fontfile = static_cast (usrPtr); @@ -119,7 +101,7 @@ QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPt delete engine; engine = 0; } else { - setHintingPreference(engine, static_cast(fontDef.hintingPreference)); + engine->setQtDefaultHintStyle(static_cast(fontDef.hintingPreference)); } return engine; @@ -172,7 +154,7 @@ QFontEngine *QBasicFontDatabase::fontEngine(const QByteArray &fontData, qreal pi } fe->updateFamilyNameAndStyle(); - setHintingPreference(fe, hintingPreference); + fe->setQtDefaultHintStyle(static_cast(fontDef.hintingPreference)); return fe; } -- cgit v1.2.3 From ea3e2ca6ea465157293bdf45046ed23f8f83d1dc Mon Sep 17 00:00:00 2001 From: Andreas Hartmetz Date: Thu, 4 Jun 2015 18:21:03 +0200 Subject: OSX FreeType: respect hinting preference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-42839 Change-Id: I2bccd7bda74ccbbb752181f1caea7ecf4672c01c Reviewed-by: Morten Johan Sørvig --- src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index a9ca5391e8..4c9c7b78db 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -994,6 +994,7 @@ QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, qWarning() << "QCoreTextFontDatabase::freeTypefontEngine Failed to create engine"; return Q_NULLPTR; } + engine->setQtDefaultHintStyle(static_cast(fontDef.hintingPreference)); return engine.take(); } -- cgit v1.2.3 From 385202c27caa070e07eba098a1b968f9d466aaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Wed, 10 Dec 2014 13:42:45 +0000 Subject: OSX FreeType: Add support for sub pixel font rendering. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-42839 Change-Id: Iea4552d766936a55fd177e4287591d2715202d9c Reviewed-by: Morten Johan Sørvig --- src/gui/text/qfontengine_ft_p.h | 1 + .../fontdatabases/mac/qcoretextfontdatabase.mm | 14 ++++++++++++-- src/plugins/platforms/cocoa/qcocoaintegration.h | 1 + src/plugins/platforms/cocoa/qcocoaintegration.mm | 10 ++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 4b32f078e5..b81e51bf2e 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -307,6 +307,7 @@ private: friend class QFontEngineFTRawFont; friend class QFontconfigDatabase; friend class QBasicFontDatabase; + friend class QCoreTextFontDatabase; friend class QFontEngineMultiFontConfig; int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const; diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 4c9c7b78db..1f000421cc 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -986,10 +986,20 @@ QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, QFontEngine::FaceId faceId; faceId.filename = filename; const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - const QFontEngineFT::GlyphFormat format = antialias ? QFontEngineFT::Format_A8 - : QFontEngineFT::Format_Mono; QScopedPointer engine(new QFontEngineFT(fontDef)); + QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono; + if (antialias) { + QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint(); + if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) { + format = QFontEngineFT::Format_A8; + engine->subpixelType = QFontEngine::Subpixel_None; + } else { + format = QFontEngineFT::Format_A32; + engine->subpixelType = subpixelType; + } + } + if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) { qWarning() << "QCoreTextFontDatabase::freeTypefontEngine Failed to create engine"; return Q_NULLPTR; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 9e5dd3747e..32a08dbb0d 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -73,6 +73,7 @@ public: QPlatformCursor *cursor() const Q_DECL_OVERRIDE { return m_cursor; } QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE; QList virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; } + QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE; // ---------------------------------------------------- // Additional methods diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 0b9a38b560..2e6bfc95db 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -142,6 +142,16 @@ qreal QCocoaScreen::devicePixelRatio() const return qreal(screen ? [screen backingScaleFactor] : 1.0); } +QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const +{ + QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint(); + if (type == QPlatformScreen::Subpixel_None) { + // Every OSX machine has RGB pixels unless a peculiar or rotated non-Apple screen is attached + type = QPlatformScreen::Subpixel_RGB; + } + return type; +} + QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const { NSPoint screenPoint = qt_mac_flipPoint(point); -- cgit v1.2.3 From f029468b8d822da378a20577f7b8c16a447e4e1b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 19 Mar 2015 17:47:13 +0100 Subject: Add QMainWindow::resizeDocks This API allows to programatically resize QDockWidgets Task-number: QTBUG-32001 Change-Id: I58072a391f8e7f325a26745b5bedd3fe49508e91 Reviewed-by: Jocelyn Turcotte (Woboq GmbH) --- src/widgets/widgets/qdockarealayout.cpp | 47 +++++++++++++++++++++++++++++++++ src/widgets/widgets/qdockarealayout_p.h | 1 + src/widgets/widgets/qmainwindow.cpp | 29 ++++++++++++++++++++ src/widgets/widgets/qmainwindow.h | 3 +++ 4 files changed, 80 insertions(+) (limited to 'src') diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp index c61984a457..0a00086138 100644 --- a/src/widgets/widgets/qdockarealayout.cpp +++ b/src/widgets/widgets/qdockarealayout.cpp @@ -3101,6 +3101,53 @@ void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second) remove(index); } +void QDockAreaLayout::resizeDocks(const QList &docks, + const QList &sizes, Qt::Orientation o) +{ + if (docks.count() != sizes.count()) { + qWarning("QMainWidget::resizeDocks: size of the lists are not the same"); + return; + } + int count = docks.count(); + fallbackToSizeHints = false; + for (int i = 0; i < count; ++i) { + QList path = indexOf(docks[i]); + if (path.isEmpty()) { + qWarning("QMainWidget::resizeDocks: one QDockWidget is not part of the layout"); + continue; + } + int size = sizes[i]; + if (size <= 0) { + qWarning("QMainWidget::resizeDocks: all sizes need to be larger than 0"); + size = 1; + } + + while (path.size() > 1) { + QDockAreaLayoutInfo *info = this->info(path); + if (!info->tabbed && info->o == o) { + info->item_list[path.last()].size = size; + int totalSize = 0; + foreach (const QDockAreaLayoutItem &item, info->item_list) { + if (!item.skip()) { + if (totalSize != 0) + totalSize += sep; + totalSize += item.size == -1 ? pick(o, item.sizeHint()) : item.size; + } + } + size = totalSize; + } + path.removeLast(); + } + + const int dockNum = path.first(); + Q_ASSERT(dockNum < QInternal::DockCount); + QRect &r = this->docks[dockNum].rect; + QSize s = r.size(); + rpick(o, s) = size; + r.setSize(s); + } +} + void QDockAreaLayout::splitDockWidget(QDockWidget *after, QDockWidget *dockWidget, Qt::Orientation orientation) diff --git a/src/widgets/widgets/qdockarealayout_p.h b/src/widgets/widgets/qdockarealayout_p.h index 93b005f64f..5d352f0124 100644 --- a/src/widgets/widgets/qdockarealayout_p.h +++ b/src/widgets/widgets/qdockarealayout_p.h @@ -268,6 +268,7 @@ public: void splitDockWidget(QDockWidget *after, QDockWidget *dockWidget, Qt::Orientation orientation); void tabifyDockWidget(QDockWidget *first, QDockWidget *second); + void resizeDocks(const QList &docks, const QList &sizes, Qt::Orientation o); void apply(bool animate); diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp index 5d53e7def4..ff4bb3cc98 100644 --- a/src/widgets/widgets/qmainwindow.cpp +++ b/src/widgets/widgets/qmainwindow.cpp @@ -1237,6 +1237,35 @@ void QMainWindow::removeDockWidget(QDockWidget *dockwidget) Qt::DockWidgetArea QMainWindow::dockWidgetArea(QDockWidget *dockwidget) const { return d_func()->layout->dockWidgetArea(dockwidget); } + +/*! + \since 5.6 + Resizes the dock widgets in the list \a docks to the corresponding size in + pixels from the list \a sizes. If \a orientation is Qt::Horizontal, adjusts + the width, otherwise adjusts the height of the dock widgets. + The sizes will be adjusted such that the maximum and the minimum sizes are + respected and the QMainWindow itself will not be resized. + Any additional/missing space is distributed amongst the widgets according + to the relative weight of the sizes. + + Example: + \code + resizeDocks({blueWidget, yellowWidget}, {20 , 40}, Qt::Horizontal); + \endcode + If the blue and the yellow widget are nested on the same level they will be + resized such that the yellowWidget is twice as big as the blueWidget + + If some widgets are grouped in tabs, only one widget per group should be + specified. Widgets not in the list might be changed to repect the constraints. +*/ +void QMainWindow::resizeDocks(const QList &docks, + const QList &sizes, Qt::Orientation orientation) +{ + d_func()->layout->layoutState.dockAreaLayout.resizeDocks(docks, sizes, orientation); + d_func()->layout->invalidate(); +} + + #endif // QT_NO_DOCKWIDGET /*! diff --git a/src/widgets/widgets/qmainwindow.h b/src/widgets/widgets/qmainwindow.h index ab6ee22748..70d78a7904 100644 --- a/src/widgets/widgets/qmainwindow.h +++ b/src/widgets/widgets/qmainwindow.h @@ -165,6 +165,9 @@ public: bool restoreDockWidget(QDockWidget *dockwidget); Qt::DockWidgetArea dockWidgetArea(QDockWidget *dockwidget) const; + + void resizeDocks(const QList &docks, + const QList &sizes, Qt::Orientation orientation); #endif // QT_NO_DOCKWIDGET QByteArray saveState(int version = 0) const; -- cgit v1.2.3 From 6dde874c3203464f76170834234c026e02dc7abc Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Thu, 13 Aug 2015 18:59:03 +0300 Subject: QProcess: discard unwanted output from the child process Drop process output to nullDevice(), if an application does not request forwarding, redirecting or reading from the device channel. This prevents from accumulation of unnecessary data which can not be read. Change-Id: Ia311a8c658a46cf580ffa9484c5369f3fc5f98a7 Reviewed-by: Thiago Macieira Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qprocess.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index dfde5f236d..cdae149678 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2206,6 +2206,16 @@ void QProcessPrivate::start(QIODevice::OpenMode mode) mode &= ~QIODevice::ReadOnly; // not open for reading if (mode == 0) mode = QIODevice::Unbuffered; +#ifndef Q_OS_WINCE + if ((mode & QIODevice::ReadOnly) == 0) { + if (stdoutChannel.type == QProcessPrivate::Channel::Normal) + q->setStandardOutputFile(q->nullDevice()); + if (stderrChannel.type == QProcessPrivate::Channel::Normal + && processChannelMode != QProcess::MergedChannels) + q->setStandardErrorFile(q->nullDevice()); + } +#endif + q->QIODevice::open(mode); stdinChannel.closed = false; -- cgit v1.2.3 From 8c5ce68fcf09d128072c31d74878fcb0fd9b9c7a Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 6 Aug 2015 13:47:44 +0200 Subject: qdoc: Allow formal parameters in link targets This update allows qdoc to handle \l commands for linking to functions, where the formal parameters are included in the link target. For example, \l {QWidget::find(QString name)} will only match a member function of QWidget that has a single parameter of type QString. The parameter name is not used in the search. Change-Id: I8a31c9a7ed632f12a0e6d8a33cbb5cd361098317 Task-number: QTBUG-47286 Reviewed-by: Martin Smith --- src/corelib/tools/qlist.cpp | 2 +- src/tools/qdoc/codeparser.h | 1 - src/tools/qdoc/cppcodemarker.cpp | 8 +- src/tools/qdoc/cppcodeparser.cpp | 74 ++++++++++++------ src/tools/qdoc/cppcodeparser.h | 16 +--- src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc | 9 ++- src/tools/qdoc/generator.cpp | 18 ++--- src/tools/qdoc/node.cpp | 101 +++++++++++++++++++------ src/tools/qdoc/node.h | 26 ++++--- src/tools/qdoc/qdocdatabase.cpp | 53 +++++++++++-- src/tools/qdoc/qdocdatabase.h | 11 +-- src/tools/qdoc/qdocindexfiles.cpp | 2 +- src/tools/qdoc/qmlvisitor.cpp | 4 +- src/tools/qdoc/tokenizer.cpp | 1 + src/tools/qdoc/tree.cpp | 17 +++-- src/tools/qdoc/tree.h | 6 +- 16 files changed, 238 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 509afadfc2..8ed0da7ca0 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -378,7 +378,7 @@ void **QListData::erase(void **xi) references into a QVector and non-heap-allocating QLists. Internally, QList\ is represented as an array of T if - If \c{sizeof(T) <= sizeof(void*)} and T has been declared to be + \c{sizeof(T) <= sizeof(void*)} and T has been declared to be either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using \l {Q_DECLARE_TYPEINFO}. Otherwise, QList\ is represented as an array of T* and the items are allocated on the heap. diff --git a/src/tools/qdoc/codeparser.h b/src/tools/qdoc/codeparser.h index 379deb7e23..9d9e9286ec 100644 --- a/src/tools/qdoc/codeparser.h +++ b/src/tools/qdoc/codeparser.h @@ -40,7 +40,6 @@ QT_BEGIN_NAMESPACE class Config; -class Node; class QString; class QDocDatabase; diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp index 868b249290..774ff115b9 100644 --- a/src/tools/qdoc/cppcodemarker.cpp +++ b/src/tools/qdoc/cppcodemarker.cpp @@ -157,11 +157,11 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, synopsis += "("; if (!func->parameters().isEmpty()) { //synopsis += QLatin1Char(' '); - QList::ConstIterator p = func->parameters().constBegin(); + QVector::ConstIterator p = func->parameters().constBegin(); while (p != func->parameters().constEnd()) { if (p != func->parameters().constBegin()) synopsis += ", "; - synopsis += typified((*p).leftType()); + synopsis += typified((*p).dataType()); if (style != Subpage && !(*p).name().isEmpty()) synopsis += "<@param>" + protect((*p).name()) + ""; @@ -328,11 +328,11 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) synopsis = name; synopsis += QLatin1Char('('); if (!func->parameters().isEmpty()) { - QList::ConstIterator p = func->parameters().constBegin(); + QVector::ConstIterator p = func->parameters().constBegin(); while (p != func->parameters().constEnd()) { if (p != func->parameters().constBegin()) synopsis += ", "; - synopsis += typified((*p).leftType()); + synopsis += typified((*p).dataType()); if (!(*p).name().isEmpty()) { if (!synopsis.endsWith(QLatin1Char('('))) synopsis += QLatin1Char(' '); diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index cab416370a..8d9596c10b 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -54,6 +54,7 @@ static bool inMacroCommand_ = false; static bool parsingHeaderFile_ = false; QStringList CppCodeParser::exampleFiles; QStringList CppCodeParser::exampleDirs; +CppCodeParser* CppCodeParser::cppParser_ = 0; /*! The constructor initializes some regular expressions @@ -63,6 +64,7 @@ CppCodeParser::CppCodeParser() : varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::") { reset(); + cppParser_ = this; } /*! @@ -374,12 +376,12 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, } else { func->setMetaness(FunctionNode::MacroWithParams); - QList params = func->parameters(); + QVector params = func->parameters(); for (int i = 0; i < params.size(); ++i) { Parameter ¶m = params[i]; - if (param.name().isEmpty() && !param.leftType().isEmpty() - && param.leftType() != "...") - param = Parameter("", "", param.leftType()); + if (param.name().isEmpty() && !param.dataType().isEmpty() + && param.dataType() != "...") + param = Parameter("", "", param.dataType()); } func->setParameters(params); } @@ -1308,23 +1310,23 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) /*! Parse the next function parameter, if there is one, and - append it to parameter list \a p. Return true if a parameter - is parsed and appended to \a p. Otherwise return false. + append it to parameter vector \a pvect. Return true if + a parameter is parsed and appended to \a pvect. + Otherwise return false. */ -bool CppCodeParser::matchParameter(ParsedParameterList& pplist) +bool CppCodeParser::matchParameter(QVector& pvect, bool& isQPrivateSignal) { - ParsedParameter pp; if (match(Tok_QPrivateSignal)) { - pp.qPrivateSignal_ = true; - pplist.append(pp); + isQPrivateSignal = true; return true; } + Parameter p; CodeChunk chunk; - if (!matchDataType(&chunk, &pp.name_)) { + if (!matchDataType(&chunk, &p.name_)) { return false; } - pp.dataType_ = chunk.toString(); + p.dataType_ = chunk.toString(); chunk.clear(); match(Tok_Comment); if (match(Tok_Equal)) { @@ -1336,8 +1338,8 @@ bool CppCodeParser::matchParameter(ParsedParameterList& pplist) readToken(); } } - pp.defaultValue_ = chunk.toString(); - pplist.append(pp); + p.defaultValue_ = chunk.toString(); + pvect.append(p); return true; } @@ -1542,10 +1544,11 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent, readToken(); // A left paren was seen. Parse the parameters - ParsedParameterList pplist; + bool isQPrivateSignal = false; + QVector pvect; if (tok != Tok_RightParen) { do { - if (!matchParameter(pplist)) + if (!matchParameter(pvect, isQPrivateSignal)) return false; } while (match(Tok_Comma)); } @@ -1629,13 +1632,10 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent, func->setStatic(matched_static); func->setConst(matchedConst); func->setVirtualness(virtuality); - if (!pplist.isEmpty()) { - foreach (const ParsedParameter& pp, pplist) { - if (pp.qPrivateSignal_) - func->setPrivateSignal(); - else - func->addParameter(Parameter(pp.dataType_, "", pp.name_, pp.defaultValue_)); - } + if (isQPrivateSignal) + func->setPrivateSignal(); + if (!pvect.isEmpty()) { + func->setParameters(pvect); } } if (parentPathPtr != 0) @@ -2416,6 +2416,34 @@ bool CppCodeParser::makeFunctionNode(const QString& signature, return ok; } +/*! + This function uses a Tokenizer to parse the \a parameters of a + function into the parameter vector \a {pvect}. + */ +bool CppCodeParser::parseParameters(const QString& parameters, + QVector& pvect, + bool& isQPrivateSignal) +{ + Tokenizer* outerTokenizer = tokenizer; + int outerTok = tok; + + QByteArray latin1 = parameters.toLatin1(); + Tokenizer stringTokenizer(Location(), latin1); + stringTokenizer.setParsingFnOrMacro(true); + tokenizer = &stringTokenizer; + readToken(); + + inMacroCommand_ = false; + do { + if (!matchParameter(pvect, isQPrivateSignal)) + return false; + } while (match(Tok_Comma)); + + tokenizer = outerTokenizer; + tok = outerTok; + return true; +} + /*! Create a new FunctionNode for a QML method or signal, as specified by \a type, as a child of \a parent. \a sig is diff --git a/src/tools/qdoc/cppcodeparser.h b/src/tools/qdoc/cppcodeparser.h index 733418e27a..ec04482321 100644 --- a/src/tools/qdoc/cppcodeparser.h +++ b/src/tools/qdoc/cppcodeparser.h @@ -51,16 +51,6 @@ class CppCodeParser : public CodeParser { Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser) - struct ParsedParameter { - bool qPrivateSignal_; - QString dataType_; - QString name_; - QString defaultValue_; - ParsedParameter() : qPrivateSignal_(false) { } - }; - friend class QTypeInfo; - typedef QVector ParsedParameterList; - struct ExtraFuncData { Aggregate* root; // Used as the parent. Node::NodeType type; // The node type: Function, etc. @@ -74,6 +64,7 @@ class CppCodeParser : public CodeParser public: CppCodeParser(); ~CppCodeParser(); + static CppCodeParser* cppParser() { return cppParser_; } virtual void initializeParser(const Config& config) Q_DECL_OVERRIDE; virtual void terminateParser() Q_DECL_OVERRIDE; @@ -84,6 +75,7 @@ public: virtual void parseSourceFile(const Location& location, const QString& filePath) Q_DECL_OVERRIDE; virtual void doneParsingHeaderFiles() Q_DECL_OVERRIDE; virtual void doneParsingSourceFiles() Q_DECL_OVERRIDE; + bool parseParameters(const QString& parameters, QVector& pvect, bool& isQPrivateSignal); protected: const QSet& topicCommands(); @@ -126,7 +118,7 @@ protected: bool matchTemplateAngles(CodeChunk *type = 0); bool matchTemplateHeader(); bool matchDataType(CodeChunk *type, QString *var = 0); - bool matchParameter(ParsedParameterList& pplist); + bool matchParameter(QVector& pvect, bool& isQPrivateSignal); bool matchFunctionDecl(Aggregate *parent, QStringList *parentPathPtr, FunctionNode **funcPtr, @@ -184,10 +176,10 @@ protected: static QStringList exampleFiles; static QStringList exampleDirs; + static CppCodeParser* cppParser_; QString exampleNameFilter; QString exampleImageFilter; }; -Q_DECLARE_TYPEINFO(CppCodeParser::ParsedParameter, Q_MOVABLE_TYPE); #define COMMAND_ABSTRACT Doc::alias("abstract") #define COMMAND_CLASS Doc::alias("class") diff --git a/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc b/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc index 0f9ca463bb..49cbfc0654 100644 --- a/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc +++ b/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc @@ -1839,8 +1839,13 @@ \li \c {\l QWidget} - The name of a class documented with the \l {class-command} {\\class} command. - \li \c {\l QWidget::sizeHint()} - The name of a member function, - documented with or without an \l {fn-command} {\\fn} command. + \li \c {\l QWidget::sizeHint()} - The signature of a function without + parameters. If a matching function without parameters can't be found, + the link is satisfied with the first matching function found. + + \li \c {\l QWidget::removeAction(QAction* action)} - The signature + of a function with parameters. If an exact match is not found, the + link is not satisfied and qdoc reports a \e {Can't link to...} error. \li \c {\l } - The subject of a \l {headerfile-command} {\\headerfile} command. diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index 5153b0de5c..7dfbbb1cb8 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -804,9 +804,9 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) else if (node->type() == Node::Function) { const FunctionNode *func = static_cast(node); QSet definedParams; - QList::ConstIterator p = func->parameters().constBegin(); + QVector::ConstIterator p = func->parameters().constBegin(); while (p != func->parameters().constEnd()) { - if ((*p).name().isEmpty() && (*p).leftType() != QLatin1String("...") + if ((*p).name().isEmpty() && (*p).dataType() != QLatin1String("...") && func->name() != QLatin1String("operator++") && func->name() != QLatin1String("operator--")) { node->doc().location().warning(tr("Missing parameter name")); @@ -836,7 +836,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) else if (!(*a).isEmpty() && !documentedParams.contains(*a)) { bool needWarning = (func->status() > Node::Obsolete); if (func->overloadNumber() > 0) { - FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name()); + FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name(), QString()); if (primaryFunc) { foreach (const Parameter ¶m, primaryFunc->parameters()) { @@ -1504,7 +1504,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker) if (i != 0) code += ", "; const Parameter &p = func->parameters().at(i); - code += p.leftType() + p.rightType(); + code += p.dataType() + p.rightType(); } code += ")"; @@ -1516,7 +1516,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker) if (i != 0) code += ", "; const Parameter &p = func->parameters().at(i); - code += p.leftType(); + code += p.dataType(); if (code[code.size()-1].isLetterOrNumber()) code += " "; code += p.name() + p.rightType(); @@ -2049,14 +2049,14 @@ void Generator::supplementAlsoList(const Node *node, QList &alsoList) if (func->name().startsWith("set") && func->name().size() >= 4) { alternateName = func->name()[3].toLower(); alternateName += func->name().mid(4); - alternateFunc = func->parent()->findFunctionNode(alternateName); + alternateFunc = func->parent()->findFunctionNode(alternateName, QString()); if (!alternateFunc) { alternateName = "is" + func->name().mid(3); - alternateFunc = func->parent()->findFunctionNode(alternateName); + alternateFunc = func->parent()->findFunctionNode(alternateName, QString()); if (!alternateFunc) { alternateName = "has" + func->name().mid(3); - alternateFunc = func->parent()->findFunctionNode(alternateName); + alternateFunc = func->parent()->findFunctionNode(alternateName, QString()); } } } @@ -2064,7 +2064,7 @@ void Generator::supplementAlsoList(const Node *node, QList &alsoList) alternateName = "set"; alternateName += func->name()[0].toUpper(); alternateName += func->name().mid(1); - alternateFunc = func->parent()->findFunctionNode(alternateName); + alternateFunc = func->parent()->findFunctionNode(alternateName, QString()); } if (alternateFunc && alternateFunc->access() != Node::Private) { diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index 8646e699a9..1ed6820fbf 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -34,11 +34,12 @@ #include "node.h" #include "tree.h" #include "codemarker.h" -#include "codeparser.h" +#include "cppcodeparser.h" #include #include "qdocdatabase.h" #include #include "generator.h" +#include "tokenizer.h" QT_BEGIN_NAMESPACE @@ -810,9 +811,56 @@ Node* Aggregate::findChildNode(const QString& name, NodeType type) Find a function node that is a child of this nose, such that the function node has the specified \a name. */ -FunctionNode *Aggregate::findFunctionNode(const QString& name) const -{ - return static_cast(primaryFunctionMap_.value(name)); +FunctionNode *Aggregate::findFunctionNode(const QString& name, const QString& params) const +{ + FunctionNode* pfn = static_cast(primaryFunctionMap_.value(name)); + FunctionNode* fn = pfn; + if (fn) { + const QVector* funcParams = &(fn->parameters()); + if (params.isEmpty() && funcParams->isEmpty()) + return fn; + bool isQPrivateSignal = false; // Not used in the search + QVector testParams; + if (!params.isEmpty()) { + CppCodeParser* cppParser = CppCodeParser::cppParser(); + cppParser->parseParameters(params, testParams, isQPrivateSignal); + } + NodeList funcs = secondaryFunctionMap_.value(name); + int i = -1; + while (fn) { + if (testParams.size() == funcParams->size()) { + if (testParams.isEmpty()) + return fn; + bool different = false; + for (int j=0; jat(j).dataType()) { + different = true; + break; + } + } + if (!different) + return fn; + } + if (++i < funcs.size()) { + fn = static_cast(funcs.at(i)); + funcParams = &(fn->parameters()); + } + else + fn = 0; + } + if (!fn && !testParams.empty()) + return 0; + } + /* + Most \l commands that link to functions don't include + the parameter declarations in the function signature, + so if the \l is meant to go to a function that does + have parameters, the algorithm above won't find it. + Therefore we must return the pointer to the function + in the primary function map in the cases where the + parameters should have been specified in the \l command. + */ + return (fn ? fn : pfn); } /*! @@ -1090,20 +1138,20 @@ void Aggregate::setIncludes(const QStringList& includes) */ bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2) { - if (f1->parameters().count() != f2->parameters().count()) + if (f1->parameters().size() != f2->parameters().size()) return false; if (f1->isConst() != f2->isConst()) return false; - QList::ConstIterator p1 = f1->parameters().constBegin(); - QList::ConstIterator p2 = f2->parameters().constBegin(); + QVector::ConstIterator p1 = f1->parameters().constBegin(); + QVector::ConstIterator p2 = f2->parameters().constBegin(); while (p2 != f2->parameters().constEnd()) { if ((*p1).hasType() && (*p2).hasType()) { if ((*p1).rightType() != (*p2).rightType()) return false; - QString t1 = p1->leftType(); - QString t2 = p2->leftType(); + QString t1 = p1->dataType(); + QString t2 = p2->dataType(); if (t1.length() < t2.length()) qSwap(t1, t2); @@ -1751,33 +1799,40 @@ void TypedefNode::setAssociatedEnum(const EnumNode *enume) /*! Constructs this parameter from the left and right types - \a leftType and rightType, the parameter \a name, and the + \a dataType and rightType, the parameter \a name, and the \a defaultValue. In practice, \a rightType is not used, and I don't know what is was meant for. */ -Parameter::Parameter(const QString& leftType, +Parameter::Parameter(const QString& dataType, const QString& rightType, const QString& name, const QString& defaultValue) - : leftType_(leftType), rightType_(rightType), name_(name), defaultValue_(defaultValue) + : dataType_(dataType), + rightType_(rightType), + name_(name), + defaultValue_(defaultValue) { + // nothing. } /*! - The standard copy constructor copies the strings from \a p. + Standard copy constructor copies \p. */ Parameter::Parameter(const Parameter& p) - : leftType_(p.leftType_), rightType_(p.rightType_), name_(p.name_), defaultValue_(p.defaultValue_) + : dataType_(p.dataType_), + rightType_(p.rightType_), + name_(p.name_), + defaultValue_(p.defaultValue_) { + // nothing. } /*! - Assigning Parameter \a p to this Parameter copies the - strings across. + standard assignment operator assigns \p. */ Parameter& Parameter::operator=(const Parameter& p) { - leftType_ = p.leftType_; + dataType_ = p.dataType_; rightType_ = p.rightType_; name_ = p.name_; defaultValue_ = p.defaultValue_; @@ -1791,7 +1846,7 @@ Parameter& Parameter::operator=(const Parameter& p) */ QString Parameter::reconstruct(bool value) const { - QString p = leftType_ + rightType_; + QString p = dataType_ + rightType_; if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' '))) p += QLatin1Char(' '); p += name_; @@ -1902,8 +1957,8 @@ void FunctionNode::addParameter(const Parameter& parameter) */ void FunctionNode::borrowParameterNames(const FunctionNode *source) { - QList::Iterator t = parameters_.begin(); - QList::ConstIterator s = source->parameters_.constBegin(); + QVector::Iterator t = parameters_.begin(); + QVector::ConstIterator s = source->parameters_.constBegin(); while (s != source->parameters_.constEnd() && t != parameters_.end()) { if (!(*s).name().isEmpty()) (*t).setName((*s).name()); @@ -1958,7 +2013,7 @@ bool FunctionNode::hasActiveAssociatedProperty() const QStringList FunctionNode::parameterNames() const { QStringList names; - QList::ConstIterator p = parameters().constBegin(); + QVector::ConstIterator p = parameters().constBegin(); while (p != parameters().constEnd()) { names << (*p).name(); ++p; @@ -1975,7 +2030,7 @@ QString FunctionNode::rawParameters(bool names, bool values) const { QString raw; foreach (const Parameter ¶meter, parameters()) { - raw += parameter.leftType() + parameter.rightType(); + raw += parameter.dataType() + parameter.rightType(); if (names) raw += parameter.name(); if (values) @@ -1991,7 +2046,7 @@ QString FunctionNode::rawParameters(bool names, bool values) const QStringList FunctionNode::reconstructParameters(bool values) const { QStringList reconstructedParameters; - QList::ConstIterator p = parameters().constBegin(); + QVector::ConstIterator p = parameters().constBegin(); while (p != parameters().constEnd()) { reconstructedParameters << (*p).reconstruct(values); ++p; diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index e9816dad19..596a71b6d5 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -376,7 +376,7 @@ public: Node* findChildNode(const QString& name, Node::Genus genus) const; Node* findChildNode(const QString& name, NodeType type); virtual void findChildren(const QString& name, NodeList& nodes) const Q_DECL_OVERRIDE; - FunctionNode* findFunctionNode(const QString& name) const; + FunctionNode* findFunctionNode(const QString& name, const QString& params) const; FunctionNode* findFunctionNode(const FunctionNode* clone) const; void addInclude(const QString &include); void setIncludes(const QStringList &includes); @@ -815,12 +815,11 @@ inline void EnumNode::setFlagsType(TypedefNode* t) t->setAssociatedEnum(this); } - class Parameter { public: Parameter() {} - Parameter(const QString& leftType, + Parameter(const QString& dataType, const QString& rightType = QString(), const QString& name = QString(), const QString& defaultValue = QString()); @@ -830,21 +829,24 @@ public: void setName(const QString& name) { name_ = name; } - bool hasType() const { return leftType_.length() + rightType_.length() > 0; } - const QString& leftType() const { return leftType_; } + bool hasType() const { return dataType_.length() + rightType_.length() > 0; } + const QString& dataType() const { return dataType_; } const QString& rightType() const { return rightType_; } const QString& name() const { return name_; } const QString& defaultValue() const { return defaultValue_; } QString reconstruct(bool value = false) const; -private: - QString leftType_; - QString rightType_; + public: + QString dataType_; + QString rightType_; // mws says remove this 04/08/2015 QString name_; QString defaultValue_; }; +//friend class QTypeInfo; +//Q_DECLARE_TYPEINFO(Parameter, Q_MOVABLE_TYPE); + class FunctionNode : public LeafNode { public: @@ -874,7 +876,7 @@ public: void setOverloadNumber(unsigned char n) { overloadNumber_ = n; } void setReimplemented(bool b); void addParameter(const Parameter& parameter); - inline void setParameters(const QList& parameters); + inline void setParameters(const QVector& parameters); void borrowParameterNames(const FunctionNode* source); void setReimplementedFrom(FunctionNode* from); @@ -907,7 +909,7 @@ public: virtual bool isJsMethod() const Q_DECL_OVERRIDE { return (type() == Node::QmlMethod) && (genus() == Node::JS); } - const QList& parameters() const { return parameters_; } + const QVector& parameters() const { return parameters_; } void clearParams() { parameters_.clear(); } QStringList parameterNames() const; QString rawParameters(bool names = false, bool values = false) const; @@ -957,7 +959,7 @@ private: bool privateSignal_: 1; bool overload_ : 1; unsigned char overloadNumber_; - QList parameters_; + QVector parameters_; const FunctionNode* reimplementedFrom_; PropNodeList associatedProperties_; QList reimplementedBy_; @@ -1030,7 +1032,7 @@ private: const PropertyNode* overrides_; }; -inline void FunctionNode::setParameters(const QList &p) +inline void FunctionNode::setParameters(const QVector &p) { parameters_ = p; } diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp index 5f2a61bb76..7f2e64b00c 100644 --- a/src/tools/qdoc/qdocdatabase.cpp +++ b/src/tools/qdoc/qdocdatabase.cpp @@ -380,6 +380,30 @@ QString QDocForest::getLinkCounts(QStringList& strings, QVector& counts) return depends; } +/*! + */ +const Node* QDocForest::findFunctionNode(const QString& target, + const Node* relative, + Node::Genus genus) +{ + QString function, params; + int length = target.length(); + if (target.endsWith(QChar(')'))) { + int position = target.lastIndexOf(QChar('(')); + params = target.mid(position+1, length-position-2); + function = target.left(position); + } + else + function = target; + foreach (Tree* t, searchOrder()) { + const Node* n = t->findFunctionNode(function, params, relative, genus); + if (n) + return n; + relative = 0; + } + return 0; +} + /*! \class QDocDatabase This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a lot of maps and @@ -1342,8 +1366,16 @@ void QDocDatabase::resolveNamespaces() } } } - - +#if 0 +/*! + */ +const Node* QDocDatabase::findFunctionNode(const QString& target, + const Node* relative, + Node::Genus genus) +{ + return forest_.findFunctionNode(target, relative, genus); +} +#endif /*! This function is called for autolinking to a \a type, which could be a function return type or a parameter @@ -1641,6 +1673,8 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q Atom* atom = const_cast(a); QStringList targetPath = atom->string().split("#"); QString first = targetPath.first().trimmed(); + if (Generator::debugging()) + qDebug() << " first:" << first; Tree* domain = 0; Node::Genus genus = Node::DontCare; @@ -1659,8 +1693,14 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q else if (domain) { if (first.endsWith(".html")) node = domain->findNodeByNameAndType(QStringList(first), Node::Document); - else if (first.endsWith("()")) - node = domain->findFunctionNode(first, 0, genus); + else if (first.endsWith(QChar(')'))) { + QString function, params; + int length = first.length(); + int position = first.lastIndexOf(QChar('(')); + params = first.mid(position+1, length-position-2); + function = first.left(position); + node = domain->findFunctionNode(function, params, 0, genus); + } else { int flags = SearchBaseClasses | SearchEnumValues; QStringList nodePath = first.split("::"); @@ -1683,8 +1723,11 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q if (!node && first.contains("/")) return findNodeForTarget(targetPath, relative, genus, ref); } - else if (first.endsWith("()")) + else if (first.endsWith(QChar(')'))) { node = findFunctionNode(first, relative, genus); + if (Generator::debugging()) + qDebug() << " node:" << node; + } else { node = findNodeForTarget(targetPath, relative, genus, ref); return node; diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h index 5d55ea48e1..80a92af4ed 100644 --- a/src/tools/qdoc/qdocdatabase.h +++ b/src/tools/qdoc/qdocdatabase.h @@ -141,15 +141,8 @@ class QDocForest const Node* findFunctionNode(const QString& target, const Node* relative, - Node::Genus genus) { - foreach (Tree* t, searchOrder()) { - const Node* n = t->findFunctionNode(target, relative, genus); - if (n) - return n; - relative = 0; - } - return 0; - } + Node::Genus genus); + const Node* findNodeForTarget(QStringList& targetPath, const Node* relative, Node::Genus genus, diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 37194b911c..8db901bbc7 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -1238,7 +1238,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, for (int i = 0; i < functionNode->parameters().size(); ++i) { Parameter parameter = functionNode->parameters()[i]; writer.writeStartElement("parameter"); - writer.writeAttribute("left", parameter.leftType()); + writer.writeAttribute("left", parameter.dataType()); writer.writeAttribute("right", parameter.rightType()); writer.writeAttribute("name", parameter.name()); writer.writeAttribute("default", parameter.defaultValue()); diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp index 6f63624bf0..155e1de054 100644 --- a/src/tools/qdoc/qmlvisitor.cpp +++ b/src/tools/qdoc/qmlvisitor.cpp @@ -675,7 +675,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member) QString name = member->name.toString(); FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false); - QList parameters; + QVector parameters; for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) { if (!it->type.isEmpty() && !it->name.isEmpty()) parameters.append(Parameter(it->type.toString(), QString(), it->name.toString())); @@ -754,7 +754,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd) } if (overloads > 1) qmlMethod->setOverloadFlag(true); - QList parameters; + QVector parameters; QQmlJS::AST::FormalParameterList* formals = fd->formals; if (formals) { QQmlJS::AST::FormalParameterList* fpl = formals; diff --git a/src/tools/qdoc/tokenizer.cpp b/src/tools/qdoc/tokenizer.cpp index a85c3b00d8..987fff548c 100644 --- a/src/tools/qdoc/tokenizer.cpp +++ b/src/tools/qdoc/tokenizer.cpp @@ -33,6 +33,7 @@ #include "config.h" #include "tokenizer.h" +#include "generator.h" #include #include diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index e0fd68d2e7..d64903e61e 100644 --- a/src/tools/qdoc/tree.cpp +++ b/src/tools/qdoc/tree.cpp @@ -220,6 +220,7 @@ QmlTypeNode* Tree::findQmlTypeNode(const QStringList& path) used as the starting point. */ const FunctionNode* Tree::findFunctionNode(const QStringList& path, + const QString& params, const Node* relative, int findFlags, Node::Genus genus) const @@ -234,7 +235,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path, qcn = static_cast(n); } if (qcn) - return static_cast(qcn->findFunctionNode(path[2])); + return static_cast(qcn->findFunctionNode(path[2], params)); } if (!relative) @@ -254,7 +255,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path, const Node* next; if (i == path.size() - 1) - next = ((const Aggregate*) node)->findFunctionNode(path.at(i)); + next = ((const Aggregate*) node)->findFunctionNode(path.at(i), params); else next = ((const Aggregate*) node)->findChildNode(path.at(i), genus); @@ -262,7 +263,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path, NodeList baseClasses = allBaseClasses(static_cast(node)); foreach (const Node* baseClass, baseClasses) { if (i == path.size() - 1) - next = static_cast(baseClass)->findFunctionNode(path.at(i)); + next = static_cast(baseClass)->findFunctionNode(path.at(i), params); else next = static_cast(baseClass)->findChildNode(path.at(i), genus); @@ -1452,13 +1453,17 @@ void Tree::insertQmlType(const QString& key, QmlTypeNode* n) Split \a target on "::" and find the function node with that path. */ -const Node* Tree::findFunctionNode(const QString& target, const Node* relative, Node::Genus genus) +const Node* Tree::findFunctionNode(const QString& target, + const QString& params, + const Node* relative, + Node::Genus genus) const { QString t = target; - if (t.endsWith("()")) + if (t.endsWith("()")) { t.chop(2); + } QStringList path = t.split("::"); - const FunctionNode* fn = findFunctionNode(path, relative, SearchBaseClasses, genus); + const FunctionNode* fn = findFunctionNode(path, params, relative, SearchBaseClasses, genus); if (fn && fn->metaness() != FunctionNode::MacroWithoutParams) return fn; return 0; diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h index 9e195c90ae..1fef15bc6d 100644 --- a/src/tools/qdoc/tree.h +++ b/src/tools/qdoc/tree.h @@ -107,7 +107,10 @@ class Tree ClassNode* findClassNode(const QStringList& path, const Node* start = 0) const; NamespaceNode* findNamespaceNode(const QStringList& path) const; FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone); - const Node* findFunctionNode(const QString& target, const Node* relative, Node::Genus genus); + const Node* findFunctionNode(const QString& target, + const QString& params, + const Node* relative, + Node::Genus genus) const; Node* findNodeRecursive(const QStringList& path, int pathIndex, @@ -163,6 +166,7 @@ class Tree NamespaceNode *root() { return &root_; } const FunctionNode *findFunctionNode(const QStringList &path, + const QString& params, const Node *relative = 0, int findFlags = 0, Node::Genus genus = Node::DontCare) const; -- cgit v1.2.3 From 330da82cc2b51a96ebcf021746e14304a1c9a68b Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 11 Aug 2015 11:58:02 +0200 Subject: qdoc: Instantiator::objectAt now appear in docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a bug in bool CppCodeParser::splitQmlMethodArg(), which has now been fixed. The bug occurred when there was a "::" in the return type. Change-Id: Id31ed0d4a03d84e76fb69403441a3491ec884ddc Task-number: QTBUG-47438 Reviewed-by: Topi Reiniö Reviewed-by: Andrew Knight --- src/tools/qdoc/cppcodeparser.cpp | 49 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index 8d9596c10b..0f70777256 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -687,10 +687,10 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, ::(, , ...) ::::(, , ...) - This function splits the argument into one of those two - forms, sets \a module, \a qmlTypeName, and \a name, and returns - true. If the argument doesn't match either form, an error - message is emitted and false is returned. + This function splits the \a{arg}ument into one of those + two forms, sets \a type, \a module, and \a qmlTypeName, + and returns true. If the argument doesn't match either + form, an error message is emitted and false is returned. \note The two QML types \e{Component} and \e{QtObject} never have a module qualifier. @@ -700,30 +700,29 @@ bool CppCodeParser::splitQmlMethodArg(const QString& arg, QString& module, QString& qmlTypeName) { - QStringList colonSplit(arg.split("::")); + QString name; + int leftParen = arg.indexOf(QChar('(')); + if (leftParen > 0) + name = arg.left(leftParen); + else + name = arg; + int firstBlank = name.indexOf(QChar(' ')); + if (firstBlank > 0) { + type = name.left(firstBlank); + name = name.right(name.length() - firstBlank - 1); + } + else + type.clear(); + + QStringList colonSplit(name.split("::")); if (colonSplit.size() > 1) { - QStringList blankSplit = colonSplit[0].split(QLatin1Char(' ')); - if (blankSplit.size() > 1) { - type = blankSplit[0]; - if (colonSplit.size() > 2) { - module = blankSplit[1]; - qmlTypeName = colonSplit[1]; - } - else { - module.clear(); - qmlTypeName = blankSplit[1]; - } + if (colonSplit.size() > 2) { + module = colonSplit[0]; + qmlTypeName = colonSplit[1]; } else { - type.clear(); - if (colonSplit.size() > 2) { - module = colonSplit[0]; - qmlTypeName = colonSplit[1]; - } - else { - module.clear(); - qmlTypeName = colonSplit[0]; - } + module.clear(); + qmlTypeName = colonSplit[0]; } return true; } -- cgit v1.2.3 From 89302b8b88b2bfa9581bb15c1caa052cb6d76988 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Fri, 7 Aug 2015 13:46:57 +0200 Subject: doc: Add a few missing const keywords in \fn commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds "const" to a few \fn commands for new operators in QHash and QMap. Change-Id: I93cf7aaf88fcb4db17de5810b555b978e8119e20 Task-number: QTBUG-47669 Reviewed-by: Topi Reiniö --- src/corelib/tools/qhash.cpp | 4 ++-- src/corelib/tools/qmap.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 87a59c67c8..1f3ea36121 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -2240,7 +2240,7 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW Returns a pointer to the current item's key. */ -/*! \fn bool QHash::key_iterator::operator==(key_iterator other) +/*! \fn bool QHash::key_iterator::operator==(key_iterator other) const Returns \c true if \a other points to the same item as this iterator; otherwise returns \c false. @@ -2248,7 +2248,7 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW \sa operator!=() */ -/*! \fn bool QHash::key_iterator::operator!=(key_iterator other) +/*! \fn bool QHash::key_iterator::operator!=(key_iterator other) const Returns \c true if \a other points to a different item than this iterator; otherwise returns \c false. diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index f7aa7332dd..e49a1a098d 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -1719,7 +1719,7 @@ void QMapDataBase::freeData(QMapDataBase *d) Returns a pointer to the current item's key. */ -/*! \fn bool QMap::key_iterator::operator==(key_iterator other) +/*! \fn bool QMap::key_iterator::operator==(key_iterator other) const Returns \c true if \a other points to the same item as this iterator; otherwise returns \c false. @@ -1727,7 +1727,7 @@ void QMapDataBase::freeData(QMapDataBase *d) \sa operator!=() */ -/*! \fn bool QMap::key_iterator::operator!=(key_iterator other) +/*! \fn bool QMap::key_iterator::operator!=(key_iterator other) const Returns \c true if \a other points to a different item than this iterator; otherwise returns \c false. -- cgit v1.2.3