Merge remote-tracking branch 'origin/5.4' into dev
Change-Id: I2811ff0b9d4097f0be60ff16e9664a5060cff23e
This commit is contained in:
commit
2dfc786c26
46
configure
vendored
46
configure
vendored
@ -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
|
||||
|
@ -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 = "©"
|
||||
macro.eacute.HTML = "é"
|
||||
macro.gui = "\\b"
|
||||
macro.hr.HTML = "<hr />"
|
||||
macro.HR.HTML = "<hr />"
|
||||
macro.iacute.HTML = "í"
|
||||
macro.key = "\\b"
|
||||
macro.menu = "\\b"
|
||||
|
@ -305,6 +305,10 @@ headers
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
.subtitle, .small-subtitle {
|
||||
display: block;
|
||||
clear: left;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
33
header.LGPL21
Normal 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
1
src/3rdparty/angle/src/common/platform.h
vendored
1
src/3rdparty/angle/src/common/platform.h
vendored
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
5
src/3rdparty/harfbuzz-ng/src/hb-private.hh
vendored
5
src/3rdparty/harfbuzz-ng/src/hb-private.hh
vendored
@ -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 */
|
||||
|
||||
|
||||
|
23
src/3rdparty/pcre/patches/pcre-r1495.patch
vendored
Normal file
23
src/3rdparty/pcre/patches/pcre-r1495.patch
vendored
Normal 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;
|
||||
|
45
src/3rdparty/pcre/patches/pcre-r1498.patch
vendored
Normal file
45
src/3rdparty/pcre/patches/pcre-r1498.patch
vendored
Normal 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. */
|
27
src/3rdparty/pcre/pcre_compile.c
vendored
27
src/3rdparty/pcre/pcre_compile.c
vendored
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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); });
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 \
|
||||
|
@ -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; };
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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));
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -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()
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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 *))
|
||||
|
@ -198,6 +198,7 @@ class Q_GUI_EXPORT QOpenGLContextPrivate : public QObjectPrivate
|
||||
public:
|
||||
QOpenGLContextPrivate()
|
||||
: qGLContextHandle(0)
|
||||
, qGLContextDeleteFunction(0)
|
||||
, platformGLContext(0)
|
||||
, shareContext(0)
|
||||
, shareGroup(0)
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -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 ®i
|
||||
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 ®i
|
||||
}
|
||||
}
|
||||
|
||||
funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
funcs->glDisable(GL_BLEND);
|
||||
d_ptr->blitter->release();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
291
src/network/ssl/qasn1element.cpp
Normal file
291
src/network/ssl/qasn1element.cpp
Normal 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
|
@ -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
|
@ -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++) {
|
||||
|
@ -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
|
||||
|
266
src/network/ssl/qsslcertificate_qt.cpp
Normal file
266
src/network/ssl/qsslcertificate_qt.cpp
Normal 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
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -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;
|
||||
|
||||
|
184
src/network/ssl/qsslkey_qt.cpp
Normal file
184
src/network/ssl/qsslkey_qt.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -242,6 +242,7 @@ public:
|
||||
void swapRegion(const QRegion ®ion);
|
||||
|
||||
QOpenGLContext *guiGlContext;
|
||||
// true if QGLContext owns the QOpenGLContext (for who deletes who)
|
||||
bool ownContext;
|
||||
|
||||
void setupSharing();
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user