Merge remote-tracking branch 'origin/5.4' into dev

Change-Id: I2811ff0b9d4097f0be60ff16e9664a5060cff23e
This commit is contained in:
Frederik Gladhorn 2014-09-01 11:35:12 +02:00
commit 2dfc786c26
272 changed files with 6704 additions and 3589 deletions

46
configure vendored
View File

@ -617,7 +617,7 @@ CFG_EGL=auto
CFG_EGL_X=auto
CFG_FONTCONFIG=auto
CFG_FREETYPE=auto
CFG_HARFBUZZ=auto
CFG_HARFBUZZ=qt
CFG_SQL_AVAILABLE=
QT_ALL_BUILD_PARTS=" libs tools examples tests "
QT_DEFAULT_BUILD_PARTS="libs tools examples"
@ -2357,13 +2357,14 @@ Third Party Libraries:
+ -system-freetype.... Use the libfreetype provided by the system (enabled if -fontconfig is active).
See http://www.freetype.org
* -no-harfbuzz ....... Do not compile HarfBuzz-NG support.
-qt-harfbuzz ....... (experimental) Use HarfBuzz-NG bundled with Qt
-no-harfbuzz ....... Do not compile HarfBuzz-NG support.
* -qt-harfbuzz ....... Use HarfBuzz-NG bundled with Qt to do text shaping.
It can still be disabled by setting
the QT_HARFBUZZ environment variable to "old".
-system-harfbuzz ... Use HarfBuzz-NG from the operating system
to do text shaping. It can still be disabled
by setting QT_HARFBUZZ environment variable to "old".
-system-harfbuzz ... (experimental) Use HarfBuzz-NG from the operating system
to do text shaping. It can still be disabled
by setting QT_HARFBUZZ environment variable to "old".
by setting the QT_HARFBUZZ environment variable to "old".
See http://www.harfbuzz.org
-no-openssl ........ Do not compile support for OpenSSL.
+ -openssl ........... Enable run-time OpenSSL support.
@ -5301,18 +5302,22 @@ if [ "$CFG_FREETYPE" = "auto" ]; then
fi
# harfbuzz support
[ "$XPLATFORM_MAC" = "yes" ] && [ "$CFG_HARFBUZZ" = "auto" ] && CFG_HARFBUZZ=yes
[ "$CFG_HARFBUZZ" = "auto" ] && CFG_HARFBUZZ=no # disable auto-detection on non-Mac for now
if [ "$CFG_HARFBUZZ" = "auto" ]; then
if compileTest unix/harfbuzz "HarfBuzz"; then
CFG_HARFBUZZ=system
else
CFG_HARFBUZZ=yes
if [ "$CFG_HARFBUZZ" = "system" ]; then
if ! compileTest unix/harfbuzz "HarfBuzz"; then
if [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then
echo " HarfBuzz system library support cannot be enabled due to functionality tests!"
echo " Turn on verbose messaging (-v) to $0 to see the final report."
echo " If you believe this message is in error you may use the continue"
echo " switch (-continue) to $0 to continue."
exit 101
else
CFG_HARFBUZZ=qt
fi
fi
fi
if [ "$XPLATFORM_MAC" = "yes" -a "$CFG_HARFBUZZ" = "system" ]; then
if [ "$XPLATFORM_MAC" = "yes" -a "$CFG_HARFBUZZ" != "qt" ]; then
echo
echo "WARNING: AAT is not supported with -system-harfbuzz on Mac OS X."
echo "WARNING: On OS X, AAT is supported only with -qt-harfbuzz."
echo
fi
@ -6542,7 +6547,7 @@ report_support " FontConfig ............." "$CFG_FONTCONFIG"
report_support " FreeType ..............." "$CFG_FREETYPE" system "system library" yes "bundled copy"
report_support " Glib ..................." "$CFG_GLIB"
report_support " GTK theme .............." "$CFG_QGTKSTYLE"
report_support " HarfBuzz ..............." "$CFG_HARFBUZZ"
report_support " HarfBuzz ..............." "$CFG_HARFBUZZ" system "system library" qt "bundled copy"
report_support " Iconv .................." "$CFG_ICONV"
report_support " ICU ...................." "$CFG_ICU"
report_support " Image formats:"
@ -6630,6 +6635,13 @@ if [ "$CFG_OPENSSL" = "linked" ] && [ "$OPENSSL_LIBS" = "" ]; then
echo "library names through OPENSSL_LIBS."
echo "For example:"
echo " OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto' ./configure -openssl-linked"
fi
if [ "$CFG_JOURNALD" = "yes" ] || [ "$CFG_SLOG2" = "yes"]; then
echo
echo "NOTE: journald or slog2 integration is enabled."
echo "If your users intend on developing applications against this build,"
echo "ensure that the IDEs they use either set QT_LOGGING_TO_CONSOLE to 1"
echo "or the IDE is able to read the logged output from journald or slog2."
echo
fi
if [ "$CFG_XKBCOMMON" = "qt" ] && [ "$CFG_XKB_CONFIG_ROOT" = "not found" ]; then

View File

@ -3,12 +3,11 @@ macro.Aring.HTML = "Å"
macro.aring.HTML = "å"
macro.Auml.HTML = "Ä"
macro.author = "\\b{Author:}"
macro.br.HTML = "<br />"
macro.BR.HTML = "<br />"
macro.copyright.HTML = "&copy;"
macro.eacute.HTML = "&eacute;"
macro.gui = "\\b"
macro.hr.HTML = "<hr />"
macro.HR.HTML = "<hr />"
macro.iacute.HTML = "&iacute;"
macro.key = "\\b"
macro.menu = "\\b"

View File

@ -305,6 +305,10 @@ headers
margin-left: 0px;
margin-right: 0px;
}
.subtitle, .small-subtitle {
display: block;
clear: left;
}
}
h1 {

View File

@ -95,12 +95,9 @@ MainWindow::MainWindow()
groupBox->setLayout(m_layout);
QMenu *fileMenu = new QMenu("&File");
QMenu *helpMenu = new QMenu("&Help");
QMenu *showMenu = new QMenu("&Show");
menuBar()->addMenu(fileMenu);
menuBar()->addMenu(showMenu);
menuBar()->addMenu(helpMenu);
QMenu *fileMenu = menuBar()->addMenu("&File");
QMenu *showMenu = menuBar()->addMenu("&Show");
QMenu *helpMenu = menuBar()->addMenu("&Help");
QAction *exit = new QAction("E&xit", fileMenu);
QAction *aboutQt = new QAction("About Qt", helpMenu);
QAction *showLogo = new QAction("Show 3D Logo", showMenu);

View File

@ -185,7 +185,7 @@ int main(int argc, char **argv)
fmt.setDepthBufferSize(24);
fmt.setStencilBufferSize(8);
window.setFormat(fmt);
window.show();
window.showMaximized();
return app.exec();
}

View File

@ -104,6 +104,9 @@ TextEdit::TextEdit(QWidget *parent)
textEdit->setFocus();
setCurrentFileName(QString());
QFont textFont("Helvetica");
textFont.setStyleHint(QFont::SansSerif);
textEdit->setFont(textFont);
fontChanged(textEdit->font());
colorChanged(textEdit->textColor());
alignmentChanged(textEdit->alignment());

33
header.LGPL21 Normal file
View File

@ -0,0 +1,33 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the FOO module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/

View File

@ -56,6 +56,7 @@
# if defined(ANGLE_ENABLE_D3D11)
# include <d3d10_1.h>
# include <d3d10.h>
# include <d3d11.h>
# include <dxgi.h>
# include <dxgi1_2.h>

View File

@ -305,6 +305,19 @@ EGLint Renderer11::initialize()
mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples);
}
#if !defined(ANGLE_PLATFORM_WINRT)
static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
{
ID3D10Multithread *multithread;
result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread));
ASSERT(SUCCEEDED(result));
result = multithread->SetMultithreadProtected(true);
ASSERT(SUCCEEDED(result));
multithread->Release();
}
#endif
initializeDevice();
return EGL_SUCCESS;

View File

@ -319,6 +319,10 @@ EGLint Renderer9::initialize()
D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
behaviorFlags |= D3DCREATE_MULTITHREADED;
{
TRACE_EVENT0("gpu", "D3d9_CreateDevice");
result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);

View File

@ -52,7 +52,13 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
#else
#define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 }
#endif
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
#else
#define hb_mutex_impl_init(M) InitializeCriticalSection (M)
#endif
#define hb_mutex_impl_lock(M) EnterCriticalSection (M)
#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)

View File

@ -117,15 +117,16 @@
#endif
// Take from https://github.com/behdad/harfbuzz/commit/26a963b9cb4af3119177f277a2d48a5d537458fb
#ifdef _WIN32_WCE
#if defined(_WIN32_WCE)
/* Some things not defined on Windows CE. */
#define MemoryBarrier()
#define getenv(Name) NULL
#define setlocale(Category, Locale) "C"
static int errno = 0; /* Use something better? */
#elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
#define getenv(Name) NULL
#endif
/* Basics */

View File

@ -0,0 +1,23 @@
Index: pcre_compile.c
===================================================================
--- pcre_compile.c (revision 1494)
+++ pcre_compile.c (revision 1495)
@@ -8267,12 +8267,16 @@
/* If it was a capturing subpattern, check to see if it contained any
recursive back references. If so, we must wrap it in atomic brackets.
- In any event, remove the block from the chain. */
+ Because we are moving code along, we must ensure that any pending recursive
+ references are updated. In any event, remove the block from the chain. */
if (capnumber > 0)
{
if (cd->open_caps->flag)
{
+ *code = OP_END;
+ adjust_recurse(start_bracket, 1 + LINK_SIZE,
+ (options & PCRE_UTF8) != 0, cd, cd->hwm);
memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
IN_UCHARS(code - start_bracket));
*start_bracket = OP_ONCE;

View File

@ -0,0 +1,45 @@
Index: pcre_compile.c
===================================================================
--- pcre_compile.c (revision 1497)
+++ pcre_compile.c (revision 1498)
@@ -2374,6 +2374,7 @@
if (c == OP_RECURSE)
{
const pcre_uchar *scode = cd->start_code + GET(code, 1);
+ const pcre_uchar *endgroup = scode;
BOOL empty_branch;
/* Test for forward reference or uncompleted reference. This is disabled
@@ -2388,24 +2389,20 @@
if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
}
- /* If we are scanning a completed pattern, there are no forward references
- and all groups are complete. We need to detect whether this is a recursive
- call, as otherwise there will be an infinite loop. If it is a recursion,
- just skip over it. Simple recursions are easily detected. For mutual
- recursions we keep a chain on the stack. */
+ /* If the reference is to a completed group, we need to detect whether this
+ is a recursive call, as otherwise there will be an infinite loop. If it is
+ a recursion, just skip over it. Simple recursions are easily detected. For
+ mutual recursions we keep a chain on the stack. */
+ do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
+ if (code >= scode && code <= endgroup) continue; /* Simple recursion */
else
- {
+ {
recurse_check *r = recurses;
- const pcre_uchar *endgroup = scode;
-
- do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
- if (code >= scode && code <= endgroup) continue; /* Simple recursion */
-
for (r = recurses; r != NULL; r = r->prev)
if (r->group == scode) break;
if (r != NULL) continue; /* Mutual recursion */
- }
+ }
/* Completed reference; scan the referenced group, remembering it on the
stack chain to detect mutual recursions. */

View File

@ -2370,6 +2370,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (c == OP_RECURSE)
{
const pcre_uchar *scode = cd->start_code + GET(code, 1);
const pcre_uchar *endgroup = scode;
BOOL empty_branch;
/* Test for forward reference or uncompleted reference. This is disabled
@ -2384,24 +2385,20 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
}
/* If we are scanning a completed pattern, there are no forward references
and all groups are complete. We need to detect whether this is a recursive
call, as otherwise there will be an infinite loop. If it is a recursion,
just skip over it. Simple recursions are easily detected. For mutual
recursions we keep a chain on the stack. */
/* If the reference is to a completed group, we need to detect whether this
is a recursive call, as otherwise there will be an infinite loop. If it is
a recursion, just skip over it. Simple recursions are easily detected. For
mutual recursions we keep a chain on the stack. */
do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
if (code >= scode && code <= endgroup) continue; /* Simple recursion */
else
{
{
recurse_check *r = recurses;
const pcre_uchar *endgroup = scode;
do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
if (code >= scode && code <= endgroup) continue; /* Simple recursion */
for (r = recurses; r != NULL; r = r->prev)
if (r->group == scode) break;
if (r != NULL) continue; /* Mutual recursion */
}
}
/* Completed reference; scan the referenced group, remembering it on the
stack chain to detect mutual recursions. */
@ -8244,12 +8241,16 @@ for (;;)
/* If it was a capturing subpattern, check to see if it contained any
recursive back references. If so, we must wrap it in atomic brackets.
In any event, remove the block from the chain. */
Because we are moving code along, we must ensure that any pending recursive
references are updated. In any event, remove the block from the chain. */
if (capnumber > 0)
{
if (cd->open_caps->flag)
{
*code = OP_END;
adjust_recurse(start_bracket, 1 + LINK_SIZE,
(options & PCRE_UTF8) != 0, cd, cd->hwm);
memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
IN_UCHARS(code - start_bracket));
*start_bracket = OP_ONCE;

View File

@ -108,15 +108,20 @@ public class QtNative
}
}
public static void openURL(String url)
public static boolean openURL(String url)
{
boolean ok = true;
try {
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
activity().startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
ok = false;
}
return ok;
}
// this method loads full path libs

View File

@ -0,0 +1,72 @@
From d52fac0c0b5d12cd117ae4b871f0ac6a202755ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20Br=C3=BCning?= <michael.bruning@digia.com>
Date: Wed, 27 Aug 2014 12:42:00 +0200
Subject: [PATCH] Let ANGLE use multithreaded devices if necessary.
This is needed to prevent lock-ups in application that use ANGLE from
multiple threads, as e.g. QtWebEngine based applications do.
The environment variable QT_D3DCREATE_MULTITHREADED is used to
communicate this from the QtWebEngine module.
Change-Id: Ibd5a5c75eb68af567d420d9a35efb3490c93b27c
---
src/3rdparty/angle/src/common/platform.h | 1 +
.../angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 13 +++++++++++++
.../angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 4 ++++
3 files changed, 18 insertions(+)
diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h
index e16e7ac..cedc6f2 100644
--- a/src/3rdparty/angle/src/common/platform.h
+++ b/src/3rdparty/angle/src/common/platform.h
@@ -56,6 +56,7 @@
# if defined(ANGLE_ENABLE_D3D11)
# include <d3d10_1.h>
+# include <d3d10.h>
# include <d3d11.h>
# include <dxgi.h>
# include <dxgi1_2.h>
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
index 17a13f9..651b065 100644
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
@@ -305,6 +305,19 @@ EGLint Renderer11::initialize()
mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples);
}
+#if !defined(ANGLE_PLATFORM_WINRT)
+ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
+ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
+ {
+ ID3D10Multithread *multithread;
+ result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread));
+ ASSERT(SUCCEEDED(result));
+ result = multithread->SetMultithreadProtected(true);
+ ASSERT(SUCCEEDED(result));
+ multithread->Release();
+ }
+#endif
+
initializeDevice();
return EGL_SUCCESS;
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
index 491c27a..2c8a79f 100644
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
@@ -319,6 +319,10 @@ EGLint Renderer9::initialize()
D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
+ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
+ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
+ behaviorFlags |= D3DCREATE_MULTITHREADED;
+
{
TRACE_EVENT0("gpu", "D3d9_CreateDevice");
result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
--
1.8.3.2

View File

@ -222,7 +222,8 @@ QUnifiedTimer::QUnifiedTimer() :
QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false),
startTimersPending(false), stopTimerPending(false),
slowdownFactor(5.0f), profilerCallback(0)
slowdownFactor(5.0f), profilerCallback(0),
driverStartTime(0), temporalDrift(0)
{
time.invalidate();
driver = &defaultDriver;
@ -253,18 +254,56 @@ QUnifiedTimer *QUnifiedTimer::instance()
void QUnifiedTimer::maybeUpdateAnimationsToCurrentTime()
{
qint64 elapsed = driver->elapsed();
if (elapsed - lastTick > 50)
updateAnimationTimers(elapsed);
if (elapsed() - lastTick > 50)
updateAnimationTimers(-1);
}
void QUnifiedTimer::updateAnimationTimers(qint64 currentTick)
qint64 QUnifiedTimer::elapsed() const
{
if (driver->isRunning())
return driverStartTime + driver->elapsed();
else if (time.isValid())
return time.elapsed() + temporalDrift;
// Reaching here would normally indicate that the function is called
// under the wrong circumstances as neither pauses nor actual animations
// are running and there should be no need to query for elapsed().
return 0;
}
void QUnifiedTimer::startAnimationDriver()
{
if (driver->isRunning()) {
qWarning("QUnifiedTimer::startAnimationDriver: driver is already running...");
return;
}
// Set the start time to the currently elapsed() value before starting.
// This means we get the animation system time including the temporal drift
// which is what we want.
driverStartTime = elapsed();
driver->start();
}
void QUnifiedTimer::stopAnimationDriver()
{
if (!driver->isRunning()) {
qWarning("QUnifiedTimer::stopAnimationDriver: driver is not running");
return;
}
// Update temporal drift. Since the driver is running, elapsed() will
// return the total animation time in driver-time. Subtract the current
// wall time to get the delta.
temporalDrift = elapsed() - time.elapsed();
driver->stop();
}
void QUnifiedTimer::updateAnimationTimers(qint64)
{
//setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
if(insideTick)
return;
qint64 totalElapsed = currentTick >= 0 ? currentTick : driver->elapsed();
qint64 totalElapsed = elapsed();
// ignore consistentTiming in case the pause timer is active
qint64 delta = (consistentTiming && !pauseTimer.isActive()) ?
@ -323,8 +362,7 @@ void QUnifiedTimer::localRestart()
} else if (!driver->isRunning()) {
if (pauseTimer.isActive())
pauseTimer.stop();
driver->setStartTime(time.isValid() ? time.elapsed() : 0);
driver->start();
startAnimationDriver();
}
}
@ -345,27 +383,26 @@ void QUnifiedTimer::setTimingInterval(int interval)
if (driver->isRunning() && !pauseTimer.isActive()) {
//we changed the timing interval
driver->stop();
driver->setStartTime(time.isValid() ? time.elapsed() : 0);
driver->start();
stopAnimationDriver();
startAnimationDriver();
}
}
void QUnifiedTimer::startTimers()
{
startTimersPending = false;
if (!animationTimers.isEmpty())
updateAnimationTimers(-1);
//we transfer the waiting animations into the "really running" state
animationTimers += animationTimersToStart;
animationTimersToStart.clear();
if (!animationTimers.isEmpty()) {
localRestart();
if (!time.isValid()) {
lastTick = 0;
time.start();
temporalDrift = 0;
driverStartTime = 0;
}
localRestart();
}
}
@ -373,7 +410,7 @@ void QUnifiedTimer::stopTimer()
{
stopTimerPending = false;
if (animationTimers.isEmpty()) {
driver->stop();
stopAnimationDriver();
pauseTimer.stop();
// invalidate the start reference time
time.invalidate();
@ -483,14 +520,12 @@ void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d)
return;
}
if (driver->isRunning()) {
driver->stop();
d->setStartTime(time.isValid() ? time.elapsed() : 0);
d->start();
}
bool running = driver->isRunning();
if (running)
stopAnimationDriver();
driver = d;
if (running)
startAnimationDriver();
}
void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
@ -500,13 +535,12 @@ void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
return;
}
bool running = driver->isRunning();
if (running)
stopAnimationDriver();
driver = &defaultDriver;
if (d->isRunning()) {
d->stop();
driver->setStartTime(time.isValid() ? time.elapsed() : 0);
driver->start();
}
if (running)
startAnimationDriver();
}
/*!
@ -603,10 +637,12 @@ void QAnimationTimer::restartAnimationTimer()
void QAnimationTimer::startAnimations()
{
if (!startAnimationPending)
return;
startAnimationPending = false;
//force timer to update, which prevents large deltas for our newly added animations
if (!animations.isEmpty())
QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
//we transfer the waiting animations into the "really running" state
animations += animationsToStart;
@ -618,7 +654,8 @@ void QAnimationTimer::startAnimations()
void QAnimationTimer::stopTimer()
{
stopTimerPending = false;
if (animations.isEmpty()) {
bool pendingStart = startAnimationPending && animationsToStart.size() > 0;
if (animations.isEmpty() && !pendingStart) {
QUnifiedTimer::resumeAnimationTimer(this);
QUnifiedTimer::stopAnimationTimer(this);
// invalidate the start reference time
@ -749,20 +786,25 @@ QAnimationDriver::~QAnimationDriver()
This is to take into account that pauses can occur in running
animations which will stop the driver, but the time still
increases.
\obsolete
This logic is now handled internally in the animation system.
*/
void QAnimationDriver::setStartTime(qint64 startTime)
void QAnimationDriver::setStartTime(qint64)
{
Q_D(QAnimationDriver);
d->startTime = startTime;
}
/*!
Returns the start time of the animation.
\obsolete
This logic is now handled internally in the animation system.
*/
qint64 QAnimationDriver::startTime() const
{
Q_D(const QAnimationDriver);
return d->startTime;
return 0;
}
@ -772,6 +814,10 @@ qint64 QAnimationDriver::startTime() const
If \a timeStep is positive, it will be used as the current time in the
calculations; otherwise, the current clock time will be used.
Since 5.4, the timeStep argument is ignored and elapsed() will be
used instead in combination with the internal time offsets of the
animation system.
*/
void QAnimationDriver::advanceAnimation(qint64 timeStep)

View File

@ -149,6 +149,7 @@ public:
virtual qint64 elapsed() const;
// ### Qt6: Remove these two functions
void setStartTime(qint64 startTime);
qint64 startTime() const;
@ -157,6 +158,7 @@ Q_SIGNALS:
void stopped();
protected:
// ### Qt6: Remove timestep argument
void advanceAnimation(qint64 timeStep = -1);
virtual void start();
virtual void stop();

View File

@ -132,9 +132,8 @@ private:
class Q_CORE_EXPORT QAnimationDriverPrivate : public QObjectPrivate
{
public:
QAnimationDriverPrivate() : running(false), startTime(0) {}
QAnimationDriverPrivate() : running(false) {}
bool running;
qint64 startTime;
};
class Q_CORE_EXPORT QAbstractAnimationTimer : public QObject
@ -193,6 +192,10 @@ public:
int runningAnimationCount();
void registerProfilerCallback(void (*cb)(qint64));
void startAnimationDriver();
void stopAnimationDriver();
qint64 elapsed() const;
protected:
void timerEvent(QTimerEvent *);
@ -233,6 +236,9 @@ private:
int closestPausedAnimationTimerTimeToFinish();
void (*profilerCallback)(qint64);
qint64 driverStartTime; // The time the animation driver was started
qint64 temporalDrift; // The delta between animation driver time and wall time.
};
class QAnimationTimer : public QAbstractAnimationTimer

View File

@ -1045,7 +1045,7 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo
// determine charset
QTextCodec *c = QTextCodec::codecForUtfText(ba, 0);
if (!c) {
QByteArray header = ba.left(512).toLower();
QByteArray header = ba.left(1024).toLower();
int pos = header.indexOf("meta ");
if (pos != -1) {
pos = header.indexOf("charset=", pos);

View File

@ -249,7 +249,7 @@
If the value is \e not compatible with the property's type, the
property is \e not changed, and false is returned. But if the
property with the given name doesn't exist in the QObject (i.e.,
if it wasn't declared with Q_PROPERTY(), a new property with the
if it wasn't declared with Q_PROPERTY()), a new property with the
given name and value is automatically added to the QObject, but
false is still returned. This means that a return of false can't
be used to determine whether a particular property was actually

View File

@ -392,7 +392,7 @@
compatible with the slot's arguments. Arguments can also be implicitly
converted by the compiler, if needed.
You can also connect to functors or C++11 lamdas:
You can also connect to functors or C++11 lambdas:
\code
connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });

View File

@ -880,7 +880,12 @@ public:
int control;
};
# ifdef Q_COMPILER_DECLTYPE
// We need to use __typeof__ if we don't have decltype or if the compiler
// hasn't been updated to the fix of Core Language Defect Report 382
// (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#382).
// GCC 4.3 and 4.4 have support for decltype, but are affected by DR 382.
# if defined(Q_COMPILER_DECLTYPE) && \
(defined(Q_CC_CLANG) || defined(Q_CC_INTEL) || !defined(Q_CC_GNU) || (__GNUC__ * 100 + __GNUC_MINOR__) >= 405)
# define QT_FOREACH_DECLTYPE(x) typename QtPrivate::remove_reference<decltype(x)>::type
# else
# define QT_FOREACH_DECLTYPE(x) __typeof__((x))

View File

@ -98,6 +98,7 @@ Qt {
#ifndef QT_NO_GESTURES
Q_ENUMS(GestureState)
Q_ENUMS(GestureType)
Q_ENUMS(NativeGestureType)
#endif
Q_ENUMS(CursorMoveStyle)
Q_ENUMS(TimerType)

View File

@ -369,15 +369,15 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
if (fileHandle == INVALID_HANDLE_VALUE)
return -1;
DWORD bytesToRead = DWORD(maxlen); // <- lossy
qint64 bytesToRead = maxlen;
// Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
// the chunks are too large, so we limit the block size to 32MB.
static const DWORD maxBlockSize = 32 * 1024 * 1024;
static const qint64 maxBlockSize = 32 * 1024 * 1024;
qint64 totalRead = 0;
do {
DWORD blockSize = qMin<DWORD>(bytesToRead, maxBlockSize);
DWORD blockSize = DWORD(qMin(bytesToRead, maxBlockSize));
DWORD bytesRead;
if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) {
if (totalRead == 0) {
@ -392,7 +392,7 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
totalRead += bytesRead;
bytesToRead -= bytesRead;
} while (totalRead < maxlen);
return qint64(totalRead);
return totalRead;
}
/*

View File

@ -324,7 +324,7 @@ QWinRTSettingsPrivate::QWinRTSettingsPrivate(QSettings::Scope scope, const QStri
}
QWinRTSettingsPrivate::QWinRTSettingsPrivate(QString rPath)
: QSettingsPrivate(QSettings::NativeFormat)
: QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, rPath, QString())
, writeContainer(0)
{
init(QSettings::UserScope);

View File

@ -48,24 +48,24 @@ QT_BEGIN_NAMESPACE
\class QStorageInfo
\inmodule QtCore
\since 5.4
\brief Provides information about currently mounted storages and drives.
\brief Provides information about currently mounted storage and drives.
\ingroup io
\ingroup shared
Allows retrieving information about the volume's space, its mount point,
label, filesystem name.
label, and filesystem name.
You can create an instance of QStorageInfo by passing the path to the
volume's mount point as the constructor parameter, or you can set it using
setPath() method. The static mountedVolumes() method can be used to get the
volume's mount point as a constructor parameter, or you can set it using
the setPath() method. The static mountedVolumes() method can be used to get the
list of all mounted filesystems.
QStorageInfo always caches the retrieved information but you can call
QStorageInfo always caches the retrieved information, but you can call
refresh() to invalidate the cache.
The following example retrieves the most common information about the root
volume of the system and prints information about it.
volume of the system, and prints information about it.
\snippet code/src_corelib_io_qstorageinfo.cpp 2
*/
@ -73,7 +73,8 @@ QT_BEGIN_NAMESPACE
/*!
Constructs an empty QStorageInfo object.
This object is not ready for use, invalid and all its parameters are empty.
Objects created with the default constructor will be invalid and therefore
not ready for use.
\sa setPath(), isReady(), isValid()
*/
@ -83,15 +84,15 @@ QStorageInfo::QStorageInfo()
}
/*!
Constructs a new QStorageInfo that gives information about the volume
Constructs a new QStorageInfo object that gives information about the volume
mounted at \a path.
If you pass a directory or file, the QStorageInfo object will refer to the
volume where this directory or file is located.
You can check if the created object is correct using the isValid() method.
The following example shows how to get volume on which application is
located. It is recommended to always check that volume is ready and valid.
The following example shows how to get the volume on which the application is
located. It is recommended to always check that the volume is ready and valid.
\snippet code/src_corelib_io_qstorageinfo.cpp 0
@ -104,8 +105,8 @@ QStorageInfo::QStorageInfo(const QString &path)
}
/*!
Constructs a new QStorageInfo that gives information about the volume
that contains the \a dir folder.
Constructs a new QStorageInfo object that gives information about the volume
containing the \a dir folder.
*/
QStorageInfo::QStorageInfo(const QDir &dir)
: d(new QStorageInfoPrivate)
@ -114,7 +115,7 @@ QStorageInfo::QStorageInfo(const QDir &dir)
}
/*!
Constructs a new QStorageInfo that is a copy of the \a other QStorageInfo.
Constructs a new QStorageInfo object that is a copy of the \a other QStorageInfo object.
*/
QStorageInfo::QStorageInfo(const QStorageInfo &other)
: d(other.d)
@ -122,14 +123,14 @@ QStorageInfo::QStorageInfo(const QStorageInfo &other)
}
/*!
Destroys the QStorageInfo and frees its resources.
Destroys the QStorageInfo object and frees its resources.
*/
QStorageInfo::~QStorageInfo()
{
}
/*!
Makes a copy of \a other QStorageInfo and assigns it to this QStorageInfo.
Makes a copy of the QStorageInfo object \a other and assigns it to this QStorageInfo object.
*/
QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other)
{
@ -140,20 +141,20 @@ QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other)
/*!
\fn QStorageInfo &QStorageInfo::operator=(QStorageInfo &&other)
Move-assigns \a other to this QStorageInfo instance.
Assigns \a other to this QStorageInfo instance.
*/
/*!
\fn void QStorageInfo::swap(QStorageInfo &other)
Swaps this volume info with the \a other. This function is very fast and
Swaps this volume info with \a other. This function is very fast and
never fails.
*/
/*!
Sets QStorageInfo to the filesystem mounted where \a path is located.
Sets this QStorageInfo object to the filesystem mounted where \a path is located.
Path can either be a root path of the filesystem, or a directory or a file
\a path can either be a root path of the filesystem, a directory, or a file
within that filesystem.
\sa rootPath()
@ -171,12 +172,12 @@ void QStorageInfo::setPath(const QString &path)
Returns the mount point of the filesystem this QStorageInfo object
represents.
On Windows, returns the volume letter in case the volume is not mounted to
On Windows, it returns the volume letter in case the volume is not mounted to
a directory.
Note that the value returned by rootPath() is the real mount point of a
volume and may not be equal to the value passed to constructor or setPath()
method. For example, if you have only the root volume in the system and
volume, and may not be equal to the value passed to the constructor or setPath()
method. For example, if you have only the root volume in the system, and
pass '/directory' to setPath(), then this method will return '/'.
\sa setPath(), device()
@ -187,10 +188,10 @@ QString QStorageInfo::rootPath() const
}
/*!
Returns the size (in bytes) available for the current user. If the user is
the root user or a system administrator returns all available size.
Returns the size (in bytes) available for the current user. It returns
the total size available if the user is the root user or a system administrator.
This size can be less than or equal to the free size, returned by
This size can be less than or equal to the free size returned by
bytesFree() function.
\sa bytesTotal(), bytesFree()
@ -201,9 +202,9 @@ qint64 QStorageInfo::bytesAvailable() const
}
/*!
Returns the number of free bytes on a volume. Note, that if there are some
kind of quotas on the filesystem, this value can be bigger than
bytesAvailable().
Returns the number of free bytes in a volume. Note that if there are
quotas on the filesystem, this value can be larger than the value
returned by bytesAvailable().
\sa bytesTotal(), bytesAvailable()
*/
@ -213,7 +214,7 @@ qint64 QStorageInfo::bytesFree() const
}
/*!
Returns total volume size in bytes.
Returns the total volume size in bytes.
\sa bytesFree(), bytesAvailable()
*/
@ -227,7 +228,7 @@ qint64 QStorageInfo::bytesTotal() const
This is a platform-dependent function, and filesystem names can vary
between different operating systems. For example, on Windows filesystems
can be named as 'NTFS' and on Linux as 'ntfs-3g' or 'fuseblk'.
they can be named \c NTFS, and on Linux they can be named \c ntfs-3g or \c fuseblk.
\sa name()
*/
@ -240,8 +241,8 @@ QByteArray QStorageInfo::fileSystemType() const
Returns the device for this volume.
For example, on Unix filesystems (including OS X), this returns the
devpath like '/dev/sda0' for local storages. On Windows, returns the UNC
path starting with \\\\?\\ for local storages (i.e. volume GUID).
devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC
path starting with \c \\\\?\\ for local storages (in other words, the volume GUID).
\sa rootPath()
*/
@ -251,13 +252,13 @@ QByteArray QStorageInfo::device() const
}
/*!
Returns the human-readable name of a filesystem, usually called 'label'.
Returns the human-readable name of a filesystem, usually called \c label.
Not all filesystems support this feature, in this case value returned by
Not all filesystems support this feature. In this case, the value returned by
this method could be empty. An empty string is returned if the file system
does not support labels or no label is set.
does not support labels, or if no label is set.
On Linux, retrieving the volume's label requires udev to be present in the
On Linux, retrieving the volume's label requires \c udev to be present in the
system.
\sa fileSystemType()
@ -283,8 +284,8 @@ QString QStorageInfo::displayName() const
Returns true if this QStorageInfo represents the system root volume; false
otherwise.
On Unix filesystems, the root volume is a volume mounted at "/", on Windows
the root volume is the volume where OS is installed.
On Unix filesystems, the root volume is a volume mounted on \c /. On Windows,
the root volume is the volume where the OS is installed.
\sa root()
*/
@ -299,8 +300,8 @@ bool QStorageInfo::isReadOnly() const
}
/*!
Returns true if current filesystem is ready to work; false otherwise. For
example, false is returned if CD volume is not inserted.
Returns true if the current filesystem is ready to work; false otherwise. For
example, false is returned if the CD volume is not inserted.
Note that fileSystemType(), name(), bytesTotal(), bytesFree(), and
bytesAvailable() will return invalid data until the volume is ready.
@ -326,9 +327,9 @@ bool QStorageInfo::isValid() const
/*!
Resets QStorageInfo's internal cache.
QStorageInfo caches information about storages to speed up performance -
QStorageInfo retrieves information during object construction and/or call
to setPath() method. You have to manually reset the cache by calling this
QStorageInfo caches information about storage to speed up performance.
QStorageInfo retrieves information during object construction and/or when calling
the setPath() method. You have to manually reset the cache by calling this
function to update storage information.
*/
void QStorageInfo::refresh()
@ -338,17 +339,16 @@ void QStorageInfo::refresh()
}
/*!
Returns list of QStorageInfos that corresponds to the list of currently
Returns the list of QStorageInfo objects that corresponds to the list of currently
mounted filesystems.
On Windows, this returns drives presented in 'My Computer' folder. On Unix
operating systems, returns list of all mounted filesystems (except for
On Windows, this returns the drives visible in the \gui{My Computer} folder. On Unix
operating systems, it returns the list of all mounted filesystems (except for
pseudo filesystems).
By default, returns all currently mounted filesystems.
Returns all currently mounted filesystems by default.
The example shows how to retrieve all storages present in the system and
skip read-only storages.
The example shows how to retrieve all available filesystems, skipping read-only ones.
\snippet code/src_corelib_io_qstorageinfo.cpp 1
@ -364,8 +364,8 @@ Q_GLOBAL_STATIC_WITH_ARGS(QStorageInfo, getRoot, (QStorageInfoPrivate::root()))
/*!
Returns a QStorageInfo object that represents the system root volume.
On Unix systems this call returns '/' volume, on Windows the volume where
operating system is installed is returned.
On Unix systems this call returns the root ('/') volume; in Windows the volume where
the operating system is installed.
\sa isRoot()
*/
@ -379,8 +379,8 @@ QStorageInfo QStorageInfo::root()
\relates QStorageInfo
Returns true if \a first QStorageInfo object refers to the same drive or volume
as the \a second; otherwise returns false.
Returns true if the \a first QStorageInfo object refers to the same drive or volume
as the \a second; otherwise it returns false.
Note that the result of comparing two invalid QStorageInfo objects is always
positive.
@ -391,8 +391,8 @@ QStorageInfo QStorageInfo::root()
\relates QStorageInfo
Returns true if \a first QStorageInfo object refers to a different drive or
volume than the one specified by \a second; otherwise returns false.
Returns true if the \a first QStorageInfo object refers to a different drive or
volume than the \a second; otherwise returns false.
*/
QT_END_NAMESPACE

View File

@ -746,6 +746,11 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
from which you got the reference.
*/
/*! \fn QJsonValueRef *QJsonArray::iterator::operator->() const
Returns a pointer to a modifiable reference to the current item.
*/
/*! \fn QJsonValueRef QJsonArray::iterator::operator[](int j) const
Returns a modifiable reference to the item at offset \a j from the
@ -971,6 +976,11 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
Returns the current item.
*/
/*! \fn QJsonValue *QJsonArray::const_iterator::operator->() const
Returns a pointer to the current item.
*/
/*! \fn QJsonValue QJsonArray::const_iterator::operator[](int j) const
Returns the item at offset \a j from the item pointed to by this iterator (the item at

View File

@ -112,14 +112,17 @@ public:
typedef std::random_access_iterator_tag iterator_category;
typedef int difference_type;
typedef QJsonValue value_type;
//typedef T *pointer;
typedef QJsonValueRef reference;
inline iterator() : a(0), i(0) { }
explicit inline iterator(QJsonArray *array, int index) : a(array), i(index) { }
inline QJsonValueRef operator*() const { return QJsonValueRef(a, i); }
//inline T *operator->() const { return &concrete(i)->value; }
#ifdef Q_QDOC
inline QJsonValueRef* operator->() const;
#else
inline QJsonValueRefPtr operator->() const { return QJsonValueRefPtr(a, i); }
#endif
inline QJsonValueRef operator[](int j) const { return QJsonValueRef(a, i + j); }
inline bool operator==(const iterator &o) const { return i == o.i; }
@ -153,7 +156,6 @@ public:
typedef std::random_access_iterator_tag iterator_category;
typedef qptrdiff difference_type;
typedef QJsonValue value_type;
//typedef const T *pointer;
typedef QJsonValue reference;
inline const_iterator() : a(0), i(0) { }
@ -162,7 +164,11 @@ public:
inline const_iterator(const iterator &o) : a(o.a), i(o.i) {}
inline QJsonValue operator*() const { return a->at(i); }
//inline T *operator->() const { return &concrete(i)->value; }
#ifdef Q_QDOC
inline QJsonValue* operator->() const;
#else
inline QJsonValuePtr operator->() const { return QJsonValuePtr(a->at(i)); }
#endif
inline QJsonValue operator[](int j) const { return a->at(i+j); }
inline bool operator==(const const_iterator &o) const { return i == o.i; }
inline bool operator!=(const const_iterator &o) const { return i != o.i; }

View File

@ -710,6 +710,11 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
\sa key()
*/
/*! \fn QJsonValueRef *QJsonObject::iterator::operator->() const
Returns a pointer to a modifiable reference to the current item.
*/
/*!
\fn bool QJsonObject::iterator::operator==(const iterator &other) const
\fn bool QJsonObject::iterator::operator==(const const_iterator &other) const
@ -893,6 +898,11 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
\sa key()
*/
/*! \fn QJsonValue *QJsonObject::const_iterator::operator->() const
Returns a pointer to the current item.
*/
/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &other) const
\fn bool QJsonObject::const_iterator::operator==(const iterator &other) const

View File

@ -107,7 +107,6 @@ public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type;
typedef QJsonValue value_type;
// typedef T *pointer;
typedef QJsonValueRef reference;
Q_DECL_CONSTEXPR inline iterator() : o(0), i(0) {}
@ -116,7 +115,11 @@ public:
inline QString key() const { return o->keyAt(i); }
inline QJsonValueRef value() const { return QJsonValueRef(o, i); }
inline QJsonValueRef operator*() const { return QJsonValueRef(o, i); }
//inline T *operator->() const { return &concrete(i)->value; }
#ifdef Q_QDOC
inline QJsonValueRef* operator->() const;
#else
inline QJsonValueRefPtr operator->() const { return QJsonValueRefPtr(o, i); }
#endif
inline bool operator==(const iterator &other) const { return i == other.i; }
inline bool operator!=(const iterator &other) const { return i != other.i; }
@ -157,7 +160,11 @@ public:
inline QString key() const { return o->keyAt(i); }
inline QJsonValue value() const { return o->valueAt(i); }
inline QJsonValue operator*() const { return o->valueAt(i); }
//inline const T *operator->() const { return &concrete(i)->value; }
#ifdef Q_QDOC
inline QJsonValue* operator->() const;
#else
inline QJsonValuePtr operator->() const { return QJsonValuePtr(o->valueAt(i)); }
#endif
inline bool operator==(const const_iterator &other) const { return i == other.i; }
inline bool operator!=(const const_iterator &other) const { return i != other.i; }

View File

@ -192,6 +192,33 @@ private:
struct UnionHelper;
};
#ifndef Q_QDOC
// ### Qt 6: Get rid of these fake pointer classes
class QJsonValuePtr
{
QJsonValue value;
public:
explicit QJsonValuePtr(const QJsonValue& val)
: value(val) {}
QJsonValue& operator*() { return value; }
QJsonValue* operator->() { return &value; }
};
class QJsonValueRefPtr
{
QJsonValueRef valueRef;
public:
QJsonValueRefPtr(QJsonArray *array, int idx)
: valueRef(array, idx) {}
QJsonValueRefPtr(QJsonObject *object, int idx)
: valueRef(object, idx) {}
QJsonValueRef& operator*() { return valueRef; }
QJsonValueRef* operator->() { return &valueRef; }
};
#endif
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
#endif

View File

@ -184,6 +184,7 @@ QT_BEGIN_NAMESPACE
\value MouseMove Mouse move (QMouseEvent).
\value MouseTrackingChange The mouse tracking state has changed.
\value Move Widget's position changed (QMoveEvent).
\value NativeGesture The system has detected a gesture (QNativeGestureEvent).
\value OrientationChange The screens orientation has changes (QScreenOrientationChangeEvent)
\value Paint Screen update necessary (QPaintEvent).
\value PaletteChange Palette of the widget changed.

View File

@ -44,7 +44,7 @@
#include <QtCore/qglobal.h>
#ifdef Q_OS_WINRT
#ifdef Q_OS_WIN
#include <QtCore/QThread>
#include <QtCore/QAbstractEventDispatcher>
@ -57,6 +57,8 @@ QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
#ifdef Q_OS_WINRT
// Environment ------------------------------------------------------
errno_t qt_winrt_getenv_s(size_t*, char*, size_t, const char*);
errno_t qt_winrt__putenv_s(const char*, const char*);
@ -122,6 +124,8 @@ generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *)
generate_inline_return_func0(tzset, void)
generate_inline_return_func0(_tzset, void)
#endif // Q_OS_WINRT
// Convenience macros for handling HRESULT values
#define RETURN_IF_FAILED(msg, ret) \
if (FAILED(hr)) { \
@ -211,5 +215,6 @@ static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results
} // QWinRTFunctions
#endif // Q_OS_WINRT
#endif // Q_OS_WIN
#endif // QFUNCTIONS_WINRT_H

View File

@ -721,7 +721,7 @@ jboolean QJNIObjectPrivate::callStaticMethod<jboolean>(jclass clazz,
{
va_list args;
va_start(args, sig);
jboolean res = callStaticMethod<jboolean>(clazz, methodName, sig);
jboolean res = callStaticMethod<jboolean>(clazz, methodName, sig, args);
va_end(args);
return res;
}
@ -1026,7 +1026,7 @@ jlong QJNIObjectPrivate::callStaticMethod<jlong>(jclass clazz,
{
va_list args;
va_start(args, sig);
jlong res = callStaticMethod<jlong>(clazz, methodName, sig);
jlong res = callStaticMethod<jlong>(clazz, methodName, sig, args);
va_end(args);
return res;
}
@ -1119,7 +1119,7 @@ jdouble QJNIObjectPrivate::callStaticMethod<jdouble>(const char *className,
{
va_list args;
va_start(args, sig);
jdouble res = callStaticMethod<jdouble>(className, methodName, sig);
jdouble res = callStaticMethod<jdouble>(className, methodName, sig, args);
va_end(args);
return res;
}

View File

@ -65,6 +65,7 @@
# include "qjsonobject.h"
# include "qjsonarray.h"
# include "qjsondocument.h"
# include "qbytearraylist.h"
#endif
#ifndef QT_NO_GEOM_VARIANT
@ -270,6 +271,7 @@ struct DefinedTypesFilter {
\value QJsonDocument QJsonDocument
\value QModelIndex QModelIndex
\value QUuid QUuid
\value QByteArrayList QByteArrayList
\value User Base value for user types
\value UnknownType This is an invalid type id. It is returned from QMetaType for types that are not registered
@ -1191,6 +1193,9 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
case QMetaType::QVariant:
stream << *static_cast<const NS(QVariant)*>(data);
break;
case QMetaType::QByteArrayList:
stream << *static_cast<const NS(QByteArrayList)*>(data);
break;
#endif
case QMetaType::QByteArray:
stream << *static_cast<const NS(QByteArray)*>(data);
@ -1414,6 +1419,9 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
case QMetaType::QVariant:
stream >> *static_cast< NS(QVariant)*>(data);
break;
case QMetaType::QByteArrayList:
stream >> *static_cast< NS(QByteArrayList)*>(data);
break;
#endif
case QMetaType::QByteArray:
stream >> *static_cast< NS(QByteArray)*>(data);

View File

@ -127,6 +127,7 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId();
F(QVariantMap, 8, QVariantMap) \
F(QVariantList, 9, QVariantList) \
F(QVariantHash, 28, QVariantHash) \
F(QByteArrayList, 49, QByteArrayList) \
#define QT_FOR_EACH_STATIC_GUI_CLASS(F)\
F(QFont, 64, QFont) \
@ -180,6 +181,7 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId();
F(QVariantList, -1, QVariantList, "QList<QVariant>") \
F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
#define QT_FOR_EACH_STATIC_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
@ -393,7 +395,7 @@ public:
QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
FirstCoreType = Bool,
LastCoreType = QJsonDocument,
LastCoreType = QByteArrayList,
FirstGuiType = QFont,
LastGuiType = QPolygonF,
FirstWidgetsType = QSizePolicy,
@ -419,7 +421,7 @@ public:
QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
QRegularExpression = 44,
QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
QObjectStar = 39, SChar = 40,
QByteArrayList = 49, QObjectStar = 39, SChar = 40,
Void = 43,
QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
QFont = 64, QPixmap = 65, QBrush = 66, QColor = 67, QPalette = 68,
@ -1763,6 +1765,7 @@ QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
typedef QList<QVariant> QVariantList;
typedef QMap<QString, QVariant> QVariantMap;
typedef QHash<QString, QVariant> QVariantHash;
typedef QList<QByteArray> QByteArrayList;
#define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \
QT_BEGIN_NAMESPACE \

View File

@ -207,6 +207,7 @@ template<> struct TypeDefinition<QJsonObject> { static const bool IsAvailable =
template<> struct TypeDefinition<QJsonValue> { static const bool IsAvailable = false; };
template<> struct TypeDefinition<QModelIndex> { static const bool IsAvailable = false; };
template<> struct TypeDefinition<QUrl> { static const bool IsAvailable = false; };
template<> struct TypeDefinition<QByteArrayList> { static const bool IsAvailable = false; };
#endif
#ifdef QT_NO_GEOM_VARIANT
template<> struct TypeDefinition<QRect> { static const bool IsAvailable = false; };

View File

@ -4749,10 +4749,14 @@ bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject
int signal_index = -1;
if (signal) {
void *args[] = { &signal_index, signal };
senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
if (signal_index < 0 || signal_index >= QMetaObjectPrivate::get(senderMetaObject)->signalCount) {
qWarning("QObject::disconnect: signal not found in %s", senderMetaObject->className());
return false;
for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
break;
}
if (!senderMetaObject) {
qWarning("QObject::disconnect: signal not found in %s", sender->metaObject()->className());
return QMetaObject::Connection(0);
}
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
}

View File

@ -61,6 +61,7 @@
#include "qjsonobject.h"
#include "qjsonarray.h"
#include "qjsondocument.h"
#include "qbytearraylist.h"
#endif
#include "private/qvariant_p.h"
#include "qmetatype_p.h"
@ -2841,6 +2842,7 @@ bool QVariant::canConvert(int targetTypeId) const
if (targetTypeId == QMetaType::QVariantList
&& (d.type == QMetaType::QVariantList
|| d.type == QMetaType::QStringList
|| d.type == QMetaType::QByteArrayList
|| QMetaType::hasRegisteredConverterFunction(d.type,
qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()))) {
return true;

View File

@ -51,6 +51,9 @@
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qobject.h>
#ifndef QT_BOOTSTRAPPED
#include <QtCore/qbytearraylist.h>
#endif
QT_BEGIN_NAMESPACE
@ -713,6 +716,11 @@ namespace QtPrivate {
if (v.userType() == qMetaTypeId<QStringList>()) {
return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QStringList*>(v.constData())));
}
#ifndef QT_BOOTSTRAPPED
if (v.userType() == qMetaTypeId<QByteArrayList>()) {
return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QByteArrayList*>(v.constData())));
}
#endif
return QSequentialIterable(v.value<QtMetaTypePrivate::QSequentialIterableImpl>());
}
};
@ -735,7 +743,7 @@ namespace QtPrivate {
{
static QVariantList invoke(const QVariant &v)
{
if (v.userType() == qMetaTypeId<QStringList>() || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
if (v.userType() == qMetaTypeId<QStringList>() || v.userType() == qMetaTypeId<QByteArrayList>() || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
QSequentialIterable iter = QVariantValueHelperInterface<QSequentialIterable>::invoke(v);
QVariantList l;
l.reserve(iter.size());

View File

@ -526,10 +526,6 @@ QList<QAbstractState*> QStateMachinePrivate::computeStatesToEnter(const QList<QA
QAbstractState *s = lst.at(j);
addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
}
for (int j = src ? 1 : 0; j < lst.size(); ++j) {
QAbstractState *s = lst.at(j);
addAncestorStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
}
if (isParallel(lca)) {
QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates();
foreach (QAbstractState* child,lcac) {
@ -727,6 +723,7 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
return;
}
}
addAncestorStatesToEnter(s, root, statesToEnter, statesForDefaultEntry);
}
}
@ -1095,7 +1092,6 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
if (currentErrorState != 0) {
QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
addAncestorStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
} else {
qWarning("Unrecoverable error detected in running state machine: %s",
qPrintable(errorString));

View File

@ -774,10 +774,10 @@ Q_OUTOFLINE_TEMPLATE QList<T>::~QList()
template <typename T>
Q_OUTOFLINE_TEMPLATE bool QList<T>::operator==(const QList<T> &l) const
{
if (p.size() != l.p.size())
return false;
if (d == l.d)
return true;
if (p.size() != l.p.size())
return false;
Node *i = reinterpret_cast<Node *>(p.end());
Node *b = reinterpret_cast<Node *>(p.begin());
Node *li = reinterpret_cast<Node *>(l.p.end());

View File

@ -7929,6 +7929,11 @@ QString &QString::setRawData(const QChar *unicode, int size)
Returns the Latin-1 string stored in this object.
*/
/*! \fn const char *QLatin1String::data() const
Returns the Latin-1 string stored in this object.
*/
/*! \fn int QLatin1String::size() const
Returns the size of the Latin-1 string stored in this object.
@ -7959,6 +7964,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
/*!
\fn bool QLatin1String::operator==(const QByteArray &other) const
\since 5.0
\overload
The \a other byte array is converted to a QString using
the QString::fromUtf8() function.
You can disable this operator by defining \c
QT_NO_CAST_FROM_ASCII when you compile your applications. This
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
*/
/*! \fn bool QLatin1String::operator!=(const QString &other) const
Returns \c true if this string is not equal to string \a other;
@ -7984,6 +8003,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
/*!
\fn bool QLatin1String::operator!=(const QByteArray &other) const
\since 5.0
\overload operator!=()
The \a other byte array is converted to a QString using
the QString::fromUtf8() function.
You can disable this operator by defining \c
QT_NO_CAST_FROM_ASCII when you compile your applications. This
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
*/
/*!
\fn bool QLatin1String::operator>(const QString &other) const
@ -8010,6 +8043,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
for example.
*/
/*!
\fn bool QLatin1String::operator>(const QByteArray &other) const
\since 5.0
\overload
The \a other const char pointer is converted to a QString using
the QString::fromUtf8() function.
You can disable this operator by defining \c QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
to ensure that all user-visible strings go through QObject::tr(),
for example.
*/
/*!
\fn bool QLatin1String::operator<(const QString &other) const
@ -8036,6 +8083,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
/*!
\fn bool QLatin1String::operator<(const QByteArray &other) const
\since 5.0
\overload
The \a other const char pointer is converted to a QString using
the QString::fromUtf8() function.
You can disable this operator by defining \c
QT_NO_CAST_FROM_ASCII when you compile your applications. This
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
*/
/*!
\fn bool QLatin1String::operator>=(const QString &other) const
@ -8062,6 +8123,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
/*!
\fn bool QLatin1String::operator>=(const QByteArray &other) const
\since 5.0
\overload
The \a other array is converted to a QString using
the QString::fromUtf8() function.
You can disable this operator by defining \c
QT_NO_CAST_FROM_ASCII when you compile your applications. This
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
*/
/*! \fn bool QLatin1String::operator<=(const QString &other) const
Returns \c true if this string is lexically less than or equal
@ -8087,6 +8162,19 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
/*!
\fn bool QLatin1String::operator<=(const QByteArray &other) const
\since 5.0
\overload
The \a other array is converted to a QString using
the QString::fromUtf8() function.
You can disable this operator by defining \c
QT_NO_CAST_FROM_ASCII when you compile your applications. This
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
*/
/*! \fn bool operator==(QLatin1String s1, QLatin1String s2)

View File

@ -256,7 +256,7 @@ public:
static inline QVector<T> fromStdVector(const std::vector<T> &vector)
{ QVector<T> tmp; tmp.reserve(int(vector.size())); std::copy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; }
inline std::vector<T> toStdVector() const
{ std::vector<T> tmp; tmp.reserve(size()); std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; }
{ return std::vector<T>(d->begin(), d->end()); }
private:
friend class QRegion; // Optimization for QRegion::rects()
@ -711,10 +711,10 @@ typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
template <typename T>
bool QVector<T>::operator==(const QVector<T> &v) const
{
if (d->size != v.d->size)
return false;
if (d == v.d)
return true;
if (d->size != v.d->size)
return false;
T* b = d->begin();
T* i = b + d->size;
T* j = v.d->end();
@ -810,7 +810,9 @@ bool QVector<T>::contains(const T &t) const
template <typename T>
int QVector<T>::count(const T &t) const
{
return int(std::count(cbegin(), cend(), t));
const T *b = d->begin();
const T *e = d->end();
return int(std::count(b, e, t));
}
template <typename T>

View File

@ -989,10 +989,16 @@ void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
QImageWriter::supportedImageFormats() functions to retrieve a
complete list of the supported file formats.
Note: When you add a non-empty filename to a QIcon, the icon becomes
If a high resolution version of the image exists (identified by
the suffix \c @2x on the base name), it is automatically loaded
and added with the \e{device pixel ratio} set to a value of 2.
This can be disabled by setting the environment variable
\c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING (see QImageReader).
\note When you add a non-empty filename to a QIcon, the icon becomes
non-null, even if the file doesn't exist or points to a corrupt file.
\sa addPixmap()
\sa addPixmap(), QPixmap::devicePixelRatio()
*/
void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
{

View File

@ -176,7 +176,6 @@ QIconTheme::QIconTheme(const QString &themeName)
{
QFile themeIndex;
QList <QIconDirInfo> keyList;
QStringList iconDirs = QIcon::themeSearchPaths();
for ( int i = 0 ; i < iconDirs.size() ; ++i) {
QDir iconDir(iconDirs[i]);
@ -269,7 +268,7 @@ QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName,
}
QString contentDir = theme.contentDir() + QLatin1Char('/');
QList<QIconDirInfo> subDirs = theme.keyList();
const QVector<QIconDirInfo> subDirs = theme.keyList();
const QString svgext(QLatin1String(".svg"));
const QString pngext(QLatin1String(".png"));
@ -333,9 +332,7 @@ QIconLoaderEngine::QIconLoaderEngine(const QString& iconName)
QIconLoaderEngine::~QIconLoaderEngine()
{
while (!m_entries.isEmpty())
delete m_entries.takeLast();
Q_ASSERT(m_entries.size() == 0);
qDeleteAll(m_entries);
}
QIconLoaderEngine::QIconLoaderEngine(const QIconLoaderEngine &other)
@ -371,10 +368,8 @@ void QIconLoaderEngine::ensureLoaded()
{
if (!(QIconLoader::instance()->themeKey() == m_key)) {
while (!m_entries.isEmpty())
delete m_entries.takeLast();
qDeleteAll(m_entries);
Q_ASSERT(m_entries.size() == 0);
m_entries = QIconLoader::instance()->loadIcon(m_iconName);
m_key = QIconLoader::instance()->themeKey();
}
@ -448,8 +443,10 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
// Note that m_entries are sorted so that png-files
// come first
const int numEntries = m_entries.size();
// Search for exact matches first
for (int i = 0; i < m_entries.count(); ++i) {
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize)) {
return entry;
@ -459,7 +456,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
// Find the minimum distance icon
int minimalSize = INT_MAX;
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < m_entries.count(); ++i) {
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize);
if (distance < minimalSize) {
@ -564,11 +561,12 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
{
QIconEngine::AvailableSizesArgument &arg
= *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data);
const QList<QIconDirInfo> directoryKey = QIconLoader::instance()->theme().keyList();
arg.sizes.clear();
const int N = m_entries.size();
arg.sizes.reserve(N);
// Gets all sizes from the DirectoryInfo entries
for (int i = 0 ; i < m_entries.size() ; ++i) {
for (int i = 0; i < N; ++i) {
int size = m_entries.at(i)->dir.size;
arg.sizes.append(QSize(size, size));
}

View File

@ -62,6 +62,8 @@
#include <private/qicon_p.h>
#include <private/qfactoryloader_p.h>
#include <QtCore/QHash>
#include <QtCore/QVector>
#include <QtCore/QTypeInfo>
QT_BEGIN_NAMESPACE
@ -84,6 +86,7 @@ struct QIconDirInfo
short threshold;
Type type : 4;
};
Q_DECLARE_TYPEINFO(QIconDirInfo, Q_MOVABLE_TYPE);
class QIconLoaderEngineEntry
{
@ -99,13 +102,13 @@ public:
struct ScalableEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QIcon svgIcon;
};
struct PixmapEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QPixmap basePixmap;
};
@ -144,18 +147,18 @@ public:
QIconTheme(const QString &name);
QIconTheme() : m_valid(false) {}
QStringList parents() { return m_parents; }
QList <QIconDirInfo> keyList() { return m_keyList; }
QVector<QIconDirInfo> keyList() { return m_keyList; }
QString contentDir() { return m_contentDir; }
bool isValid() { return m_valid; }
private:
QString m_contentDir;
QList <QIconDirInfo> m_keyList;
QVector<QIconDirInfo> m_keyList;
QStringList m_parents;
bool m_valid;
};
class Q_GUI_EXPORT QIconLoader : public QObject
class Q_GUI_EXPORT QIconLoader
{
public:
QIconLoader();

View File

@ -1391,14 +1391,14 @@ QVector<QRgb> QImage::colorTable() const
/*!
Returns the device pixel ratio for the image. This is the
ratio between image pixels and device-independent pixels.
ratio between \e{device pixels} and \e{device independent pixels}.
Use this function when calculating layout geometry based on
the image size: QSize layoutSize = image.size() / image.devicePixelRatio()
The default value is 1.0.
\sa setDevicePixelRatio()
\sa setDevicePixelRatio(), QImageReader
*/
qreal QImage::devicePixelRatio() const
{
@ -1423,7 +1423,8 @@ qreal QImage::devicePixelRatio() const
image size will take the ratio into account:
QSize layoutSize = image.size() / image.devicePixelRatio()
The net effect of this is that the image is displayed as
high-dpi image rather than a large image.
high-DPI image rather than a large image
(see \l{Drawing High Resolution Versions of Pixmaps and Images}).
\sa devicePixelRatio()
*/

View File

@ -74,17 +74,32 @@
that occurred, or errorString() to get a human readable
description of what went wrong.
\section1 Formats
Call supportedImageFormats() for a list of formats that
QImageReader can read. QImageReader supports all built-in image
formats, in addition to any image format plugins that support
reading.
reading. Call supportedMimeTypes() to obtain a list of supported MIME
types, which for example can be passed to QFileDialog::setMimeTypeFilters().
QImageReader autodetects the image format by default, by looking at the
provided (optional) format string, the file name suffix, and the data
stream contents. You can enable or disable this feature, by calling
setAutoDetectImageFormat().
\sa QImageWriter, QImageIOHandler, QImageIOPlugin
\section1 High Resolution Versions of Images
It is possible to provide high resolution versions of images should a scaling
between \e{device pixels} and \e{device independent pixels} be in effect.
The high resolution version is marked by the suffix \c @2x on the base name.
The image read will have its \e{device pixel ratio} set to a value of 2.
This can be disabled by setting the environment variable
\c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING.
\sa QImageWriter, QImageIOHandler, QImageIOPlugin, QMimeDatabase
\sa QImage::devicePixelRatio(), QPixmap::devicePixelRatio(), QIcon, QPainter::drawPixmap(), QPainter::drawImage(), Qt::AA_UseHighDpiPixmaps
*/
/*!

View File

@ -648,14 +648,14 @@ void QPixmap::setMask(const QBitmap &mask)
/*!
Returns the device pixel ratio for the pixmap. This is the
ratio between pixmap pixels and device-independent pixels.
ratio between \e{device pixels} and \e{device independent pixels}.
Use this function when calculating layout geometry based on
the pixmap size: QSize layoutSize = image.size() / image.devicePixelRatio()
The default value is 1.0.
\sa setDevicePixelRatio()
\sa setDevicePixelRatio(), QImageReader
*/
qreal QPixmap::devicePixelRatio() const
{
@ -680,7 +680,8 @@ qreal QPixmap::devicePixelRatio() const
pixmap size will take the ratio into account:
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio()
The net effect of this is that the pixmap is displayed as
high-dpi pixmap rather than a large pixmap.
high-DPI pixmap rather than a large pixmap
(see \l{Drawing High Resolution Versions of Pixmaps and Images}).
\sa devicePixelRatio()
*/

View File

@ -1094,7 +1094,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const
return false;
QImage image;
if (sourceImage.format() != QImage::Format_RGB32 || sourceImage.format() != QImage::Format_ARGB32 || sourceImage.format() != QImage::Format_ARGB32_Premultiplied)
if (sourceImage.format() != QImage::Format_RGB32 && sourceImage.format() != QImage::Format_ARGB32 && sourceImage.format() != QImage::Format_ARGB32_Premultiplied)
image = sourceImage.convertToFormat(QImage::Format_RGB32);
else
image = sourceImage;

View File

@ -66,7 +66,6 @@ HEADERS += \
kernel/qplatformsharedgraphicscache.h \
kernel/qplatformdialoghelper.h \
kernel/qplatformservices.h \
kernel/qplatformscreenpageflipper.h \
kernel/qplatformsystemtrayicon.h \
kernel/qplatformsessionmanager.h \
kernel/qpixelformat.h \
@ -120,7 +119,6 @@ SOURCES += \
kernel/qplatformsharedgraphicscache.cpp \
kernel/qplatformdialoghelper.cpp \
kernel/qplatformservices.cpp \
kernel/qplatformscreenpageflipper.cpp \
kernel/qplatformsystemtrayicon.cpp \
kernel/qplatformsessionmanager.cpp \
kernel/qplatformmenu.cpp \

View File

@ -3495,11 +3495,13 @@ static const char *eventClassName(QEvent::Type t)
return "QCloseEvent";
case QEvent::FileOpen:
return "QFileOpenEvent";
#ifndef QT_NO_GESTURES
case QEvent::NativeGesture:
return "QNativeGestureEvent";
case QEvent::Gesture:
case QEvent::GestureOverride:
return "QGestureEvent";
#endif
case QEvent::HoverEnter:
case QEvent::HoverLeave:
case QEvent::HoverMove:
@ -3595,6 +3597,14 @@ public:
static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("FocusReason");
return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(reason);
}
# ifndef QT_NO_GESTURES
static const char *nativeGestureTypeToString(Qt::NativeGestureType type)
{
static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("NativeGestureType");
return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(type);
}
# endif // !QT_NO_GESTURES
};
} // namespace
@ -3775,7 +3785,8 @@ QDebug operator<<(QDebug dbg, const QEvent *e)
# ifndef QT_NO_GESTURES
case QEvent::NativeGesture: {
const QNativeGestureEvent *ne = static_cast<const QNativeGestureEvent *>(e);
dbg << "QNativeGestureEvent(localPos=" << ne->localPos() << ", value=" << ne->value() << ')';
dbg << "QNativeGestureEvent(" << DebugHelper::nativeGestureTypeToString(ne->gestureType())
<< "localPos=" << ne->localPos() << ", value=" << ne->value() << ')';
}
break;
# endif // !QT_NO_GESTURES

View File

@ -639,6 +639,7 @@ bool QOpenGLContext::create()
*/
void QOpenGLContext::destroy()
{
deleteQGLContext();
Q_D(QOpenGLContext);
if (d->platformGLContext)
emit aboutToBeDestroyed();
@ -1086,6 +1087,9 @@ void *QOpenGLContext::qGLContextHandle() const
}
/*!
internal: If the delete function is specified QOpenGLContext "owns"
the passed context handle and will use the delete function to destroy it.
\internal
*/
void QOpenGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *))

View File

@ -198,6 +198,7 @@ class Q_GUI_EXPORT QOpenGLContextPrivate : public QObjectPrivate
public:
QOpenGLContextPrivate()
: qGLContextHandle(0)
, qGLContextDeleteFunction(0)
, platformGLContext(0)
, shareContext(0)
, shareGroup(0)

View File

@ -274,15 +274,6 @@ QPlatformScreen * QPlatformScreen::platformScreenForWindow(const QWindow *window
Reimplement in subclass to return the image format which corresponds to the screen format
*/
/*!
Implemented in subclasses to return a page flipper object for the screen, or 0 if the
hardware does not support page flipping. The default implementation returns 0.
*/
QPlatformScreenPageFlipper *QPlatformScreen::pageFlipper() const
{
return 0;
}
/*!
Reimplement this function in subclass to return the cursor of the screen.

View File

@ -71,7 +71,6 @@ class QPlatformOpenGLContext;
class QPlatformScreenPrivate;
class QPlatformWindow;
class QPlatformCursor;
class QPlatformScreenPageFlipper;
class QScreen;
class QSurfaceFormat;
@ -115,7 +114,6 @@ public:
virtual QString name() const { return QString(); }
virtual QPlatformScreenPageFlipper *pageFlipper() const;
virtual QPlatformCursor *cursor() const;
protected:

View File

@ -1,121 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qplatformscreenpageflipper.h"
QT_BEGIN_NAMESPACE
/*!
\class QPlatformScreenBuffer
\since 5.0
\internal
\preliminary
\ingroup qpa
\brief The QPlatformScreenBuffer class provides an abstraction for screen buffers.
*/
QPlatformScreenBuffer::QPlatformScreenBuffer()
: m_destroyed(false)
, m_ready(true)
{
}
QPlatformScreenBuffer::~QPlatformScreenBuffer()
{
}
bool QPlatformScreenBuffer::isDestroyed() const
{
return m_destroyed;
}
bool QPlatformScreenBuffer::isReady() const
{
return m_ready;
}
void QPlatformScreenBuffer::aboutToBeDisplayed()
{
}
void QPlatformScreenBuffer::displayed()
{
}
/*!
\class QPlatformScreenPageFlipper
\since 5.0
\internal
\preliminary
\ingroup qpa
\brief The QPlatformScreenPageFlipper class provides an abstract interface for display buffer swapping
Implement the displayBuffer() function to initiate a buffer swap. The
bufferDisplayed() signal should be emitted once the buffer is actually displayed on
the screen. The bufferReleased() signal should be emitted when the buffer data is no
longer owned by the display hardware.
*/
QPlatformScreenPageFlipper::QPlatformScreenPageFlipper(QObject *parent)
:QObject(parent)
{
}
/*!
\fn bool QPlatformScreenPageFlipper::displayBuffer(QPlatformScreenBuffer *buffer)
Implemented in subclasses to display \a buffer directly on the screen. Returns \c true
if it is possible to display the buffer, and \c false if the buffer cannot be displayed.
If this function returns \c true, the buffer must not be modified or destroyed before the
bufferReleased() signal is emitted. The signal bufferDisplayed() is emitted when the buffer
is displayed on the screen. The two signals may be emitted in either order.
This function is allowed to block.
*/
QT_END_NAMESPACE

View File

@ -508,7 +508,11 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
case MousePressAndHoldInterval:
return QVariant(800);
case MouseDoubleClickDistance:
return QVariant(5);
{
bool ok = false;
int dist = qgetenv("QT_DBL_CLICK_DIST").toInt(&ok);
return QVariant(ok ? dist : 5);
}
}
return QVariant();
}

View File

@ -100,6 +100,7 @@ public:
, cursor(Qt::ArrowCursor)
, hasCursor(false)
#endif
, compositing(false)
{
isWindow = true;
}
@ -175,6 +176,8 @@ public:
QCursor cursor;
bool hasCursor;
#endif
bool compositing;
};

View File

@ -47,6 +47,10 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE_EXT
#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
#endif
QT_BEGIN_NAMESPACE
/*!
@ -360,8 +364,6 @@ static int qt_gl_resolve_extensions()
extensions |= QOpenGLExtensions::BGRATextureFormat;
if (extensionMatcher.match("GL_ARB_texture_rectangle"))
extensions |= QOpenGLExtensions::TextureRectangle;
if (extensionMatcher.match("GL_SGIS_generate_mipmap"))
extensions |= QOpenGLExtensions::GenerateMipmap;
if (extensionMatcher.match("GL_ARB_texture_compression"))
extensions |= QOpenGLExtensions::TextureCompression;
if (extensionMatcher.match("GL_EXT_texture_compression_s3tc"))
@ -385,44 +387,51 @@ static int qt_gl_resolve_extensions()
if (format.majorVersion() >= 2)
extensions |= QOpenGLExtensions::GenerateMipmap;
if (format.majorVersion() >= 3)
if (format.majorVersion() >= 3) {
extensions |= QOpenGLExtensions::PackedDepthStencil
| QOpenGLExtensions::Depth24
| QOpenGLExtensions::ElementIndexUint
| QOpenGLExtensions::MapBufferRange;
| QOpenGLExtensions::MapBufferRange
| QOpenGLExtensions::FramebufferBlit
| QOpenGLExtensions::FramebufferMultisample;
} else {
// Recognize features by extension name.
if (extensionMatcher.match("GL_OES_packed_depth_stencil"))
extensions |= QOpenGLExtensions::PackedDepthStencil;
if (extensionMatcher.match("GL_OES_depth24"))
extensions |= QOpenGLExtensions::Depth24;
if (extensionMatcher.match("GL_ANGLE_framebuffer_blit"))
extensions |= QOpenGLExtensions::FramebufferBlit;
if (extensionMatcher.match("GL_ANGLE_framebuffer_multisample"))
extensions |= QOpenGLExtensions::FramebufferMultisample;
if (extensionMatcher.match("GL_NV_framebuffer_blit"))
extensions |= QOpenGLExtensions::FramebufferBlit;
if (extensionMatcher.match("GL_NV_framebuffer_multisample"))
extensions |= QOpenGLExtensions::FramebufferMultisample;
}
if (extensionMatcher.match("GL_OES_mapbuffer"))
extensions |= QOpenGLExtensions::MapBuffer;
if (extensionMatcher.match("GL_OES_packed_depth_stencil"))
extensions |= QOpenGLExtensions::PackedDepthStencil;
if (extensionMatcher.match("GL_OES_element_index_uint"))
extensions |= QOpenGLExtensions::ElementIndexUint;
if (extensionMatcher.match("GL_OES_depth24"))
extensions |= QOpenGLExtensions::Depth24;
// TODO: Consider matching GL_APPLE_texture_format_BGRA8888 as well, but it needs testing.
// We don't match GL_APPLE_texture_format_BGRA8888 here because it has different semantics.
if (extensionMatcher.match("GL_IMG_texture_format_BGRA8888") || extensionMatcher.match("GL_EXT_texture_format_BGRA8888"))
extensions |= QOpenGLExtensions::BGRATextureFormat;
if (extensionMatcher.match("GL_ANGLE_framebuffer_blit"))
extensions |= QOpenGLExtensions::FramebufferBlit;
if (extensionMatcher.match("GL_ANGLE_framebuffer_multisample"))
extensions |= QOpenGLExtensions::FramebufferMultisample;
if (extensionMatcher.match("GL_NV_framebuffer_blit"))
extensions |= QOpenGLExtensions::FramebufferBlit;
if (extensionMatcher.match("GL_NV_framebuffer_multisample"))
extensions |= QOpenGLExtensions::FramebufferMultisample;
if (format.majorVersion() >= 3)
extensions |= QOpenGLExtensions::FramebufferBlit | QOpenGLExtensions::FramebufferMultisample;
} else {
extensions |= QOpenGLExtensions::ElementIndexUint | QOpenGLExtensions::MapBuffer;
// Recognize features by extension name.
if (format.majorVersion() >= 3
|| extensionMatcher.match("GL_ARB_framebuffer_object"))
{
if (format.version() >= qMakePair(1, 2))
extensions |= QOpenGLExtensions::BGRATextureFormat;
if (format.version() >= qMakePair(1, 4) || extensionMatcher.match("GL_SGIS_generate_mipmap"))
extensions |= QOpenGLExtensions::GenerateMipmap;
if (format.majorVersion() >= 3 || extensionMatcher.match("GL_ARB_framebuffer_object")) {
extensions |= QOpenGLExtensions::FramebufferMultisample |
QOpenGLExtensions::FramebufferBlit |
QOpenGLExtensions::PackedDepthStencil;
} else {
// Recognize features by extension name.
if (extensionMatcher.match("GL_EXT_framebuffer_multisample"))
extensions |= QOpenGLExtensions::FramebufferMultisample;
if (extensionMatcher.match("GL_EXT_framebuffer_blit"))
@ -430,21 +439,20 @@ static int qt_gl_resolve_extensions()
if (extensionMatcher.match("GL_EXT_packed_depth_stencil"))
extensions |= QOpenGLExtensions::PackedDepthStencil;
}
if (format.version() >= qMakePair(3, 2) || extensionMatcher.match("GL_ARB_geometry_shader4"))
extensions |= QOpenGLExtensions::GeometryShaders;
if (extensionMatcher.match("GL_ARB_map_buffer_range"))
extensions |= QOpenGLExtensions::MapBufferRange;
}
if (format.renderableType() == QSurfaceFormat::OpenGL && format.version() >= qMakePair(3, 2))
extensions |= QOpenGLExtensions::GeometryShaders;
#ifndef QT_OPENGL_ES
if (extensionMatcher.match("GL_EXT_framebuffer_sRGB")) {
GLboolean srgbCapableFramebuffers = false;
ctx->functions()->glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgbCapableFramebuffers);
if (srgbCapableFramebuffers)
extensions |= QOpenGLExtensions::SRGBFrameBuffer;
if (extensionMatcher.match("GL_EXT_framebuffer_sRGB")) {
GLboolean srgbCapableFramebuffers = false;
ctx->functions()->glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgbCapableFramebuffers);
if (srgbCapableFramebuffers)
extensions |= QOpenGLExtensions::SRGBFrameBuffer;
}
}
#endif
return extensions;
}

View File

@ -278,16 +278,27 @@ bool QOpenGLShaderPrivate::compile(QOpenGLShader *q)
"Fragment",
"Vertex",
"Geometry",
"Tessellation Control",
"Tessellation Evaluation",
"Compute",
""
};
const char *type = types[3];
if (shaderType == QOpenGLShader::Fragment)
type = types[0];
else if (shaderType == QOpenGLShader::Vertex)
type = types[1];
else if (shaderType == QOpenGLShader::Geometry)
type = types[2];
const char *type = types[6];
switch (shaderType) {
case QOpenGLShader::Fragment:
type = types[0]; break;
case QOpenGLShader::Vertex:
type = types[1]; break;
case QOpenGLShader::Geometry:
type = types[2]; break;
case QOpenGLShader::TessellationControl:
type = types[3]; break;
case QOpenGLShader::TessellationEvaluation:
type = types[4]; break;
case QOpenGLShader::Compute:
type = types[5]; break;
}
// Get info and source code lengths
GLint infoLogLength = 0;

View File

@ -248,9 +248,6 @@ bool QOpenGLTextureBlitter::create()
Q_D(QOpenGLTextureBlitter);
d->vao->create();
d->vao->bind();
if (d->program)
return true;
@ -273,6 +270,9 @@ bool QOpenGLTextureBlitter::create()
d->program->bind();
// Create and bind the VAO, if supported.
QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data());
d->vertexBuffer.create();
d->vertexBuffer.bind();
d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data));
@ -292,8 +292,6 @@ bool QOpenGLTextureBlitter::create()
d->program->setUniformValue(d->swizzleUniformPos,false);
d->vao->release();
return true;
}
@ -316,7 +314,8 @@ void QOpenGLTextureBlitter::bind()
{
Q_D(QOpenGLTextureBlitter);
d->vao->bind();
if (d->vao->isCreated())
d->vao->bind();
d->program->bind();
@ -335,7 +334,8 @@ void QOpenGLTextureBlitter::release()
{
Q_D(QOpenGLTextureBlitter);
d->program->release();
d->vao->release();
if (d->vao->isCreated())
d->vao->release();
}
void QOpenGLTextureBlitter::setSwizzleRB(bool swizzle)

View File

@ -164,6 +164,60 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
TexSubImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(GetProcAddress(handle, QByteArrayLiteral("glTexSubImage2D")));
TexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLenum , const GLvoid *)>(GetProcAddress(handle, QByteArrayLiteral("glTexSubImage1D")));
#elif defined(QT_OPENGL_ES_2)
// Here we are targeting OpenGL ES 2.0+ only. This is likely using EGL, where,
// similarly to WGL, non-extension functions (i.e. any function that is part of the
// GLES spec) *may* not be queried via eglGetProcAddress.
// OpenGL 1.0
GetIntegerv = ::glGetIntegerv;
GetBooleanv = ::glGetBooleanv;
PixelStorei = ::glPixelStorei;
GetTexLevelParameteriv = 0;
GetTexLevelParameterfv = 0;
GetTexParameteriv = ::glGetTexParameteriv;
GetTexParameterfv = ::glGetTexParameterfv;
GetTexImage = 0;
TexImage2D = ::glTexImage2D;
TexImage1D = 0;
TexParameteriv = ::glTexParameteriv;
TexParameteri = ::glTexParameteri;
TexParameterfv = ::glTexParameterfv;
TexParameterf = ::glTexParameterf;
// OpenGL 1.1
GenTextures = ::glGenTextures;
DeleteTextures = ::glDeleteTextures;
BindTexture = ::glBindTexture;
TexSubImage2D = ::glTexSubImage2D;
TexSubImage1D = 0;
// OpenGL 1.3
GetCompressedTexImage = 0;
CompressedTexSubImage1D = 0;
CompressedTexSubImage2D = ::glCompressedTexSubImage2D;
CompressedTexImage1D = 0;
CompressedTexImage2D = ::glCompressedTexImage2D;
ActiveTexture = ::glActiveTexture;
// OpenGL 3.0
GenerateMipmap = ::glGenerateMipmap;
// OpenGL 3.2
TexImage3DMultisample = 0;
TexImage2DMultisample = 0;
// OpenGL 4.2
TexStorage3D = 0;
TexStorage2D = 0;
TexStorage1D = 0;
// OpenGL 4.3
TexStorage3DMultisample = 0;
TexStorage2DMultisample = 0;
TexBufferRange = 0;
TextureView = 0;
#else
// OpenGL 1.0
@ -196,6 +250,13 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3DOES")));
CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3DOES")));
} else {
#ifdef QT_OPENGL_ES_3
// OpenGL ES 3.0+ has glTexImage3D.
TexImage3D = ::glTexImage3D;
TexSubImage3D = ::glTexSubImage3D;
CompressedTexImage3D = ::glCompressedTexImage3D;
CompressedTexSubImage3D = ::glCompressedTexSubImage3D;
#else
// OpenGL 1.2
TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexImage3D")));
TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3D")));
@ -203,8 +264,10 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
// OpenGL 1.3
CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3D")));
CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3D")));
#endif
}
#ifndef QT_OPENGL_ES_2
// OpenGL 1.3
GetCompressedTexImage = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glGetCompressedTexImage")));
CompressedTexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage1D")));
@ -230,6 +293,7 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
TexStorage2DMultisample = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLboolean )>(context->getProcAddress(QByteArrayLiteral("glTexStorage2DMultisample")));
TexBufferRange = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLenum , GLuint , GLintptr , GLsizeiptr )>(context->getProcAddress(QByteArrayLiteral("glTexBufferRange")));
TextureView = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint , GLenum , GLuint , GLuint , GLuint , GLuint )>(context->getProcAddress(QByteArrayLiteral("glTextureView")));
#endif
}
void QOpenGLTextureHelper::dsa_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param)

View File

@ -98,8 +98,10 @@ void QAbstractOpenGLFunctionsPrivate::removeFunctionsBackend(QOpenGLContext *con
Qt now provides a family of classes which all inherit from
QAbstractOpenGLFunctions which expose every core OpenGL function by way of a
corresponding member function. There is a class for every valid combination
of OpenGL version and profile. Each class follows the naming convention
QOpenGLFunctions_<MAJOR VERSION>_<MINOR VERSION>[_PROFILE].
of OpenGL version and profile. Each class follows the naming convention:
\badcode
QOpenGLFunctions_<MAJOR VERSION>_<MINOR VERSION>[_PROFILE]
\endcode
For OpenGL versions 1.0 through to 3.0 there are no profiles, leading to the
classes:

View File

@ -921,7 +921,7 @@ void QRasterPaintEngine::renderHintsChanged()
bool was_aa = s->flags.antialiased;
bool was_bilinear = s->flags.bilinear;
s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
s->flags.antialiased = bool(s->renderHints & (QPainter::Antialiasing | QPainter::HighQualityAntialiasing));
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
@ -2726,7 +2726,7 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
scanline += bpl;
}
} else { // 32-bit alpha...
uint *sl = (uint *) src;
uint *sl = (uint *) scanline;
for (int y = y0; y < y1; ++y) {
for (int x = x0; x < x1; ) {
// Skip those with 0 coverage

View File

@ -1106,6 +1106,11 @@ void QPainterPrivate::updateState(QPainterState *newState)
\li \inlineimage qpainter-pathstroking.png
\endtable
Text drawing is done using drawText(). When you need
fine-grained positioning, boundingRect() tells you where a given
drawText() command will draw.
\section1 Drawing Pixmaps and Images
There are functions to draw pixmaps/images, namely drawPixmap(),
drawImage() and drawTiledPixmap(). Both drawPixmap() and drawImage()
@ -1113,15 +1118,25 @@ void QPainterPrivate::updateState(QPainterState *newState)
on-screen while drawImage() may be faster on a QPrinter or other
devices.
Text drawing is done using drawText(). When you need
fine-grained positioning, boundingRect() tells you where a given
drawText() command will draw.
There is a drawPicture() function that draws the contents of an
entire QPicture. The drawPicture() function is the only function
that disregards all the painter's settings as QPicture has its own
settings.
\section2 Drawing High Resolution Versions of Pixmaps and Images
High resolution versions of pixmaps have a \e{device pixel ratio} value larger
than 1 (see QImageReader, QPixmap::devicePixelRatio()). Should it match the value
of the underlying QPaintDevice, it is drawn directly onto the device with no
additional transformation applied.
This is for example the case when drawing a QPixmap of 64x64 pixels size with
a device pixel ratio of 2 onto a high DPI screen which also has
a device pixel ratio of 2. Note that the pixmap is then effectively 32x32
pixels in \e{user space}. Code paths in Qt that calculate layout geometry
based on the pixmap size will use this size. The net effect of this is that
the pixmap is displayed as high DPI pixmap rather than a large pixmap.
\section1 Rendering Quality
To get the optimal rendering result using QPainter, you should use
@ -5024,6 +5039,8 @@ static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransfor
into the given \a target in the paint device.
\note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
\note See \l{Drawing High Resolution Versions of Pixmaps and Images} on how this is affected
by QPixmap::devicePixelRatio().
\table 100%
\row
@ -5038,7 +5055,7 @@ static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransfor
transparent. Drawing bitmaps with gradient or texture colors is
not supported.
\sa drawImage()
\sa drawImage(), QPixmap::devicePixelRatio()
*/
void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
{
@ -7694,6 +7711,8 @@ void QPainterState::init(QPainter *p) {
into the \a target rectangle in the paint device.
\note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
\note See \l{Drawing High Resolution Versions of Pixmaps and Images} on how this is affected
by QImage::devicePixelRatio().
If the image needs to be modified to fit in a lower-resolution
result (e.g. converting from 32-bit to 8-bit), use the \a flags to
@ -7705,7 +7724,7 @@ void QPainterState::init(QPainter *p) {
\snippet code/src_gui_painting_qpainter.cpp 20
\endtable
\sa drawPixmap()
\sa drawPixmap(), QImage::devicePixelRatio()
*/
/*!

View File

@ -62,6 +62,7 @@ public:
QPlatformBackingStorePrivate(QWindow *w)
: window(w)
#ifndef QT_NO_OPENGL
, textureId(0)
, blitter(0)
#endif
{
@ -276,7 +277,6 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(false);
}
funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
for (int i = 0; i < textures->count(); ++i) {
@ -287,6 +287,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
}
}
funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
funcs->glDisable(GL_BLEND);
d_ptr->blitter->release();

View File

@ -1072,28 +1072,12 @@ struct QRegionPrivate {
int innerArea;
inline QRegionPrivate() : numRects(0), innerArea(-1) {}
inline QRegionPrivate(const QRect &r) {
numRects = 1;
extents = r;
innerRect = r;
innerArea = r.width() * r.height();
}
inline QRegionPrivate(const QRegionPrivate &r) {
rects = r.rects;
numRects = r.numRects;
extents = r.extents;
innerRect = r.innerRect;
innerArea = r.innerArea;
}
inline QRegionPrivate &operator=(const QRegionPrivate &r) {
rects = r.rects;
numRects = r.numRects;
extents = r.extents;
innerRect = r.innerRect;
innerArea = r.innerArea;
return *this;
inline QRegionPrivate(const QRect &r)
: numRects(1),
extents(r),
innerRect(r),
innerArea(r.width() * r.height())
{
}
void intersect(const QRect &r);

View File

@ -826,7 +826,7 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
}
if (set && set->outline_drawing)
load_flags = FT_LOAD_NO_BITMAP;
load_flags |= FT_LOAD_NO_BITMAP;
if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
load_flags |= FT_LOAD_NO_HINTING;

View File

@ -401,6 +401,16 @@ QString QPlatformFontDatabase::fontDir() const
return fontpath;
}
/*!
Returns true if the font family is private. For any given family name,
the result is platform dependent.
*/
bool QPlatformFontDatabase::isPrivateFontFamily(const QString &family) const
{
Q_UNUSED(family);
return false;
}
/*!
Returns the default system font.

View File

@ -110,6 +110,7 @@ public:
virtual QString fontDir() const;
virtual QFont defaultFont() const;
virtual bool isPrivateFontFamily(const QString &family) const;
virtual QString resolveFontFamilyAlias(const QString &family) const;
virtual bool fontsAlwaysScalable() const;

View File

@ -2008,6 +2008,9 @@ static int qt_timeout_value(int msecs, int elapsed)
\note Multiple calls to this functions do not accumulate the time.
If the function times out, the connecting process will be aborted.
\note This function may fail randomly on Windows. Consider using the event
loop and the connected() signal if your software will run on Windows.
\sa connectToHost(), connected()
*/
bool QAbstractSocket::waitForConnected(int msecs)
@ -2107,6 +2110,9 @@ bool QAbstractSocket::waitForConnected(int msecs)
there is new data available for reading; otherwise it returns \c false
(if an error occurred or the operation timed out).
\note This function may fail randomly on Windows. Consider using the event
loop and the readyRead() signal if your software will run on Windows.
\sa waitForBytesWritten()
*/
bool QAbstractSocket::waitForReadyRead(int msecs)
@ -2166,6 +2172,20 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
}
/*! \reimp
This function blocks until at least one byte has been written on the socket
and the \l{QIODevice::}{bytesWritten()} signal has been emitted. The
function will timeout after \a msecs milliseconds; the default timeout is
30000 milliseconds.
The function returns \c true if the bytesWritten() signal is emitted;
otherwise it returns \c false (if an error occurred or the operation timed
out).
\note This function may fail randomly on Windows. Consider using the event
loop and the bytesWritten() signal if your software will run on Windows.
\sa waitForReadyRead()
*/
bool QAbstractSocket::waitForBytesWritten(int msecs)
{
@ -2247,6 +2267,9 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
If msecs is -1, this function will not time out.
\note This function may fail randomly on Windows. Consider using the event
loop and the disconnected() signal if your software will run on Windows.
\sa disconnectFromHost(), close()
*/
bool QAbstractSocket::waitForDisconnected(int msecs)

View File

@ -51,8 +51,14 @@
#include <qelapsedtimer.h>
#include <qthread.h>
#include <qabstracteventdispatcher.h>
#include <qfunctions_winrt.h>
#include <private/qeventdispatcher_winrt_p.h>
#include <private/qthread_p.h>
#include <private/qabstractsocket_p.h>
#ifndef QT_NO_SSL
#include <QSslSocket>
#endif
#include <wrl.h>
#include <windows.foundation.collections.h>
@ -124,6 +130,20 @@ struct SocketHandler
Q_GLOBAL_STATIC(SocketHandler, gSocketHandler)
struct SocketGlobal
{
SocketGlobal()
{
HRESULT hr;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
&bufferFactory);
Q_ASSERT_SUCCEEDED(hr);
}
ComPtr<IBufferFactory> bufferFactory;
};
Q_GLOBAL_STATIC(SocketGlobal, g)
static inline QString qt_QStringFromHString(const HString &string)
{
UINT32 length;
@ -131,60 +151,7 @@ static inline QString qt_QStringFromHString(const HString &string)
return QString::fromWCharArray(rawString, length);
}
#define READ_BUFFER_SIZE 8192
class ByteArrayBuffer : public Microsoft::WRL::RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>,
IBuffer, Windows::Storage::Streams::IBufferByteAccess>
{
public:
ByteArrayBuffer(int size) : m_bytes(size, Qt::Uninitialized), m_length(0)
{
}
ByteArrayBuffer(const char *data, int size) : m_bytes(data, size), m_length(size)
{
}
HRESULT __stdcall Buffer(byte **value)
{
*value = reinterpret_cast<byte *>(m_bytes.data());
return S_OK;
}
HRESULT __stdcall get_Capacity(UINT32 *value)
{
*value = m_bytes.size();
return S_OK;
}
HRESULT __stdcall get_Length(UINT32 *value)
{
*value = m_length;
return S_OK;
}
HRESULT __stdcall put_Length(UINT32 value)
{
Q_ASSERT(value <= UINT32(m_bytes.size()));
m_length = value;
return S_OK;
}
ComPtr<IInputStream> inputStream() const
{
return m_stream;
}
void setInputStream(ComPtr<IInputStream> stream)
{
m_stream = stream;
}
private:
QByteArray m_bytes;
UINT32 m_length;
ComPtr<IInputStream> m_stream;
};
#define READ_BUFFER_SIZE 65536
template <typename T>
static AsyncStatus opStatus(const ComPtr<T> &op)
@ -207,6 +174,14 @@ static AsyncStatus opStatus(const ComPtr<T> &op)
QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
: QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent)
{
#ifndef QT_NO_SSL
Q_D(QNativeSocketEngine);
Q_ASSERT(parent);
d->sslSocket = qobject_cast<QSslSocket *>(parent->parent());
#else
d->sslSocket = Q_NULLPTR;
#endif
connect(this, SIGNAL(connectionReady()), SLOT(connectionNotification()), Qt::QueuedConnection);
connect(this, SIGNAL(readReady()), SLOT(readNotification()), Qt::QueuedConnection);
connect(this, SIGNAL(writeReady()), SLOT(writeNotification()), Qt::QueuedConnection);
@ -239,16 +214,14 @@ bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::
if (isValid())
close();
d->socketDescriptor = socketDescriptor;
// Currently, only TCP sockets are initialized this way.
SocketHandler *handler = gSocketHandler();
d->tcp = handler->pendingTcpSockets.take(socketDescriptor);
d->socketDescriptor = qintptr(gSocketHandler->pendingTcpSockets.take(socketDescriptor));
d->socketType = QAbstractSocket::TcpSocket;
if (!d->tcp || !d->fetchConnectionParameters()) {
if (!d->socketDescriptor || !d->fetchConnectionParameters()) {
d->setError(QAbstractSocket::UnsupportedSocketOperationError,
d->InvalidSocketErrorString);
d->socketDescriptor = -1;
return false;
}
@ -287,68 +260,23 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
return false;
}
ComPtr<IAsyncAction> op;
const QString portString = QString::number(port);
HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
HRESULT hr = E_FAIL;
if (d->socketType == QAbstractSocket::TcpSocket)
hr = d->tcp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op);
hr = d->tcpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
else if (d->socketType == QAbstractSocket::UdpSocket)
hr = d->udp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op);
hr = d->udpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
if (FAILED(hr)) {
qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not obtain connect action");
return false;
}
hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(
d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
if (FAILED(hr)) {
qErrnoWarning(hr, "Unable to set host connection callback.");
return false;
}
d->socketState = QAbstractSocket::ConnectingState;
while (opStatus(op) == Started)
d->eventLoop.processEvents();
hr = d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
Q_ASSERT_SUCCEEDED(hr);
AsyncStatus status = opStatus(op);
if (status == Error || status == Canceled)
return false;
if (hr == 0x8007274c) { // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
d->setError(QAbstractSocket::NetworkError, d->ConnectionTimeOutErrorString);
d->socketState = QAbstractSocket::UnconnectedState;
return false;
}
if (hr == 0x8007274d) { // No connection could be made because the target machine actively refused it.
d->setError(QAbstractSocket::ConnectionRefusedError, d->ConnectionRefusedErrorString);
d->socketState = QAbstractSocket::UnconnectedState;
return false;
}
if (FAILED(hr)) {
d->setError(QAbstractSocket::UnknownSocketError, d->UnknownSocketErrorString);
d->socketState = QAbstractSocket::UnconnectedState;
return false;
}
if (d->socketType == QAbstractSocket::TcpSocket) {
IInputStream *stream;
hr = d->tcp->get_InputStream(&stream);
if (FAILED(hr))
return false;
ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->readBuffer.Get());
buffer->setInputStream(stream);
ComPtr<IAsyncBufferOperation> op;
hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
if (FAILED(hr))
return false;
hr = op->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to set socket read callback.");
return false;
}
}
d->socketState = QAbstractSocket::ConnectedState;
return true;
return d->socketState == QAbstractSocket::ConnectedState;
}
bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
@ -385,7 +313,7 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
return false;
}
} else if (d->socketType == QAbstractSocket::UdpSocket) {
hr = d->udp->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
hr = d->udpSocket()->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message
return false;
@ -447,13 +375,16 @@ int QNativeSocketEngine::accept()
if (d->socketType == QAbstractSocket::TcpSocket) {
IStreamSocket *socket = d->pendingConnections.takeFirst();
IInputStream *stream;
socket->get_InputStream(&stream);
// TODO: delete buffer and stream on socket close
ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->readBuffer.Get());
buffer->setInputStream(stream);
HRESULT hr;
ComPtr<IBuffer> buffer;
hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IInputStream> stream;
hr = socket->get_InputStream(&stream);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsyncBufferOperation> op;
HRESULT hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Faild to read from the socket buffer.");
return -1;
@ -476,12 +407,25 @@ int QNativeSocketEngine::accept()
void QNativeSocketEngine::close()
{
Q_D(QNativeSocketEngine);
if (d->connectOp) {
ComPtr<IAsyncInfo> info;
d->connectOp.As(&info);
if (info) {
info->Cancel();
info->Close();
}
}
if (d->socketDescriptor != -1) {
ComPtr<IClosable> socket;
if (d->socketType == QAbstractSocket::TcpSocket && d->tcp)
d->tcp.As(&socket);
else if (d->socketType == QAbstractSocket::UdpSocket && d->udp)
d->udp.As(&socket);
if (d->socketType == QAbstractSocket::TcpSocket) {
d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
d->tcpSocket()->Release();
} else if (d->socketType == QAbstractSocket::UdpSocket) {
d->udpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
d->udpSocket()->Release();
}
if (socket) {
d->closingDown = true;
@ -549,42 +493,40 @@ qint64 QNativeSocketEngine::read(char *data, qint64 maxlen)
qint64 QNativeSocketEngine::write(const char *data, qint64 len)
{
Q_D(QNativeSocketEngine);
if (!isValid())
return -1;
HRESULT hr = E_FAIL;
ComPtr<IOutputStream> stream;
if (d->socketType == QAbstractSocket::TcpSocket)
hr = d->tcp->get_OutputStream(&stream);
hr = d->tcpSocket()->get_OutputStream(&stream);
else if (d->socketType == QAbstractSocket::UdpSocket)
hr = d->udp->get_OutputStream(&stream);
hr = d->udpSocket()->get_OutputStream(&stream);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get output stream to socket.");
return -1;
}
ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(data, len);
ComPtr<IBuffer> buffer;
hr = g->bufferFactory->Create(len, &buffer);
Q_ASSERT_SUCCEEDED(hr);
hr = buffer->put_Length(len);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
hr = buffer.As(&byteArrayAccess);
Q_ASSERT_SUCCEEDED(hr);
byte *bytes;
hr = byteArrayAccess->Buffer(&bytes);
Q_ASSERT_SUCCEEDED(hr);
memcpy(bytes, data, len);
ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
hr = stream->WriteAsync(buffer.Get(), &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to write to socket.");
return -1;
}
hr = op->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<UINT32, UINT32>>(
d, &QNativeSocketEnginePrivate::handleWriteCompleted).Get());
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to set socket write callback.");
return -1;
}
while (opStatus(op) == Started)
d->eventLoop.processEvents();
AsyncStatus status = opStatus(op);
if (status == Error || status == Canceled)
return -1;
RETURN_IF_FAILED("Failed to write to stream", return -1);
UINT32 bytesWritten;
hr = op->GetResults(&bytesWritten);
hr = QWinRTFunctions::await(op, &bytesWritten);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get written socket length.");
d->setError(QAbstractSocket::SocketAccessError, QNativeSocketEnginePrivate::AccessErrorString);
return -1;
}
@ -655,7 +597,7 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QH
ComPtr<IOutputStream> stream;
const QString portString = QString::number(port);
HStringReference portRef(reinterpret_cast<LPCWSTR>(portString.utf16()));
if (FAILED(d->udp->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation)))
if (FAILED(d->udpSocket()->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation)))
return -1;
HRESULT hr;
while (hr = streamOperation->GetResults(&stream) == E_ILLEGAL_METHOD_CALL)
@ -825,29 +767,50 @@ void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
d->notifyOnException = enable;
}
void QNativeSocketEngine::establishRead()
{
Q_D(QNativeSocketEngine);
HRESULT hr;
ComPtr<IInputStream> stream;
hr = d->tcpSocket()->get_InputStream(&stream);
RETURN_VOID_IF_FAILED("Failed to get socket input stream");
ComPtr<IBuffer> buffer;
hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsyncBufferOperation> op;
hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
RETURN_VOID_IF_FAILED("Failed to initiate socket read");
hr = op->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
Q_ASSERT_SUCCEEDED(hr);
}
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{
Q_UNUSED(socketProtocol);
SocketHandler *handler = gSocketHandler();
switch (socketType) {
case QAbstractSocket::TcpSocket: {
HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &tcp);
ComPtr<IStreamSocket> socket;
HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &socket);
if (FAILED(hr)) {
qWarning("Failed to create StreamSocket instance");
return false;
}
socketDescriptor = ++handler->socketCount;
socketDescriptor = qintptr(socket.Detach());
return true;
}
case QAbstractSocket::UdpSocket: {
HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &udp);
ComPtr<IDatagramSocket> socket;
HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &socket);
if (FAILED(hr)) {
qWarning("Failed to create stream socket");
return false;
}
EventRegistrationToken token;
udp->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
socketDescriptor = ++handler->socketCount;
udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
socketDescriptor = qintptr(socket.Detach());
return true;
}
default:
@ -865,8 +828,6 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate()
, closingDown(false)
, socketDescriptor(-1)
{
ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(READ_BUFFER_SIZE);
readBuffer = buffer;
}
QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
@ -980,7 +941,7 @@ int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt)
{
ComPtr<IStreamSocketControl> control;
if (socketType == QAbstractSocket::TcpSocket) {
if (FAILED(tcp->get_Control(&control))) {
if (FAILED(tcpSocket()->get_Control(&control))) {
qWarning("QNativeSocketEnginePrivate::option: Could not obtain socket control");
return -1;
}
@ -1036,7 +997,7 @@ bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption o
{
ComPtr<IStreamSocketControl> control;
if (socketType == QAbstractSocket::TcpSocket) {
if (FAILED(tcp->get_Control(&control))) {
if (FAILED(tcpSocket()->get_Control(&control))) {
qWarning("QNativeSocketEnginePrivate::setOption: Could not obtain socket control");
return false;
}
@ -1100,7 +1061,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
ComPtr<IHostName> hostName;
HString tmpHString;
ComPtr<IStreamSocketInformation> info;
if (FAILED(tcp->get_Information(&info))) {
if (FAILED(tcpSocket()->get_Information(&info))) {
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket info");
return false;
}
@ -1129,7 +1090,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
ComPtr<IHostName> hostName;
HString tmpHString;
ComPtr<IDatagramSocketInformation> info;
if (FAILED(udp->get_Information(&info))) {
if (FAILED(udpSocket()->get_Information(&info))) {
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket information");
return false;
}
@ -1169,8 +1130,46 @@ HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener
return S_OK;
}
HRESULT QNativeSocketEnginePrivate::handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus)
HRESULT QNativeSocketEnginePrivate::handleConnectToHost(IAsyncAction *action, AsyncStatus)
{
Q_Q(QNativeSocketEngine);
HRESULT hr = action->GetResults();
if (wasDeleted || !connectOp) // Protect against a late callback
return S_OK;
connectOp.Reset();
switch (hr) {
case 0x8007274c: // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
socketState = QAbstractSocket::UnconnectedState;
return S_OK;
case 0x80072751: // A socket operation was attempted to an unreachable host.
setError(QAbstractSocket::HostNotFoundError, HostUnreachableErrorString);
socketState = QAbstractSocket::UnconnectedState;
return S_OK;
case 0x8007274d: // No connection could be made because the target machine actively refused it.
setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
socketState = QAbstractSocket::UnconnectedState;
return S_OK;
default:
if (FAILED(hr)) {
setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
socketState = QAbstractSocket::UnconnectedState;
return S_OK;
}
break;
}
socketState = QAbstractSocket::ConnectedState;
emit q->connectionReady();
// Delay the reader so that the SSL socket can upgrade
if (sslSocket)
q->connect(sslSocket, SIGNAL(encrypted()), SLOT(establishRead()));
else
q->establishRead();
return S_OK;
}
@ -1183,22 +1182,25 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
if (status == Error || status == Canceled)
return S_OK;
ByteArrayBuffer *buffer = 0;
HRESULT hr = asyncInfo->GetResults((IBuffer **)&buffer);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get ready read results.");
return S_OK;
}
UINT32 len;
buffer->get_Length(&len);
if (!len) {
ComPtr<IBuffer> buffer;
HRESULT hr = asyncInfo->GetResults(&buffer);
RETURN_OK_IF_FAILED("Failed to get read results buffer");
UINT32 bufferLength;
hr = buffer->get_Length(&bufferLength);
Q_ASSERT_SUCCEEDED(hr);
if (!bufferLength) {
if (q->isReadNotificationEnabled())
emit q->readReady();
return S_OK;
}
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
hr = buffer.As(&byteArrayAccess);
Q_ASSERT_SUCCEEDED(hr);
byte *data;
buffer->Buffer(&data);
hr = byteArrayAccess->Buffer(&data);
Q_ASSERT_SUCCEEDED(hr);
readMutex.lock();
if (readBytes.atEnd()) // Everything has been read; the buffer is safe to reset
@ -1208,15 +1210,25 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
qint64 readPos = readBytes.pos();
readBytes.seek(readBytes.size());
Q_ASSERT(readBytes.atEnd());
readBytes.write(reinterpret_cast<const char*>(data), qint64(len));
readBytes.write(reinterpret_cast<const char*>(data), qint64(bufferLength));
readBytes.seek(readPos);
readMutex.unlock();
if (q->isReadNotificationEnabled())
emit q->readReady();
ComPtr<IInputStream> stream;
hr = tcpSocket()->get_InputStream(&stream);
Q_ASSERT_SUCCEEDED(hr);
// Reuse the stream buffer
hr = buffer->get_Capacity(&bufferLength);
Q_ASSERT_SUCCEEDED(hr);
hr = buffer->put_Length(0);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsyncBufferOperation> op;
hr = buffer->inputStream()->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
hr = stream->ReadAsync(buffer.Get(), bufferLength, InputStreamOptions_Partial, &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Could not read into socket stream buffer.");
return S_OK;
@ -1229,28 +1241,6 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
return S_OK;
}
HRESULT QNativeSocketEnginePrivate::handleWriteCompleted(IAsyncOperationWithProgress<UINT32, UINT32> *op, AsyncStatus status)
{
if (status == Error) {
ComPtr<IAsyncInfo> info;
HRESULT hr = op->QueryInterface(IID_PPV_ARGS(&info));
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to cast operation.");
return S_OK;
}
HRESULT errorCode;
hr = info->get_ErrorCode(&errorCode);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get error code.");
return S_OK;
}
qErrnoWarning(errorCode, "A socket error occurred.");
return S_OK;
}
return S_OK;
}
HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, IDatagramSocketMessageReceivedEventArgs *args)
{
Q_Q(QNativeSocketEngine);

View File

@ -134,6 +134,9 @@ signals:
void readReady();
void writeReady();
private slots:
void establishRead();
private:
Q_DECLARE_PRIVATE(QNativeSocketEngine)
Q_DISABLE_COPY(QNativeSocketEngine)
@ -192,17 +195,21 @@ public:
bool checkProxy(const QHostAddress &address);
bool fetchConnectionParameters();
private:
Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> tcp;
Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IDatagramSocket> udp;
inline ABI::Windows::Networking::Sockets::IStreamSocket *tcpSocket() const
{ return reinterpret_cast<ABI::Windows::Networking::Sockets::IStreamSocket *>(socketDescriptor); }
inline ABI::Windows::Networking::Sockets::IDatagramSocket *udpSocket() const
{ return reinterpret_cast<ABI::Windows::Networking::Sockets::IDatagramSocket *>(socketDescriptor); }
Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> tcpListener;
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> readBuffer;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> connectOp;
QBuffer readBytes;
QMutex readMutex;
QList<ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *> pendingDatagrams;
QList<ABI::Windows::Networking::Sockets::IStreamSocket *> pendingConnections;
QList<ABI::Windows::Networking::Sockets::IStreamSocket *> currentConnections;
QEventLoop eventLoop;
QAbstractSocket *sslSocket;
HRESULT handleBindCompleted(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus);
HRESULT handleNewDatagram(ABI::Windows::Networking::Sockets::IDatagramSocket *socket,
@ -211,7 +218,6 @@ private:
ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args);
HRESULT handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus);
HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32> *asyncInfo, ABI::Windows::Foundation::AsyncStatus);
HRESULT handleWriteCompleted(ABI::Windows::Foundation::IAsyncOperationWithProgress<UINT32, UINT32> *, ABI::Windows::Foundation::AsyncStatus);
};
QT_END_NAMESPACE

View File

@ -0,0 +1,291 @@
/****************************************************************************
**
** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qasn1element_p.h"
#include <QtCore/qdatastream.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qvector.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
typedef QMap<QByteArray, QByteArray> OidNameMap;
static OidNameMap createOidMap()
{
OidNameMap oids;
// used by unit tests
oids.insert(oids.end(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink"));
oids.insert(oids.end(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST"));
oids.insert(oids.end(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street"));
return oids;
}
Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap()))
QAsn1Element::QAsn1Element(quint8 type, const QByteArray &value)
: mType(type)
, mValue(value)
{
}
bool QAsn1Element::read(QDataStream &stream)
{
// type
quint8 tmpType;
stream >> tmpType;
if (!tmpType)
return false;
// length
qint64 length = 0;
quint8 first;
stream >> first;
if (first & 0x80) {
// long form
const quint8 bytes = (first & 0x7f);
if (bytes > 7)
return false;
quint8 b;
for (int i = 0; i < bytes; i++) {
stream >> b;
length = (length << 8) | b;
}
} else {
// short form
length = (first & 0x7f);
}
// value
QByteArray tmpValue;
tmpValue.resize(length);
int count = stream.readRawData(tmpValue.data(), tmpValue.size());
if (count != length)
return false;
mType = tmpType;
mValue.swap(tmpValue);
return true;
}
bool QAsn1Element::read(const QByteArray &data)
{
QDataStream stream(data);
return read(stream);
}
void QAsn1Element::write(QDataStream &stream) const
{
// type
stream << mType;
// length
qint64 length = mValue.size();
if (length >= 128) {
// long form
quint8 encodedLength = 0x80;
QByteArray ba;
while (length) {
ba.prepend(quint8((length & 0xff)));
length >>= 8;
encodedLength += 1;
}
stream << encodedLength;
stream.writeRawData(ba.data(), ba.size());
} else {
// short form
stream << quint8(length);
}
// value
stream.writeRawData(mValue.data(), mValue.size());
}
QAsn1Element QAsn1Element::fromInteger(unsigned int val)
{
QAsn1Element elem(QAsn1Element::IntegerType);
while (val > 127) {
elem.mValue.prepend(val & 0xff);
val >>= 8;
}
elem.mValue.prepend(val & 0x7f);
return elem;
}
QAsn1Element QAsn1Element::fromVector(const QVector<QAsn1Element> &items)
{
QAsn1Element seq;
seq.mType = SequenceType;
QDataStream stream(&seq.mValue, QIODevice::WriteOnly);
for (QVector<QAsn1Element>::const_iterator it = items.cbegin(), end = items.cend(); it != end; ++it)
it->write(stream);
return seq;
}
QAsn1Element QAsn1Element::fromObjectId(const QByteArray &id)
{
QAsn1Element elem;
elem.mType = ObjectIdentifierType;
QList<QByteArray> bits = id.split('.');
Q_ASSERT(bits.size() > 2);
elem.mValue += quint8((bits[0].toUInt() * 40 + bits[1].toUInt()));
for (int i = 2; i < bits.size(); ++i) {
char buffer[std::numeric_limits<unsigned int>::digits / 7 + 2];
char *pBuffer = buffer + sizeof(buffer);
*--pBuffer = '\0';
unsigned int node = bits[i].toUInt();
*--pBuffer = quint8((node & 0x7f));
node >>= 7;
while (node) {
*--pBuffer = quint8(((node & 0x7f) | 0x80));
node >>= 7;
}
elem.mValue += pBuffer;
}
return elem;
}
QDateTime QAsn1Element::toDateTime() const
{
if (mValue.endsWith('Z')) {
if (mType == UtcTimeType && mValue.size() == 13)
return QDateTime(QDate(2000 + mValue.mid(0, 2).toInt(),
mValue.mid(2, 2).toInt(),
mValue.mid(4, 2).toInt()),
QTime(mValue.mid(6, 2).toInt(),
mValue.mid(8, 2).toInt(),
mValue.mid(10, 2).toInt()),
Qt::UTC);
else if (mType == GeneralizedTimeType && mValue.size() == 15)
return QDateTime(QDate(mValue.mid(0, 4).toInt(),
mValue.mid(4, 2).toInt(),
mValue.mid(6, 2).toInt()),
QTime(mValue.mid(8, 2).toInt(),
mValue.mid(10, 2).toInt(),
mValue.mid(12, 2).toInt()),
Qt::UTC);
}
return QDateTime();
}
QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
{
QMultiMap<QByteArray, QString> info;
QAsn1Element elem;
QDataStream issuerStream(mValue);
while (elem.read(issuerStream) && elem.mType == QAsn1Element::SetType) {
QAsn1Element issuerElem;
QDataStream setStream(elem.mValue);
if (issuerElem.read(setStream) && issuerElem.mType == QAsn1Element::SequenceType) {
QVector<QAsn1Element> elems = issuerElem.toVector();
if (elems.size() == 2) {
const QByteArray key = elems.front().toObjectName();
if (!key.isEmpty())
info.insert(key, elems.back().toString());
}
}
}
return info;
}
QVector<QAsn1Element> QAsn1Element::toVector() const
{
QVector<QAsn1Element> items;
if (mType == SequenceType) {
QAsn1Element elem;
QDataStream stream(mValue);
while (elem.read(stream))
items << elem;
}
return items;
}
QByteArray QAsn1Element::toObjectId() const
{
QByteArray key;
if (mType == ObjectIdentifierType && !mValue.isEmpty()) {
quint8 b = mValue[0];
key += QByteArray::number(b / 40) + '.' + QByteArray::number (b % 40);
unsigned int val = 0;
for (int i = 1; i < mValue.size(); ++i) {
b = mValue[i];
val = (val << 7) | (b & 0x7f);
if (!(b & 0x80)) {
key += '.' + QByteArray::number(val);
val = 0;
}
}
}
return key;
}
QByteArray QAsn1Element::toObjectName() const
{
QByteArray key = toObjectId();
return oidNameMap->value(key, key);
}
QString QAsn1Element::toString() const
{
if (mType == PrintableStringType || mType == TeletexStringType)
return QString::fromLatin1(mValue, mValue.size());
if (mType == Utf8StringType)
return QString::fromUtf8(mValue, mValue.size());
return QString();
}
QT_END_NAMESPACE

View File

@ -1,9 +1,9 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@ -39,54 +39,78 @@
**
****************************************************************************/
#ifndef QPLATFORMSCREENPAGEFLIPPER_H
#define QPLATFORMSCREENPAGEFLIPPER_H
#ifndef QASN1ELEMENT_P_H
#define QASN1ELEMENT_P_H
//
// W A R N I N G
// -------------
//
// This file is part of the QPA API and is not meant to be used
// in applications. Usage of this API may make your code
// source and binary incompatible with future versions of Qt.
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/QObject>
#include <QtCore/qdatetime.h>
#include <QtCore/qmap.h>
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QPlatformScreenBuffer {
public:
QPlatformScreenBuffer();
virtual ~QPlatformScreenBuffer();
bool isDestroyed() const;
bool isReady() const;
virtual void aboutToBeDisplayed();
virtual void displayed();
virtual void release() = 0;
virtual void *handle() const = 0;
protected:
bool m_destroyed;
bool m_ready;
};
class Q_GUI_EXPORT QPlatformScreenPageFlipper : public QObject
class Q_AUTOTEST_EXPORT QAsn1Element
{
Q_OBJECT
public:
explicit QPlatformScreenPageFlipper(QObject *parent = 0);
enum ElementType {
// universal
IntegerType = 0x02,
BitStringType = 0x03,
OctetStringType = 0x04,
NullType = 0x05,
ObjectIdentifierType = 0x06,
Utf8StringType = 0x0c,
PrintableStringType = 0x13,
TeletexStringType = 0x14,
UtcTimeType = 0x17,
GeneralizedTimeType = 0x18,
SequenceType = 0x30,
SetType = 0x31,
virtual bool displayBuffer(QPlatformScreenBuffer *) = 0;
// application
Rfc822NameType = 0x81,
DnsNameType = 0x82,
Q_SIGNALS:
void bufferDisplayed(QPlatformScreenBuffer *);
void bufferReleased(QPlatformScreenBuffer *);
// context specific
Context0Type = 0xA0,
Context3Type = 0xA3
};
explicit QAsn1Element(quint8 type = 0, const QByteArray &value = QByteArray());
bool read(QDataStream &data);
bool read(const QByteArray &data);
void write(QDataStream &data) const;
static QAsn1Element fromInteger(unsigned int val);
static QAsn1Element fromVector(const QVector<QAsn1Element> &items);
static QAsn1Element fromObjectId(const QByteArray &id);
QDateTime toDateTime() const;
QMultiMap<QByteArray, QString> toInfo() const;
QVector<QAsn1Element> toVector() const;
QByteArray toObjectId() const;
QByteArray toObjectName() const;
QString toString() const;
quint8 type() const { return mType; }
QByteArray value() const { return mValue; }
private:
quint8 mType;
QByteArray mValue;
};
Q_DECLARE_TYPEINFO(QAsn1Element, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // QPLATFORMSCREENPAGEFLIPPER_H
#endif

View File

@ -122,6 +122,7 @@
#include "qsslcertificate.h"
#include "qsslcertificate_p.h"
#include "qasn1element_p.h"
#include "qsslkey_p.h"
#include <QtCore/qdir.h>
@ -641,6 +642,155 @@ static const char *certificate_blacklist[] = {
0
};
bool QSslCertificatePrivate::parse(const QByteArray &data)
{
#ifndef QT_NO_OPENSSL
Q_UNUSED(data);
#else
QAsn1Element root;
QDataStream dataStream(data);
if (!root.read(dataStream) || root.type() != QAsn1Element::SequenceType)
return false;
QDataStream rootStream(root.value());
QAsn1Element cert;
if (!cert.read(rootStream) || cert.type() != QAsn1Element::SequenceType)
return false;
// version or serial number
QAsn1Element elem;
QDataStream certStream(cert.value());
if (!elem.read(certStream))
return false;
if (elem.type() == QAsn1Element::Context0Type) {
QDataStream versionStream(elem.value());
if (!elem.read(versionStream) || elem.type() != QAsn1Element::IntegerType)
return false;
versionString = QByteArray::number(elem.value()[0] + 1);
if (!elem.read(certStream))
return false;
} else {
versionString = QByteArray::number(1);
}
// serial number
if (elem.type() != QAsn1Element::IntegerType)
return false;
QByteArray hexString;
hexString.reserve(elem.value().size() * 3);
for (int a = 0; a < elem.value().size(); ++a) {
const quint8 b = elem.value().at(a);
if (b || !hexString.isEmpty()) { // skip leading zeros
hexString += QByteArray::number(b, 16).rightJustified(2, '0');
hexString += ':';
}
}
hexString.chop(1);
serialNumberString = hexString;
// algorithm ID
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
return false;
//qDebug() << "algorithm ID" << elem.type() << elem.length << elem.value().toHex();
// issuer info
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
return false;
QByteArray issuerDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
issuerInfo = elem.toInfo();
// validity period
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
return false;
QDataStream validityStream(elem.value());
if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
return false;
notValidBefore = elem.toDateTime();
if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
return false;
notValidAfter = elem.toDateTime();
// subject name
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
return false;
QByteArray subjectDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
subjectInfo = elem.toInfo();
subjectMatchesIssuer = issuerDer == subjectDer;
// public key
qint64 keyStart = certStream.device()->pos();
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
return false;
publicKeyDerData.resize(certStream.device()->pos() - keyStart);
QDataStream keyStream(elem.value());
if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
return false;
// key algorithm
if (!elem.read(elem.value()) || elem.type() != QAsn1Element::ObjectIdentifierType)
return false;
const QByteArray oid = elem.toObjectId();
if (oid == "1.2.840.113549.1.1.1")
publicKeyAlgorithm = QSsl::Rsa;
else if (oid == "1.2.840.10040.4.1")
publicKeyAlgorithm = QSsl::Dsa;
else
publicKeyAlgorithm = QSsl::Opaque;
certStream.device()->seek(keyStart);
certStream.readRawData(publicKeyDerData.data(), publicKeyDerData.size());
// extensions
while (elem.read(certStream)) {
if (elem.type() == QAsn1Element::Context3Type) {
if (elem.read(elem.value()) && elem.type() == QAsn1Element::SequenceType) {
QDataStream extStream(elem.value());
while (elem.read(extStream) && elem.type() == QAsn1Element::SequenceType) {
QAsn1Element oidElem, valElem;
QDataStream seqStream(elem.value());
if (oidElem.read(seqStream) && oidElem.type() == QAsn1Element::ObjectIdentifierType &&
valElem.read(seqStream) && valElem.type() == QAsn1Element::OctetStringType) {
// alternative name
if (oidElem.toObjectId() == QByteArray("2.5.29.17")) {
QAsn1Element sanElem;
if (sanElem.read(valElem.value()) && sanElem.type() == QAsn1Element::SequenceType) {
QDataStream nameStream(sanElem.value());
QAsn1Element nameElem;
while (nameElem.read(nameStream)) {
if (nameElem.type() == QAsn1Element::Rfc822NameType) {
subjectAlternativeNames.insert(QSsl::EmailEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
} else if (nameElem.type() == QAsn1Element::DnsNameType) {
subjectAlternativeNames.insert(QSsl::DnsEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
}
}
}
}
}
}
}
}
}
derData = data.left(dataStream.device()->pos());
null = false;
#endif // QT_NO_OPENSSL
return true;
}
bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
{
for (int a = 0; certificate_blacklist[a] != 0; a++) {

View File

@ -69,6 +69,11 @@ struct X509_EXTENSION;
struct ASN1_OBJECT;
#endif
#ifdef Q_OS_WINRT
#include <wrl.h>
#include <windows.security.cryptography.certificates.h>
#endif
QT_BEGIN_NAMESPACE
// forward declaration
@ -99,9 +104,18 @@ public:
QDateTime notValidAfter;
QDateTime notValidBefore;
#ifdef QT_NO_OPENSSL
bool subjectMatchesIssuer;
QSsl::KeyAlgorithm publicKeyAlgorithm;
QByteArray publicKeyDerData;
QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames;
QByteArray derData;
#endif
X509 *x509;
void init(const QByteArray &data, QSsl::EncodingFormat format);
bool parse(const QByteArray &data);
static QByteArray asn1ObjectId(ASN1_OBJECT *object);
static QByteArray asn1ObjectName(ASN1_OBJECT *object);
@ -117,6 +131,12 @@ public:
friend class QSslSocketBackendPrivate;
QAtomicInt ref;
#ifdef Q_OS_WINRT
Microsoft::WRL::ComPtr<ABI::Windows::Security::Cryptography::Certificates::ICertificate> certificate;
static QSslCertificate QSslCertificate_from_Certificate(ABI::Windows::Security::Cryptography::Certificates::ICertificate *iCertificate);
#endif
};
QT_END_NAMESPACE

View File

@ -0,0 +1,266 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsslcertificate.h"
#include "qsslcertificate_p.h"
#include "qsslkey.h"
#include "qsslkey_p.h"
#include "qsslcertificateextension.h"
#include "qsslcertificateextension_p.h"
QT_BEGIN_NAMESPACE
bool QSslCertificate::operator==(const QSslCertificate &other) const
{
if (d == other.d)
return true;
if (d->null && other.d->null)
return true;
return d->derData == other.d->derData;
}
bool QSslCertificate::isNull() const
{
return d->null;
}
bool QSslCertificate::isSelfSigned() const
{
if (d->null)
return false;
qWarning("QSslCertificate::isSelfSigned: This function does not check, whether the certificate \
is actually signed. It just checks whether issuer and subject are identical");
return d->subjectMatchesIssuer;
}
QByteArray QSslCertificate::version() const
{
return d->versionString;
}
QByteArray QSslCertificate::serialNumber() const
{
return d->serialNumberString;
}
QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
{
return issuerInfo(QSslCertificatePrivate::subjectInfoToString(info));
}
QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
{
return d->issuerInfo.values(attribute);
}
QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
{
return subjectInfo(QSslCertificatePrivate::subjectInfoToString(info));
}
QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
{
return d->subjectInfo.values(attribute);
}
QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
{
return d->subjectInfo.uniqueKeys();
}
QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
{
return d->issuerInfo.uniqueKeys();
}
QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
{
return d->subjectAlternativeNames;
}
QDateTime QSslCertificate::effectiveDate() const
{
return d->notValidBefore;
}
QDateTime QSslCertificate::expiryDate() const
{
return d->notValidAfter;
}
#ifndef Q_OS_WINRT // implemented in qsslcertificate_winrt.cpp
Qt::HANDLE QSslCertificate::handle() const
{
Q_UNIMPLEMENTED();
return 0;
}
#endif
QSslKey QSslCertificate::publicKey() const
{
QSslKey key;
key.d->type = QSsl::PublicKey;
if (d->publicKeyAlgorithm != QSsl::Opaque) {
key.d->algorithm = d->publicKeyAlgorithm;
key.d->decodeDer(d->publicKeyDerData);
}
return key;
}
QList<QSslCertificateExtension> QSslCertificate::extensions() const
{
Q_UNIMPLEMENTED();
return QList<QSslCertificateExtension>();
}
#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
#define ENDCERTSTRING "-----END CERTIFICATE-----"
QByteArray QSslCertificate::toPem() const
{
QByteArray array = toDer();
// Convert to Base64 - wrap at 64 characters.
array = array.toBase64();
QByteArray tmp;
for (int i = 0; i <= array.size() - 64; i += 64) {
tmp += QByteArray::fromRawData(array.data() + i, 64);
tmp += '\n';
}
if (int remainder = array.size() % 64) {
tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
tmp += '\n';
}
return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
}
QByteArray QSslCertificate::toDer() const
{
return d->derData;
}
QString QSslCertificate::toText() const
{
Q_UNIMPLEMENTED();
return QString();
}
void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
{
if (!data.isEmpty()) {
QList<QSslCertificate> certs = (format == QSsl::Pem)
? certificatesFromPem(data, 1)
: certificatesFromDer(data, 1);
if (!certs.isEmpty()) {
*this = *certs.first().d;
}
}
}
static bool matchLineFeed(const QByteArray &pem, int *offset)
{
char ch = 0;
// ignore extra whitespace at the end of the line
while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
++*offset;
if (ch == '\n') {
*offset += 1;
return true;
}
if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
*offset += 2;
return true;
}
return false;
}
QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
{
QList<QSslCertificate> certificates;
int offset = 0;
while (count == -1 || certificates.size() < count) {
int startPos = pem.indexOf(BEGINCERTSTRING, offset);
if (startPos == -1)
break;
startPos += sizeof(BEGINCERTSTRING) - 1;
if (!matchLineFeed(pem, &startPos))
break;
int endPos = pem.indexOf(ENDCERTSTRING, startPos);
if (endPos == -1)
break;
offset = endPos + sizeof(ENDCERTSTRING) - 1;
if (offset < pem.size() && !matchLineFeed(pem, &offset))
break;
QByteArray decoded = QByteArray::fromBase64(
QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
certificates << certificatesFromDer(decoded, 1);;
}
return certificates;
}
QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
{
QList<QSslCertificate> certificates;
QByteArray data = der;
while (count == -1 || certificates.size() < count) {
QSslCertificate cert;
if (!cert.d->parse(data))
break;
certificates << cert;
data.remove(0, cert.d->derData.size());
}
return certificates;
}
QT_END_NAMESPACE

View File

@ -39,153 +39,76 @@
**
****************************************************************************/
#include "qsslcertificate.h"
#include "qsslcertificate_p.h"
QT_BEGIN_NAMESPACE
#include <QtCore/qfunctions_winrt.h>
bool QSslCertificate::operator==(const QSslCertificate &other) const
{
if (d == other.d)
return true;
return false;
}
#include <wrl.h>
#include <windows.storage.streams.h>
#include <windows.security.cryptography.h>
#include <robuffer.h>
bool QSslCertificate::isNull() const
{
Q_UNIMPLEMENTED();
return true;
}
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Security::Cryptography;
using namespace ABI::Windows::Security::Cryptography::Certificates;
using namespace ABI::Windows::Storage::Streams;
bool QSslCertificate::isSelfSigned() const
{
Q_UNIMPLEMENTED();
return true;
}
QT_USE_NAMESPACE
QByteArray QSslCertificate::version() const
struct SslCertificateGlobal
{
Q_UNIMPLEMENTED();
return QByteArray();
}
SslCertificateGlobal() {
HRESULT hr;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Certificates_Certificate).Get(),
&certificateFactory);
Q_ASSERT_SUCCEEDED(hr);
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
&bufferFactory);
Q_ASSERT_SUCCEEDED(hr);
}
QByteArray QSslCertificate::serialNumber() const
{
Q_UNIMPLEMENTED();
return QByteArray();
}
ComPtr<ICertificateFactory> certificateFactory;
ComPtr<ICryptographicBufferStatics> bufferFactory;
};
Q_GLOBAL_STATIC(SslCertificateGlobal, g)
QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
QSslCertificate QSslCertificatePrivate::QSslCertificate_from_Certificate(ICertificate *iCertificate)
{
Q_UNIMPLEMENTED();
return QStringList();
}
Q_ASSERT(iCertificate);
ComPtr<IBuffer> buffer;
HRESULT hr = iCertificate->GetCertificateBlob(&buffer);
RETURN_IF_FAILED("Could not obtain certification blob", return QSslCertificate());
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
hr = buffer.As(&byteAccess);
RETURN_IF_FAILED("Could not obtain byte access to buffer", return QSslCertificate());
char *data;
hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
RETURN_IF_FAILED("Could not obtain buffer data", return QSslCertificate());
UINT32 size;
hr = buffer->get_Length(&size);
RETURN_IF_FAILED("Could not obtain buffer length ", return QSslCertificate());
QByteArray der(data, size);
QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
{
Q_UNIMPLEMENTED();
return QStringList();
}
QSslCertificate certificate;
certificate.d->null = false;
certificate.d->certificate = iCertificate;
QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
{
Q_UNIMPLEMENTED();
return QStringList();
}
QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
{
Q_UNIMPLEMENTED();
return QStringList();
}
QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
{
Q_UNIMPLEMENTED();
return QList<QByteArray>();
}
QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
{
Q_UNIMPLEMENTED();
return QList<QByteArray>();
}
QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
{
Q_UNIMPLEMENTED();
return QMultiMap<QSsl::AlternativeNameEntryType, QString>();
}
QDateTime QSslCertificate::effectiveDate() const
{
Q_UNIMPLEMENTED();
return QDateTime();
}
QDateTime QSslCertificate::expiryDate() const
{
Q_UNIMPLEMENTED();
return QDateTime();
return certificatesFromDer(der, 1).at(0);
}
Qt::HANDLE QSslCertificate::handle() const
{
Q_UNIMPLEMENTED();
return 0;
}
if (!d->certificate) {
HRESULT hr;
ComPtr<IBuffer> buffer;
hr = g->bufferFactory->CreateFromByteArray(d->derData.length(), (BYTE *)d->derData.data(), &buffer);
RETURN_IF_FAILED("Failed to create the certificate data buffer", return 0);
QSslKey QSslCertificate::publicKey() const
{
Q_UNIMPLEMENTED();
return QSslKey();
}
hr = g->certificateFactory->CreateCertificate(buffer.Get(), &d->certificate);
RETURN_IF_FAILED("Failed to create the certificate handle from the data buffer", return 0);
}
QList<QSslCertificateExtension> QSslCertificate::extensions() const
{
Q_UNIMPLEMENTED();
return QList<QSslCertificateExtension>();
return d->certificate.Get();
}
QByteArray QSslCertificate::toPem() const
{
Q_UNIMPLEMENTED();
return QByteArray();
}
QByteArray QSslCertificate::toDer() const
{
Q_UNIMPLEMENTED();
return QByteArray();
}
QString QSslCertificate::toText() const
{
Q_UNIMPLEMENTED();
return QString();
}
void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
{
Q_UNIMPLEMENTED();
}
QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
{
Q_UNIMPLEMENTED();
Q_UNUSED(pem)
Q_UNUSED(count)
return QList<QSslCertificate>();
}
QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
{
Q_UNIMPLEMENTED();
Q_UNUSED(der)
Q_UNUSED(count)
return QList<QSslCertificate>();
}
QT_END_NAMESPACE

View File

@ -109,10 +109,9 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
return false;
}
void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase,
bool deepClear)
void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
{
decodePem(pemFromDer(der), passPhrase, deepClear);
decodePem(pemFromDer(der), QByteArray(), deepClear);
}
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,

View File

@ -175,8 +175,10 @@ QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem) const
/*!
Constructs a QSslKey by decoding the string in the byte array
\a encoded using a specified \a algorithm and \a encoding format.
If the encoded key is encrypted, \a passPhrase is used to decrypt
it. \a type specifies whether the key is public or private.
\a type specifies whether the key is public or private.
If the key is encoded as PEM and encrypted, \a passPhrase is used
to decrypt it.
After construction, use isNull() to check if \a encoded contained
a valid key.
@ -188,7 +190,7 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
d->type = type;
d->algorithm = algorithm;
if (encoding == QSsl::Der)
d->decodeDer(encoded, passPhrase);
d->decodeDer(encoded);
else
d->decodePem(encoded, passPhrase);
}
@ -196,8 +198,10 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
/*!
Constructs a QSslKey by reading and decoding data from a
\a device using a specified \a algorithm and \a encoding format.
If the encoded key is encrypted, \a passPhrase is used to decrypt
it. \a type specifies whether the key is public or private.
\a type specifies whether the key is public or private.
If the key is encoded as PEM and encrypted, \a passPhrase is used
to decrypt it.
After construction, use isNull() to check if \a device provided
a valid key.
@ -211,9 +215,10 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
encoded = device->readAll();
d->type = type;
d->algorithm = algorithm;
d->decodePem((encoding == QSsl::Der) ?
d->pemFromDer(encoded) : encoded,
passPhrase);
if (encoding == QSsl::Der)
d->decodeDer(encoded);
else
d->decodePem(encoded, passPhrase);
}
/*!
@ -228,7 +233,11 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QSslKey::QSslKey(Qt::HANDLE handle, QSsl::KeyType type)
: d(new QSslKeyPrivate)
{
#ifndef QT_NO_OPENSSL
d->opaque = reinterpret_cast<EVP_PKEY *>(handle);
#else
d->opaque = handle;
#endif
d->algorithm = QSsl::Opaque;
d->type = type;
d->isNull = !d->opaque;
@ -313,17 +322,25 @@ QSsl::KeyAlgorithm QSslKey::algorithm() const
}
/*!
Returns the key in DER encoding. The result is encrypted with
\a passPhrase if the key is a private key and \a passPhrase is
non-empty.
Returns the key in DER encoding.
The \a passPhrase argument should be omitted as DER cannot be
encrypted. It will be removed in a future version of Qt.
*/
// ### autotest failure for non-empty passPhrase and private key
QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
{
if (d->isNull || d->algorithm == QSsl::Opaque)
return QByteArray();
// Encrypted DER is nonsense, see QTBUG-41038.
if (d->type == QSsl::PrivateKey && !passPhrase.isEmpty())
return QByteArray();
#ifndef QT_NO_OPENSSL
return d->derFromPem(toPem(passPhrase));
#else
return d->derData;
#endif
}
/*!

View File

@ -61,10 +61,6 @@
#ifndef QT_NO_OPENSSL
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#else
struct RSA;
struct DSA;
struct EVP_PKEY;
#endif
QT_BEGIN_NAMESPACE
@ -73,9 +69,11 @@ class QSslKeyPrivate
{
public:
inline QSslKeyPrivate()
: rsa(0)
: opaque(0)
#ifndef QT_NO_OPENSSL
, rsa(0)
, dsa(0)
, opaque(0)
#endif
{
clear();
}
@ -85,9 +83,10 @@ public:
void clear(bool deep = true);
#ifndef QT_NO_OPENSSL
bool fromEVP_PKEY(EVP_PKEY *pkey);
void decodeDer(const QByteArray &der, const QByteArray &passPhrase,
bool deepClear = true);
#endif
void decodeDer(const QByteArray &der, bool deepClear = true);
void decodePem(const QByteArray &pem, const QByteArray &passPhrase,
bool deepClear = true);
QByteArray pemHeader() const;
@ -102,9 +101,15 @@ public:
bool isNull;
QSsl::KeyType type;
QSsl::KeyAlgorithm algorithm;
#ifndef QT_NO_OPENSSL
EVP_PKEY *opaque;
RSA *rsa;
DSA *dsa;
EVP_PKEY *opaque;
#else
Qt::HANDLE opaque;
QByteArray derData;
int keyLength;
#endif
QAtomicInt ref;

View File

@ -0,0 +1,184 @@
/****************************************************************************
**
** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsslkey.h"
#include "qsslkey_p.h"
#include "qasn1element_p.h"
QT_USE_NAMESPACE
static const quint8 bits_table[256] = {
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};
static int numberOfBits(const QByteArray &modulus)
{
int bits = modulus.size() * 8;
for (int i = 0; i < modulus.size(); ++i) {
quint8 b = modulus[i];
bits -= 8;
if (b != 0) {
bits += bits_table[b];
break;
}
}
return bits;
}
void QSslKeyPrivate::clear(bool deep)
{
Q_UNUSED(deep);
isNull = true;
derData.clear();
keyLength = -1;
}
void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
{
clear(deepClear);
if (der.isEmpty())
return;
QAsn1Element elem;
if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
return;
if (type == QSsl::PublicKey) {
// key info
QDataStream keyStream(elem.value());
if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
return;
QVector<QAsn1Element> infoItems = elem.toVector();
if (infoItems.size() < 2 || infoItems[0].type() != QAsn1Element::ObjectIdentifierType)
return;
if (algorithm == QSsl::Rsa) {
if (infoItems[0].toObjectId() != "1.2.840.113549.1.1.1")
return;
// key data
if (!elem.read(keyStream) || elem.type() != QAsn1Element::BitStringType || elem.value().isEmpty())
return;
if (!elem.read(elem.value().mid(1)) || elem.type() != QAsn1Element::SequenceType)
return;
if (!elem.read(elem.value()) || elem.type() != QAsn1Element::IntegerType)
return;
keyLength = numberOfBits(elem.value());
} else if (algorithm == QSsl::Dsa) {
if (infoItems[0].toObjectId() != "1.2.840.10040.4.1")
return;
if (infoItems[1].type() != QAsn1Element::SequenceType)
return;
// key params
QVector<QAsn1Element> params = infoItems[1].toVector();
if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
return;
keyLength = numberOfBits(params[0].value());
}
} else {
QVector<QAsn1Element> items = elem.toVector();
if (items.isEmpty())
return;
// version
if (items[0].type() != QAsn1Element::IntegerType || items[0].value().toHex() != "00")
return;
if (algorithm == QSsl::Rsa) {
if (items.size() != 9 || items[1].type() != QAsn1Element::IntegerType)
return;
keyLength = numberOfBits(items[1].value());
} else if (algorithm == QSsl::Dsa) {
if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType)
return;
keyLength = numberOfBits(items[1].value());
}
}
derData = der;
isNull = false;
}
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
bool deepClear)
{
if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
Q_UNIMPLEMENTED();
return;
}
decodeDer(derFromPem(pem), deepClear);
}
int QSslKeyPrivate::length() const
{
return keyLength;
}
QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
{
if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
Q_UNIMPLEMENTED();
return QByteArray();
}
return pemFromDer(derData);
}
Qt::HANDLE QSslKeyPrivate::handle() const
{
return opaque;
}

View File

@ -41,6 +41,7 @@
#include "qsslkey.h"
#include "qsslkey_p.h"
#include "qsslcertificate_p.h"
#include <QtCore/qfunctions_winrt.h>
@ -59,136 +60,4 @@ using namespace ABI::Windows::Security::Cryptography::Certificates;
using namespace ABI::Windows::Security::Cryptography::Core;
using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
struct SslKeyGlobal
{
SslKeyGlobal()
{
HRESULT hr;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
&bufferFactory);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsymmetricKeyAlgorithmProviderStatics> keyProviderFactory;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_AsymmetricKeyAlgorithmProvider).Get(),
&keyProviderFactory);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsymmetricAlgorithmNamesStatics> algorithmNames;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_AsymmetricAlgorithmNames).Get(),
&algorithmNames);
Q_ASSERT_SUCCEEDED(hr);
HString algorithmName;
// The algorithm name doesn't matter for imports, so just use PKCS1
hr = algorithmNames->get_RsaPkcs1(algorithmName.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
hr = keyProviderFactory->OpenAlgorithm(algorithmName.Get(), &keyProvider);
Q_ASSERT_SUCCEEDED(hr);
}
ComPtr<ICryptographicBufferStatics> bufferFactory;
ComPtr<IAsymmetricKeyAlgorithmProvider> keyProvider;
};
Q_GLOBAL_STATIC(SslKeyGlobal, g)
// Use the opaque struct for key storage
struct EVP_PKEY {
ComPtr<ICryptographicKey> key;
};
void QSslKeyPrivate::clear(bool deep)
{
isNull = true;
if (opaque) {
if (deep) {
delete opaque;
opaque = 0;
} else {
opaque->key.Reset();
}
}
}
void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase,
bool deepClear)
{
Q_UNUSED(passPhrase);
clear(deepClear);
if (der.isEmpty())
return;
if (type != QSsl::PublicKey) {
qWarning("The WinRT SSL backend does not support importing private keys.");
return;
}
HRESULT hr;
ComPtr<IBuffer> buffer;
hr = g->bufferFactory->CreateFromByteArray(der.length(), (BYTE *)der.data(), &buffer);
Q_ASSERT_SUCCEEDED(hr);
if (!opaque)
opaque = new EVP_PKEY;
hr = g->keyProvider->ImportDefaultPublicKeyBlob(buffer.Get(), &opaque->key);
RETURN_VOID_IF_FAILED("Failed to import public key");
isNull = false;
}
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
bool deepClear)
{
decodeDer(derFromPem(pem), passPhrase, deepClear);
}
int QSslKeyPrivate::length() const
{
if (isNull)
return -1;
Q_ASSERT(opaque && opaque->key);
HRESULT hr;
UINT32 keySize;
hr = opaque->key->get_KeySize(&keySize);
Q_ASSERT_SUCCEEDED(hr);
return keySize;
}
QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
{
Q_UNUSED(passPhrase);
QByteArray result;
if (isNull)
return result;
Q_ASSERT(opaque && opaque->key);
HRESULT hr;
ComPtr<IBuffer> buffer;
hr = opaque->key->ExportDefaultPublicKeyBlobType(&buffer);
RETURN_IF_FAILED("Failed to export key", return result);
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
hr = buffer.As(&byteAccess);
Q_ASSERT_SUCCEEDED(hr);
char *data;
hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
Q_ASSERT_SUCCEEDED(hr);
UINT32 size;
hr = buffer->get_Length(&size);
Q_ASSERT_SUCCEEDED(hr);
result = pemFromDer(QByteArray::fromRawData(data, size));
return result;
}
Qt::HANDLE QSslKeyPrivate::handle() const
{
return opaque ? opaque->key.Get() : 0;
}
QT_END_NAMESPACE
QT_USE_NAMESPACE

View File

@ -1894,8 +1894,10 @@ void QSslSocket::disconnectFromHost()
emit stateChanged(d->state);
}
if (!d->writeBuffer.isEmpty())
if (!d->writeBuffer.isEmpty()) {
d->pendingClose = true;
return;
}
if (d->mode == UnencryptedMode) {
d->plainSocket->disconnectFromHost();
@ -2513,6 +2515,65 @@ QSharedPointer<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket)
return (socket) ? socket->d_func()->sslContextPointer : QSharedPointer<QSslContext>();
}
bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
{
QStringList commonNameList = cert.subjectInfo(QSslCertificate::CommonName);
foreach (const QString &commonName, commonNameList) {
if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
return true;
}
}
foreach (const QString &altName, cert.subjectAlternativeNames().values(QSsl::DnsEntry)) {
if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
return true;
}
}
return false;
}
bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
{
int wildcard = cn.indexOf(QLatin1Char('*'));
// Check this is a wildcard cert, if not then just compare the strings
if (wildcard < 0)
return cn == hostname;
int firstCnDot = cn.indexOf(QLatin1Char('.'));
int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
// Check at least 3 components
if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
return false;
// Check * is last character of 1st component (ie. there's a following .)
if (wildcard+1 != firstCnDot)
return false;
// Check only one star
if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
return false;
// Check characters preceding * (if any) match
if (wildcard && (hostname.leftRef(wildcard) != cn.leftRef(wildcard)))
return false;
// Check characters following first . match
if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot))
return false;
// Check if the hostname is an IP address, if so then wildcards are not allowed
QHostAddress addr(hostname);
if (!addr.isNull())
return false;
// Ok, I guess this was a wildcard CN and the hostname matches.
return true;
}
QT_END_NAMESPACE
#include "moc_qsslsocket.cpp"

View File

@ -1552,65 +1552,6 @@ QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates
return certificates;
}
bool QSslSocketBackendPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
{
QStringList commonNameList = cert.subjectInfo(QSslCertificate::CommonName);
foreach (const QString &commonName, commonNameList) {
if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
return true;
}
}
foreach (const QString &altName, cert.subjectAlternativeNames().values(QSsl::DnsEntry)) {
if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
return true;
}
}
return false;
}
bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
{
int wildcard = cn.indexOf(QLatin1Char('*'));
// Check this is a wildcard cert, if not then just compare the strings
if (wildcard < 0)
return cn == hostname;
int firstCnDot = cn.indexOf(QLatin1Char('.'));
int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
// Check at least 3 components
if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
return false;
// Check * is last character of 1st component (ie. there's a following .)
if (wildcard+1 != firstCnDot)
return false;
// Check only one star
if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
return false;
// Check characters preceding * (if any) match
if (wildcard && (hostname.leftRef(wildcard) != cn.leftRef(wildcard)))
return false;
// Check characters following first . match
if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot))
return false;
// Check if the hostname is an IP address, if so then wildcards are not allowed
QHostAddress addr(hostname);
if (!addr.isNull())
return false;
// Ok, I guess this was a wildcard CN and the hostname matches.
return true;
}
QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
{
QList<QSslError> errors;

View File

@ -142,8 +142,6 @@ public:
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName);
static QString getErrorsFromOpenSsl();
static bool importPKCS12(QIODevice *device,

View File

@ -150,6 +150,8 @@ public:
QRegExp::PatternSyntax syntax);
static void addDefaultCaCertificate(const QSslCertificate &cert);
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
#if defined(Q_OS_MACX)
static PtrSecCertificateCopyData ptrSecCertificateCopyData;

View File

@ -39,39 +39,132 @@
**
****************************************************************************/
/****************************************************************************
**
** In addition, as a special exception, the copyright holders listed above give
** permission to link the code of its release of Qt with the OpenSSL project's
** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
** same license as the original version), and distribute the linked executables.
**
** You must comply with the GNU General Public License version 2 in all
** respects for all of the code used other than the "OpenSSL" code. If you
** modify this file, you may extend this exception to your version of the file,
** but you are not obligated to do so. If you do not wish to do so, delete
** this exception statement from your version of this file.
**
****************************************************************************/
//#define QSSLSOCKET_DEBUG
//#define QT_DECRYPT_SSL_TRAFFIC
#include "qsslsocket_winrt_p.h"
#include "qsslsocket.h"
#include "qsslcertificate_p.h"
#include "qsslcipher_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QSysInfo>
#include <QtCore/qfunctions_winrt.h>
#include <private/qnativesocketengine_winrt_p.h>
#include <windows.networking.h>
#include <windows.networking.sockets.h>
#include <windows.security.cryptography.certificates.h>
#include <robuffer.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::Networking;
using namespace ABI::Windows::Networking::Sockets;
using namespace ABI::Windows::Security::Cryptography::Certificates;
using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
// For QSet<QSslError>
inline uint qHash(const QSslError &error, uint seed)
Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(error)))
{ return (qHash(error.error()) ^ seed); }
// For QSet<QSslCertificate>
inline uint qHash(const QSslCertificate &certificate, uint seed)
Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(certificate)))
{ return (qHash(certificate.handle()) ^ seed); }
bool QSslSocketPrivate::s_libraryLoaded = true;
bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
struct SslSocketGlobal
{
SslSocketGlobal()
{
HRESULT hr;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
&hostNameFactory);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<ICertificateStoresStatics> certificateStores;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Certificates_CertificateStores).Get(),
&certificateStores);
Q_ASSERT_SUCCEEDED(hr);
hr = certificateStores->get_TrustedRootCertificationAuthorities(&rootStore);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsyncOperation<IVectorView<Certificate *> *>> op;
hr = certificateStores->FindAllAsync(&op);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IVectorView<Certificate *>> certificates;
hr = QWinRTFunctions::await(op, certificates.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
quint32 size;
hr = certificates->get_Size(&size);
Q_ASSERT_SUCCEEDED(hr);
for (quint32 i = 0; i < size; ++i) {
ComPtr<ICertificate> certificate;
hr = certificates->GetAt(i, &certificate);
Q_ASSERT_SUCCEEDED(hr);
systemCaCertificates.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get()));
}
}
void syncCaCertificates(const QSet<QSslCertificate> &add, const QSet<QSslCertificate> &remove)
{
QMutexLocker locker(&certificateMutex);
foreach (const QSslCertificate &certificate, add) {
QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
if (it != additionalCertificates.end()) {
it.value().ref(); // Add a reference
} else {
// install certificate
HRESULT hr;
hr = rootStore->Add(static_cast<ICertificate *>(certificate.handle()));
Q_ASSERT_SUCCEEDED(hr);
additionalCertificates.insert(certificate, 1);
}
}
foreach (const QSslCertificate &certificate, remove) {
QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
if (it != additionalCertificates.end() && !it.value().deref()) {
// no more references, remove certificate
HRESULT hr;
hr = rootStore->Delete(static_cast<ICertificate *>(certificate.handle()));
Q_ASSERT_SUCCEEDED(hr);
additionalCertificates.erase(it);
}
}
}
ComPtr<IHostNameFactory> hostNameFactory;
QList<QSslCertificate> systemCaCertificates;
private:
QMutex certificateMutex;
ComPtr<ICertificateStore> rootStore;
QHash<QSslCertificate, QAtomicInt> additionalCertificates;
};
Q_GLOBAL_STATIC(SslSocketGlobal, g)
// Called on the socket's thread to avoid cross-thread deletion
void QSslSocketConnectionHelper::disconnectSocketFromHost()
{
if (d->plainSocket)
d->plainSocket->disconnectFromHost();
}
QSslSocketBackendPrivate::QSslSocketBackendPrivate()
: connectionHelper(new QSslSocketConnectionHelper(this))
{
ensureInitialized();
}
QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
{
g->syncCaCertificates(QSet<QSslCertificate>(), previousCaCertificates);
}
void QSslSocketPrivate::deinitialize()
@ -84,31 +177,28 @@ bool QSslSocketPrivate::supportsSsl()
return true;
}
bool QSslSocketPrivate::ensureLibraryLoaded()
{
return true;
}
void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
{
Q_UNIMPLEMENTED();
}
void QSslSocketPrivate::ensureInitialized()
{
if (s_loadedCiphersAndCerts)
return;
s_loadedCiphersAndCerts = true;
resetDefaultCiphers();
}
long QSslSocketPrivate::sslLibraryVersionNumber()
{
Q_UNIMPLEMENTED();
return 0;
return QSysInfo::windowsVersion();
}
QString QSslSocketPrivate::sslLibraryVersionString()
{
Q_UNIMPLEMENTED();
return QString::number(sslLibraryVersionNumber());
switch (QSysInfo::windowsVersion()) {
case QSysInfo::WV_WINDOWS8_1:
return QStringLiteral("Windows Runtime 8.1 SSL library");
default:
break;
}
return QStringLiteral("Windows Runtime SSL library");
}
long QSslSocketPrivate::sslLibraryBuildVersionNumber()
@ -125,20 +215,68 @@ QString QSslSocketPrivate::sslLibraryBuildVersionString()
void QSslSocketPrivate::resetDefaultCiphers()
{
Q_UNIMPLEMENTED();
setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
}
QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
{
QList<QSslCipher> ciphers;
const QString protocolStrings[] = { QStringLiteral("SSLv3"), QStringLiteral("TLSv1"),
QStringLiteral("TLSv1.1"), QStringLiteral("TLSv1.2") };
const QSsl::SslProtocol protocols[] = { QSsl::SslV3, QSsl::TlsV1_0, QSsl::TlsV1_1, QSsl::TlsV1_2 };
for (int i = 0; i < ARRAYSIZE(protocols); ++i) {
QSslCipher cipher;
cipher.d->isNull = false;
cipher.d->name = QStringLiteral("WINRT");
cipher.d->protocol = protocols[i];
cipher.d->protocolString = protocolStrings[i];
ciphers.append(cipher);
}
return ciphers;
}
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
{
Q_UNIMPLEMENTED();
ensureInitialized();
QList<QSslCertificate> systemCerts;
return systemCerts;
return g->systemCaCertificates;
}
void QSslSocketBackendPrivate::startClientEncryption()
{
Q_UNIMPLEMENTED();
Q_Q(QSslSocket);
QSsl::SslProtocol protocol = q->protocol();
switch (q->protocol()) {
case QSsl::AnyProtocol:
case QSsl::SslV3:
protectionLevel = SocketProtectionLevel_Ssl; // Only use this value if weak cipher support is required
break;
case QSsl::SecureProtocols:
case QSsl::TlsV1SslV3:
case QSsl::TlsV1_0:
protectionLevel = SocketProtectionLevel_Tls10;
break;
case QSsl::TlsV1_1:
protectionLevel = SocketProtectionLevel_Tls11;
break;
case QSsl::TlsV1_2:
protectionLevel = SocketProtectionLevel_Tls12;
break;
default:
protectionLevel = SocketProtectionLevel_Tls12; // default to highest
protocol = QSsl::TlsV1_2;
break;
}
// Sync custom certificates
const QSet<QSslCertificate> caCertificates = configuration.caCertificates.toSet();
const QSet<QSslCertificate> newCertificates = caCertificates - previousCaCertificates;
const QSet<QSslCertificate> oldCertificates = previousCaCertificates - caCertificates;
g->syncCaCertificates(newCertificates, oldCertificates);
previousCaCertificates = caCertificates;
continueHandshake();
}
void QSslSocketBackendPrivate::startServerEncryption()
@ -148,33 +286,379 @@ void QSslSocketBackendPrivate::startServerEncryption()
void QSslSocketBackendPrivate::transmit()
{
Q_UNIMPLEMENTED();
Q_Q(QSslSocket);
if (connectionEncrypted && !writeBuffer.isEmpty()) {
qint64 totalBytesWritten = 0;
int nextDataBlockSize;
while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
int writtenBytes = plainSocket->write(writeBuffer.readPointer(), nextDataBlockSize);
writtenBytes = nextDataBlockSize;
writeBuffer.free(writtenBytes);
totalBytesWritten += writtenBytes;
if (writtenBytes < nextDataBlockSize)
break;
}
if (totalBytesWritten > 0) {
// Don't emit bytesWritten() recursively.
if (!emittedBytesWritten) {
emittedBytesWritten = true;
emit q->bytesWritten(totalBytesWritten);
emittedBytesWritten = false;
}
}
}
// Check if we've got any data to be read from the socket.
int pendingBytes;
bool bytesRead = false;
while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
char *ptr = buffer.reserve(pendingBytes);
int readBytes = plainSocket->read(ptr, pendingBytes);
buffer.chop(pendingBytes - readBytes);
bytesRead = true;
}
if (bytesRead) {
if (readyReadEmittedPointer)
*readyReadEmittedPointer = true;
emit q->readyRead();
}
if (pendingClose) {
pendingClose = false;
q->disconnectFromHost();
}
}
void QSslSocketBackendPrivate::disconnectFromHost()
{
Q_UNIMPLEMENTED();
QMetaObject::invokeMethod(connectionHelper.data(), "disconnectSocketFromHost", Qt::QueuedConnection);
}
void QSslSocketBackendPrivate::disconnected()
{
Q_UNIMPLEMENTED();
}
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
{
Q_UNIMPLEMENTED();
return QSslCipher();
return configuration.sessionCipher;
}
QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
{
Q_UNIMPLEMENTED();
return QSsl::UnknownProtocol;
return configuration.sessionCipher.protocol();
}
void QSslSocketBackendPrivate::continueHandshake()
{
Q_UNIMPLEMENTED();
Q_Q(QSslSocket);
IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
if (qintptr(socket) == -1) {
q->setErrorString(QStringLiteral("At attempt was made to continue the handshake on an invalid socket."));
q->setSocketError(QAbstractSocket::SslInternalError);
emit q->error(QAbstractSocket::SslInternalError);
return;
}
HRESULT hr;
ComPtr<IHostName> hostName;
const QString host = verificationPeerName.isEmpty() ? plainSocket->peerName()
: verificationPeerName;
if (host.isEmpty()) {
ComPtr<IStreamSocketInformation> info;
hr = socket->get_Information(&info);
Q_ASSERT_SUCCEEDED(hr);
hr = info->get_RemoteAddress(&hostName);
} else {
HStringReference hostRef(reinterpret_cast<LPCWSTR>(host.utf16()), host.length());
hr = g->hostNameFactory->CreateHostName(hostRef.Get(), &hostName);
Q_ASSERT_SUCCEEDED(hr);
}
if (FAILED(hr)) {
q->setErrorString(qt_error_string(hr));
q->setSocketError(QAbstractSocket::SslInvalidUserDataError);
emit q->error(QAbstractSocket::SslInvalidUserDataError);
return;
}
ComPtr<IStreamSocketControl> control;
hr = socket->get_Control(&control);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IStreamSocketControl2> control2;
hr = control.As(&control2);
ComPtr<IVector<ChainValidationResult>> ignoreList;
hr = control2->get_IgnorableServerCertificateErrors(&ignoreList);
Q_ASSERT_SUCCEEDED(hr);
QSet<QSslError> ignoreErrors = ignoreErrorsList.toSet();
for (int i = ChainValidationResult_Untrusted; i < ChainValidationResult_OtherErrors + 1; ++i) {
// Populate the native ignore list - break to add, continue to skip
switch (i) {
case ChainValidationResult_Revoked:
case ChainValidationResult_InvalidSignature:
case ChainValidationResult_BasicConstraintsError:
case ChainValidationResult_InvalidCertificateAuthorityPolicy:
case ChainValidationResult_UnknownCriticalExtension:
case ChainValidationResult_OtherErrors:
continue; // The above errors can't be ignored in the handshake
case ChainValidationResult_Untrusted:
if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateUntrusted))
break;
continue;
case ChainValidationResult_Expired:
if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateExpired))
break;
continue;
case ChainValidationResult_IncompleteChain:
if (ignoreAllSslErrors
|| ignoreErrors.contains(QSslError::InvalidCaCertificate)
|| ignoreErrors.contains(QSslError::UnableToVerifyFirstCertificate)
|| ignoreErrors.contains(QSslError::UnableToGetIssuerCertificate)) {
break;
}
continue;
case ChainValidationResult_WrongUsage:
if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::InvalidPurpose))
break;
continue;
case ChainValidationResult_InvalidName:
if (ignoreAllSslErrors
|| ignoreErrors.contains(QSslError::HostNameMismatch)
|| ignoreErrors.contains(QSslError::SubjectIssuerMismatch)) {
break;
}
continue;
case ChainValidationResult_RevocationInformationMissing:
case ChainValidationResult_RevocationFailure:
default:
if (ignoreAllSslErrors)
break;
continue;
}
hr = ignoreList->Append(static_cast<ChainValidationResult>(i));
Q_ASSERT_SUCCEEDED(hr);
}
ComPtr<IAsyncAction> op;
hr = socket->UpgradeToSslAsync(protectionLevel, hostName.Get(), &op);
if (FAILED(hr)) {
q->setErrorString(QSslSocket::tr("Error creating SSL session: %1")
.arg(qt_error_string(hr)));
q->setSocketError(QAbstractSocket::SslInternalError);
emit q->error(QAbstractSocket::SslInternalError);
return;
}
hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(
this, &QSslSocketBackendPrivate::onSslUpgrade).Get());
Q_ASSERT_SUCCEEDED(hr);
}
HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus)
{
Q_Q(QSslSocket);
if (wasDeleted) {
qWarning("SSL upgrade callback received after the delegate was deleted. "
"This may be indicative of an internal bug in the WinRT SSL implementation.");
return S_OK;
}
HRESULT hr = action->GetResults();
QSet<QSslError> errors;
switch (hr) {
case SEC_E_INVALID_TOKEN: // Occurs when the server doesn't support the requested protocol
q->setErrorString(qt_error_string(hr));
q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
emit q->error(QAbstractSocket::SslHandshakeFailedError);
q->disconnectFromHost();
return S_OK;
default:
if (FAILED(hr))
qErrnoWarning(hr, "error"); // Unhandled error; let sslErrors take care of it
break;
}
IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
if (qintptr(socket) == -1) {
qWarning("The underlying TCP socket used by the SSL socket is invalid. "
"This may be indicative of an internal bug in the WinRT SSL implementation.");
return S_OK;
}
ComPtr<IStreamSocketInformation> info;
hr = socket->get_Information(&info);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IStreamSocketInformation2> info2;
hr = info.As(&info2);
Q_ASSERT_SUCCEEDED(hr);
// Cipher
QSsl::SslProtocol protocol;
SocketProtectionLevel protectionLevel;
hr = info->get_ProtectionLevel(&protectionLevel);
switch (protectionLevel) {
default:
protocol = QSsl::UnknownProtocol;
break;
case SocketProtectionLevel_Ssl:
protocol = QSsl::SslV3;
break;
case SocketProtectionLevel_Tls10:
protocol = QSsl::TlsV1_0;
break;
case SocketProtectionLevel_Tls11:
protocol = QSsl::TlsV1_1;
break;
case SocketProtectionLevel_Tls12:
protocol = QSsl::TlsV1_2;
break;
}
configuration.sessionCipher = QSslCipher(QStringLiteral("WINRT"), protocol); // The actual cipher name is not accessible
// Certificate & chain
ComPtr<ICertificate> certificate;
hr = info2->get_ServerCertificate(&certificate);
Q_ASSERT_SUCCEEDED(hr);
QList<QSslCertificate> peerCertificateChain;
if (certificate) {
ComPtr<IAsyncOperation<CertificateChain *>> op;
hr = certificate->BuildChainAsync(Q_NULLPTR, &op);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<ICertificateChain> certificateChain;
hr = QWinRTFunctions::await(op, certificateChain.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IVectorView<Certificate *>> certificates;
hr = certificateChain->GetCertificates(true, &certificates);
Q_ASSERT_SUCCEEDED(hr);
quint32 certificatesLength;
hr = certificates->get_Size(&certificatesLength);
Q_ASSERT_SUCCEEDED(hr);
for (quint32 i = 0; i < certificatesLength; ++i) {
ComPtr<ICertificate> chainCertificate;
hr = certificates->GetAt(i, &chainCertificate);
Q_ASSERT_SUCCEEDED(hr);
peerCertificateChain.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(chainCertificate.Get()));
}
}
configuration.peerCertificate = certificate ? QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get())
: QSslCertificate();
configuration.peerCertificateChain = peerCertificateChain;
// Errors
ComPtr<IVectorView<ChainValidationResult>> chainValidationResults;
hr = info2->get_ServerCertificateErrors(&chainValidationResults);
Q_ASSERT_SUCCEEDED(hr);
quint32 size;
hr = chainValidationResults->get_Size(&size);
Q_ASSERT_SUCCEEDED(hr);
for (quint32 i = 0; i < size; ++i) {
ChainValidationResult result;
hr = chainValidationResults->GetAt(i, &result);
Q_ASSERT_SUCCEEDED(hr);
switch (result) {
case ChainValidationResult_Success:
break;
case ChainValidationResult_Untrusted:
errors.insert(QSslError::CertificateUntrusted);
break;
case ChainValidationResult_Revoked:
errors.insert(QSslError::CertificateRevoked);
break;
case ChainValidationResult_Expired:
errors.insert(QSslError::CertificateExpired);
break;
case ChainValidationResult_IncompleteChain:
errors.insert(QSslError::UnableToGetIssuerCertificate);
break;
case ChainValidationResult_InvalidSignature:
errors.insert(QSslError::CertificateSignatureFailed);
break;
case ChainValidationResult_WrongUsage:
errors.insert(QSslError::InvalidPurpose);
break;
case ChainValidationResult_InvalidName:
errors.insert(QSslError::HostNameMismatch);
break;
case ChainValidationResult_InvalidCertificateAuthorityPolicy:
errors.insert(QSslError::InvalidCaCertificate);
break;
default:
errors.insert(QSslError::UnspecifiedError);
break;
}
}
sslErrors = errors.toList();
// Peer validation
if (!configuration.peerCertificate.isNull()) {
const QString peerName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
// No matches in common names or alternate names.
const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
const int index = sslErrors.indexOf(QSslError::HostNameMismatch);
if (index >= 0) // Replace the existing error
sslErrors[index] = error;
else
sslErrors.append(error);
emit q->peerVerifyError(error);
}
// Peer validation required, but no certificate is present
} else if (configuration.peerVerifyMode == QSslSocket::VerifyPeer
|| configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer) {
QSslError error(QSslError::NoPeerCertificate);
sslErrors.append(error);
emit q->peerVerifyError(error);
}
// Peer chain validation
foreach (const QSslCertificate &certificate, peerCertificateChain) {
if (!QSslCertificatePrivate::isBlacklisted(certificate))
continue;
QSslError error(QSslError::CertificateBlacklisted, certificate);
sslErrors.append(error);
emit q->peerVerifyError(error);
}
if (!sslErrors.isEmpty()) {
emit q->sslErrors(sslErrors);
q->setErrorString(sslErrors.first().errorString());
q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
emit q->error(QAbstractSocket::SslHandshakeFailedError);
// Disconnect if there are any non-ignorable errors
foreach (const QSslError &error, sslErrors) {
if (ignoreErrorsList.contains(error))
continue;
q->disconnectFromHost();
return S_OK;
}
}
if (readBufferMaxSize)
plainSocket->setReadBufferSize(readBufferMaxSize);
connectionEncrypted = true;
emit q->encrypted();
if (pendingClose) {
pendingClose = false;
q->disconnectFromHost();
}
return S_OK;
}
QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)

View File

@ -39,30 +39,15 @@
**
****************************************************************************/
/****************************************************************************
**
** In addition, as a special exception, the copyright holders listed above give
** permission to link the code of its release of Qt with the OpenSSL project's
** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
** same license as the original version), and distribute the linked executables.
**
** You must comply with the GNU General Public License version 2 in all
** respects for all of the code used other than the "OpenSSL" code. If you
** modify this file, you may extend this exception to your version of the file,
** but you are not obligated to do so. If you do not wish to do so, delete
** this exception statement from your version of this file.
**
****************************************************************************/
#ifndef QSSLSOCKET_OPENSSL_P_H
#define QSSLSOCKET_OPENSSL_P_H
#ifndef QSSLSOCKET_WINRT_P_H
#define QSSLSOCKET_WINRT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// of the QtNetwork library. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
@ -70,8 +55,24 @@
#include "qsslsocket_p.h"
#include <wrl.h>
#include <windows.networking.sockets.h>
QT_BEGIN_NAMESPACE
class QSslSocketConnectionHelper : public QObject
{
Q_OBJECT
public:
QSslSocketConnectionHelper(QSslSocketBackendPrivate *d)
: d(d) { }
Q_INVOKABLE void disconnectSocketFromHost();
private:
QSslSocketBackendPrivate *d;
};
class QSslSocketBackendPrivate : public QSslSocketPrivate
{
Q_DECLARE_PUBLIC(QSslSocket)
@ -89,13 +90,22 @@ public:
QSsl::SslProtocol sessionProtocol() const Q_DECL_OVERRIDE;
void continueHandshake() Q_DECL_OVERRIDE;
static QList<QSslCipher> defaultCiphers();
static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName);
static bool importPKCS12(QIODevice *device,
QSslKey *key, QSslCertificate *cert,
QList<QSslCertificate> *caCertificates,
const QByteArray &passPhrase);
private:
HRESULT onSslUpgrade(ABI::Windows::Foundation::IAsyncAction *,
ABI::Windows::Foundation::AsyncStatus);
QScopedPointer<QSslSocketConnectionHelper> connectionHelper;
ABI::Windows::Networking::Sockets::SocketProtectionLevel protectionLevel;
QSet<QSslCertificate> previousCaCertificates;
};
QT_END_NAMESPACE
#endif
#endif // QSSLSOCKET_WINRT_P_H

View File

@ -1,6 +1,7 @@
# OpenSSL support; compile in QSslSocket.
contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
HEADERS += ssl/qssl.h \
HEADERS += ssl/qasn1element_p.h \
ssl/qssl.h \
ssl/qsslcertificate.h \
ssl/qsslcertificate_p.h \
ssl/qsslconfiguration.h \
@ -14,7 +15,8 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslsocket_p.h \
ssl/qsslcertificateextension.h \
ssl/qsslcertificateextension_p.h
SOURCES += ssl/qssl.cpp \
SOURCES += ssl/qasn1element.cpp \
ssl/qssl.cpp \
ssl/qsslcertificate.cpp \
ssl/qsslconfiguration.cpp \
ssl/qsslcipher.cpp \
@ -25,7 +27,9 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
winrt {
HEADERS += ssl/qsslsocket_winrt_p.h
SOURCES += ssl/qsslcertificate_winrt.cpp \
SOURCES += ssl/qsslcertificate_qt.cpp \
ssl/qsslcertificate_winrt.cpp \
ssl/qsslkey_qt.cpp \
ssl/qsslkey_winrt.cpp \
ssl/qsslsocket_winrt.cpp
}

View File

@ -2126,7 +2126,7 @@ QGLContext::QGLContext(const QGLFormat &format)
d->init(0, format);
}
void qDeleteQGLContext(void *handle)
static void qDeleteQGLContext(void *handle)
{
QGLContext *context = static_cast<QGLContext *>(handle);
delete context;
@ -3475,7 +3475,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
d->valid = d->guiGlContext->create();
if (d->valid)
d->guiGlContext->setQGLContextHandle(this, qDeleteQGLContext);
d->guiGlContext->setQGLContextHandle(this, 0);
d->glFormat = QGLFormat::fromSurfaceFormat(d->guiGlContext->format());
d->setupSharing();

View File

@ -242,6 +242,7 @@ public:
void swapRegion(const QRegion &region);
QOpenGLContext *guiGlContext;
// true if QGLContext owns the QOpenGLContext (for who deletes who)
bool ownContext;
void setupSharing();

View File

@ -1,53 +1,38 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
# Name of the project which must match the outputdir. Determines the .index file
project = QtPlatformHeaders
project = QtPlatformHeaders
description = Qt Platform Headers Reference Documentation
version = $QT_VERSION
# Directories in which to search for files to document and images.
# By default set to the root directory of the project for sources
# and headers and qdoc will therefore generate output for each file.
# Images should be placed in <rootdir>/dic/images and examples in
# <rootdir>/examples.
# Paths are relative to the location of this file.
examplesinstallpath = qtplatformheaders
headerdirs += ..
sourcedirs += ..
exampledirs += .. \
snippets
qhp.projects = QtPlatformHeaders
imagedirs += images
qhp.QtPlatformHeaders.file = qtplatformheaders.qhp
qhp.QtPlatformHeaders.namespace = org.qt-project.qtplatformheaders.$QT_VERSION_TAG
qhp.QtPlatformHeaders.virtualFolder = qtplatformheaders
qhp.QtPlatformHeaders.indexTitle = Qt Platform Headers
qhp.QtPlatformHeaders.indexRoot =
depends += qtdoc qtcore qtgui qtwidgets
qhp.QtPlatformHeaders.filterAttributes = qtplatformheaders $QT_VERSION qtrefdoc
qhp.QtPlatformHeaders.customFilters.Qt.name = QtPlatformHeaders $QT_VERSION
qhp.QtPlatformHeaders.customFilters.Qt.filterAttributes = qtplatformheaders $QT_VERSION
examplesinstallpath = platformheaders
# The following parameters are for creating a qhp file, the qhelpgenerator
# program can convert the qhp file into a qch file which can be opened in
# Qt Assistant and/or Qt Creator.
# Defines the name of the project. You cannot use operators (+, =, -) in
# the name. Properties for this project are set using a qhp.<projectname>.property
# format.
qhp.projects = QtPlatformHeaders
# Sets the name of the output qhp file.
qhp.QtPlatformHeaders.file = qtplatformheaders.qhp
# Namespace for the output file. This namespace is used to distinguish between
# different documentation files in Creator/Assistant.
qhp.QtPlatformHeaders.namespace = org.qt-project.qtplatformheaders.$QT_VERSION_TAG
# Title for the package, will be the main title for the package in
# Assistant/Creator.
qhp.QtPlatformHeaders.indexTitle = Qt Platform Headers
# Only update the name of the project for the next variables.
qhp.QtPlatformHeaders.virtualFolder = qtplatformheaders
qhp.QtPlatformHeaders.subprojects = classes
qhp.QtPlatformHeaders.subprojects = classes
qhp.QtPlatformHeaders.subprojects.classes.title = C++ Classes
qhp.QtPlatformHeaders.subprojects.classes.indexTitle = Qt Platform Headers C++ Classes
qhp.QtPlatformHeaders.subprojects.classes.selectors = class fake:headerfile
qhp.QtPlatformHeaders.subprojects.classes.sortPages = true
depends += \
qtcore \
qtgui \
qtdoc
headerdirs += ..
sourcedirs += ..
exampledirs += snippets
imagedirs += images
navigation.landingpage = "Qt Platform Headers"
navigation.cppclassespage = "Qt Platform Headers C++ Classes"

View File

@ -516,7 +516,7 @@ QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine,
}
namespace {
QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match)
QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool useXftConf)
{
switch (hintingPreference) {
case QFont::PreferNoHinting:
@ -529,8 +529,7 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
break;
}
const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
if (services && (services->desktopEnvironment() == "GNOME" || services->desktopEnvironment() == "UNITY")) {
if (useXftConf) {
void *hintStyleResource =
QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
QGuiApplication::primaryScreen());
@ -558,8 +557,17 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
return QFontEngine::HintFull;
}
QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match)
QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool useXftConf)
{
if (useXftConf) {
void *subpixelTypeResource =
QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
QGuiApplication::primaryScreen());
int subpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
if (subpixelType > 0)
return QFontEngine::SubpixelAntialiasingType(subpixelType - 1);
}
int subpixel = FC_RGBA_UNKNOWN;
FcPatternGetInteger(match, FC_RGBA, 0, &subpixel);
@ -596,8 +604,22 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
fid.index = fontfile->indexValue;
bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
bool forcedAntialiasSetting = !antialias;
engine = new QFontEngineFT(fontDef);
const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
bool useXftConf = (services && (services->desktopEnvironment() == "GNOME" || services->desktopEnvironment() == "UNITY"));
if (useXftConf) {
void *antialiasResource =
QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
QGuiApplication::primaryScreen());
int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource));
if (antialiasingEnabled > 0) {
antialias = antialiasingEnabled - 1;
forcedAntialiasSetting = true;
}
}
QFontEngine::GlyphFormat format;
// try and get the pattern
FcPattern *pattern = FcPatternCreate();
@ -622,7 +644,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
FcPattern *match = FcFontMatch(0, pattern, &result);
if (match) {
engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)f.hintingPreference, match));
engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)f.hintingPreference, match, useXftConf));
FcBool fc_autohint;
if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
@ -634,18 +656,16 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
engine->lcdFilterType = lcdFilter;
#endif
if (antialias) {
// If antialiasing is not fully disabled, fontconfig may still disable it on a font match basis.
if (!forcedAntialiasSetting) {
FcBool fc_antialias;
if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) != FcResultMatch)
fc_antialias = true;
antialias = fc_antialias;
if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) == FcResultMatch)
antialias = fc_antialias;
}
if (antialias) {
QFontEngine::SubpixelAntialiasingType subpixelType = QFontEngine::Subpixel_None;
if (!(f.styleStrategy & QFont::NoSubpixelAntialias))
subpixelType = subpixelTypeFromMatch(match);
subpixelType = subpixelTypeFromMatch(match, useXftConf);
engine->subpixelType = subpixelType;
format = (subpixelType == QFontEngine::Subpixel_None)
@ -676,6 +696,20 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal p
QFontDef fontDef = engine->fontDef;
bool forcedAntialiasSetting = false;
const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
bool useXftConf = (services && (services->desktopEnvironment() == "GNOME" || services->desktopEnvironment() == "UNITY"));
if (useXftConf) {
void *antialiasResource =
QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
QGuiApplication::primaryScreen());
int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource));
if (antialiasingEnabled > 0) {
engine->antialias = antialiasingEnabled - 1;
forcedAntialiasSetting = true;
}
}
QFontEngine::GlyphFormat format;
// try and get the pattern
FcPattern *pattern = FcPatternCreate();
@ -693,7 +727,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal p
FcPattern *match = FcFontMatch(0, pattern, &result);
if (match) {
engine->setDefaultHintStyle(defaultHintStyleFromMatch(hintingPreference, match));
engine->setDefaultHintStyle(defaultHintStyleFromMatch(hintingPreference, match, useXftConf));
FcBool fc_autohint;
if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
@ -705,13 +739,14 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal p
engine->lcdFilterType = lcdFilter;
#endif
FcBool fc_antialias;
if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) != FcResultMatch)
fc_antialias = true;
engine->antialias = fc_antialias;
if (!forcedAntialiasSetting) {
FcBool fc_antialias;
if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) == FcResultMatch)
engine->antialias = fc_antialias;
}
if (engine->antialias) {
QFontEngine::SubpixelAntialiasingType subpixelType = subpixelTypeFromMatch(match);
QFontEngine::SubpixelAntialiasingType subpixelType = subpixelTypeFromMatch(match, useXftConf);
engine->subpixelType = subpixelType;
format = subpixelType == QFontEngine::Subpixel_None

View File

@ -211,6 +211,13 @@ void QCoreTextFontDatabase::populateFontDatabase()
QPlatformFontDatabase::registerAliasToFontFamily(familyName, localizedFamilyName);
#endif
}
// Force creating the theme fonts to get the descriptors in m_systemFontDescriptors
if (m_themeFonts.isEmpty())
(void)themeFonts();
Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors)
populateFromDescriptor(fontDesc);
}
void QCoreTextFontDatabase::populateFamily(const QString &familyName)
@ -231,67 +238,76 @@ void QCoreTextFontDatabase::populateFamily(const QString &familyName)
populateFromDescriptor(CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingFonts, i)));
}
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
struct FontDescription {
QCFString familyName;
QCFString styleName;
QString foundryName;
QFont::Weight weight;
QFont::Style style;
QFont::Stretch stretch;
int pixelSize;
bool fixedPitch;
QSupportedWritingSystems writingSystems;
};
static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
{
QString foundryName = QStringLiteral("CoreText");
QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
QCFString styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
QFont::Weight weight = QFont::Normal;
QFont::Style style = QFont::StyleNormal;
QFont::Stretch stretch = QFont::Unstretched;
bool fixedPitch = false;
fd->foundryName = QStringLiteral("CoreText");
fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
fd->weight = QFont::Normal;
fd->style = QFont::StyleNormal;
fd->stretch = QFont::Unstretched;
fd->fixedPitch = false;
if (styles) {
if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
Q_ASSERT(CFNumberIsFloatType(weightValue));
double normalizedWeight;
if (CFNumberGetValue(weightValue, kCFNumberDoubleType, &normalizedWeight)) {
if (normalizedWeight >= 0.62)
weight = QFont::Black;
fd->weight = QFont::Black;
else if (normalizedWeight >= 0.4)
weight = QFont::Bold;
fd->weight = QFont::Bold;
else if (normalizedWeight >= 0.3)
weight = QFont::DemiBold;
fd->weight = QFont::DemiBold;
else if (normalizedWeight == 0.0)
weight = QFont::Normal;
fd->weight = QFont::Normal;
else if (normalizedWeight <= -0.4)
weight = QFont::Light;
fd->weight = QFont::Light;
}
}
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
Q_ASSERT(CFNumberIsFloatType(italic));
double d;
if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
if (d > 0.0)
style = QFont::StyleItalic;
fd->style = QFont::StyleItalic;
}
}
if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) {
int d;
if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
if (d & kCTFontMonoSpaceTrait)
fixedPitch = true;
fd->fixedPitch = true;
if (d & kCTFontExpandedTrait)
stretch = QFont::Expanded;
fd->stretch = QFont::Expanded;
else if (d & kCTFontCondensedTrait)
stretch = QFont::Condensed;
fd->stretch = QFont::Condensed;
}
}
}
int pixelSize = 0;
if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
if (CFNumberIsFloatType(size)) {
double d;
CFNumberGetValue(size, kCFNumberDoubleType, &d);
pixelSize = d;
fd->pixelSize = d;
} else {
CFNumberGetValue(size, kCFNumberIntType, &pixelSize);
CFNumberGetValue(size, kCFNumberIntType, &fd->pixelSize);
}
}
QSupportedWritingSystems writingSystems;
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
CFIndex length = CFArrayGetCount(languages);
for (int i = 1; i < LanguageCount; ++i) {
@ -299,14 +315,24 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
continue;
QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
writingSystems.setSupported(QFontDatabase::WritingSystem(i));
fd->writingSystems.setSupported(QFontDatabase::WritingSystem(i));
}
}
}
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
{
FontDescription fd;
getFontDescription(font, &fd);
populateFromFontDescription(font, fd);
}
void QCoreTextFontDatabase::populateFromFontDescription(CTFontDescriptorRef font, const FontDescription &fd)
{
CFRetain(font);
QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch,
QPlatformFontDatabase::registerFont(fd.familyName, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch,
true /* antialiased */, true /* scalable */,
pixelSize, fixedPitch, writingSystems, (void *) font);
fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font);
}
void QCoreTextFontDatabase::releaseHandle(void *handle)
@ -612,6 +638,113 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData
return families;
}
bool QCoreTextFontDatabase::isPrivateFontFamily(const QString &family) const
{
if (family.startsWith(QLatin1Char('.')))
return true;
return QPlatformFontDatabase::isPrivateFontFamily(family);
}
static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f)
{
switch (f) {
case QPlatformTheme::SystemFont:
return kCTFontSystemFontType;
case QPlatformTheme::MenuFont:
case QPlatformTheme::MenuBarFont:
case QPlatformTheme::MenuItemFont:
return kCTFontMenuItemFontType;
case QPlatformTheme::MessageBoxFont:
return kCTFontEmphasizedSystemFontType;
case QPlatformTheme::LabelFont:
return kCTFontSystemFontType;
case QPlatformTheme::TipLabelFont:
return kCTFontToolTipFontType;
case QPlatformTheme::StatusBarFont:
return kCTFontSystemFontType;
case QPlatformTheme::TitleBarFont:
return kCTFontWindowTitleFontType;
case QPlatformTheme::MdiSubWindowTitleFont:
case QPlatformTheme::DockWidgetTitleFont:
return kCTFontSystemFontType;
case QPlatformTheme::PushButtonFont:
return kCTFontPushButtonFontType;
case QPlatformTheme::CheckBoxFont:
case QPlatformTheme::RadioButtonFont:
return kCTFontSystemFontType;
case QPlatformTheme::ToolButtonFont:
return kCTFontSmallToolbarFontType;
case QPlatformTheme::ItemViewFont:
return kCTFontSystemFontType;
case QPlatformTheme::ListViewFont:
return kCTFontViewsFontType;
case QPlatformTheme::HeaderViewFont:
return kCTFontSmallSystemFontType;
case QPlatformTheme::ListBoxFont:
return kCTFontViewsFontType;
case QPlatformTheme::ComboMenuItemFont:
return kCTFontSystemFontType;
case QPlatformTheme::ComboLineEditFont:
return kCTFontViewsFontType;
case QPlatformTheme::SmallFont:
return kCTFontSmallSystemFontType;
case QPlatformTheme::MiniFont:
return kCTFontMiniSystemFontType;
case QPlatformTheme::FixedFont:
return kCTFontUserFixedPitchFontType;
default:
return kCTFontSystemFontType;
}
}
const QHash<QPlatformTheme::Font, QFont *> &QCoreTextFontDatabase::themeFonts() const
{
if (m_themeFonts.isEmpty()) {
for (long f = QPlatformTheme::SystemFont; f < QPlatformTheme::NFonts; f++) {
QPlatformTheme::Font ft = static_cast<QPlatformTheme::Font>(f);
m_themeFonts.insert(ft, themeFont(ft));
}
}
return m_themeFonts;
}
QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const
{
CTFontUIFontType fontType = fontTypeFromTheme(f);
QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage(fontType, 0.0, NULL);
CTFontDescriptorRef fontDesc = CTFontCopyFontDescriptor(ctFont);
FontDescription fd;
getFontDescription(fontDesc, &fd);
m_systemFontDescriptors.insert(fontDesc);
QFont *font = new QFont(fd.familyName, fd.pixelSize, fd.weight, fd.style == QFont::StyleItalic);
return font;
}
QFont QCoreTextFontDatabase::defaultFont() const
{
if (defaultFontName.isEmpty()) {

Some files were not shown because too many files have changed in this diff Show More