Merge remote-tracking branch 'origin/5.4' into dev
Change-Id: Id4997327cc01bd4bb397a463bdffbd15e80398ef
This commit is contained in:
commit
d572ab1bb4
2
configure
vendored
2
configure
vendored
@ -6636,7 +6636,7 @@ if [ "$CFG_OPENSSL" = "linked" ] && [ "$OPENSSL_LIBS" = "" ]; then
|
||||
echo "For example:"
|
||||
echo " OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto' ./configure -openssl-linked"
|
||||
fi
|
||||
if [ "$CFG_JOURNALD" = "yes" ] || [ "$CFG_SLOG2" = "yes"]; then
|
||||
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,"
|
||||
|
3
doc/global/externalsites.qdocconf
Normal file
3
doc/global/externalsites.qdocconf
Normal file
@ -0,0 +1,3 @@
|
||||
# Include the external websites
|
||||
sourcedirs += externalsites
|
||||
|
@ -8,5 +8,3 @@ examples.imageextensions = "*.png *.jpg *.gif"
|
||||
headers.fileextensions = "*.ch *.h *.h++ *.hh *.hpp *.hxx"
|
||||
sources.fileextensions = "*.c++ *.cc *.cpp *.cxx *.mm *.qml *.qdoc"
|
||||
|
||||
#include the external websites
|
||||
sourcedirs += externalsites
|
||||
|
@ -97,6 +97,10 @@ a[href*="http://"], a[href*="ftp://"], a[href*="https://"] {
|
||||
text-height: 24px;
|
||||
}
|
||||
|
||||
.flags:target {
|
||||
background-color: #FFFFD6;
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------
|
||||
NOTE styles
|
||||
@ -327,6 +331,10 @@ h2, p.h2 {
|
||||
max-width: 99%;
|
||||
}
|
||||
|
||||
h2:target {
|
||||
background-color: #F2F3D4;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: 500 14px/1.2 Arial;
|
||||
font-weight: 100;
|
||||
@ -353,6 +361,10 @@ h3.fn, span.fn {
|
||||
margin-top: 45px;
|
||||
}
|
||||
|
||||
h3.fn:target {
|
||||
background-color: #F6F6D6;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #1A1A1A
|
||||
}
|
||||
@ -413,6 +425,10 @@ table, pre {
|
||||
color: #66666E;
|
||||
}
|
||||
|
||||
table tr:target {
|
||||
background-color: #F6F6D6;
|
||||
}
|
||||
|
||||
table thead {
|
||||
text-align: left;
|
||||
padding-left: 20px;
|
||||
|
@ -48,6 +48,10 @@ links
|
||||
text-height: 24px;
|
||||
}
|
||||
|
||||
.flags:target {
|
||||
background-color: #FFFFD6;
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------
|
||||
NOTE styles
|
||||
@ -204,6 +208,10 @@ h2, p.h2 {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h2:target {
|
||||
background-color: #F2F3D4;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: 500 14px/1.2 Arial;
|
||||
font-weight: 100;
|
||||
@ -212,6 +220,10 @@ h3 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
h3.fn:target {
|
||||
background-color: #F6F6D6;
|
||||
}
|
||||
|
||||
h3.fn, span.fn {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
@ -293,6 +305,10 @@ table, pre {
|
||||
color: #66666E;
|
||||
}
|
||||
|
||||
table tr:target {
|
||||
background-color: #F6F6D6;
|
||||
}
|
||||
|
||||
table thead {
|
||||
text-align: left;
|
||||
padding-left: 20px;
|
||||
|
@ -147,6 +147,21 @@ void Renderer::render()
|
||||
f->glViewport(0, 0, viewSize.width() * surface->devicePixelRatio(), viewSize.height() * surface->devicePixelRatio());
|
||||
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
f->glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
|
||||
f->glFrontFace(GL_CW);
|
||||
f->glCullFace(GL_FRONT);
|
||||
f->glEnable(GL_CULL_FACE);
|
||||
f->glEnable(GL_DEPTH_TEST);
|
||||
|
||||
m_program->bind();
|
||||
m_vbo.bind();
|
||||
|
||||
m_program->enableAttributeArray(vertexAttr);
|
||||
m_program->enableAttributeArray(normalAttr);
|
||||
m_program->setAttributeBuffer(vertexAttr, GL_FLOAT, 0, 3);
|
||||
const int verticesSize = vertices.count() * 3 * sizeof(GLfloat);
|
||||
m_program->setAttributeBuffer(normalAttr, GL_FLOAT, verticesSize, 3);
|
||||
|
||||
QMatrix4x4 modelview;
|
||||
modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
|
||||
modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
|
||||
@ -212,18 +227,6 @@ void Renderer::initialize()
|
||||
m_vbo.allocate(verticesSize * 2);
|
||||
m_vbo.write(0, vertices.constData(), verticesSize);
|
||||
m_vbo.write(verticesSize, normals.constData(), verticesSize);
|
||||
|
||||
QOpenGLFunctions *f = m_context->functions();
|
||||
f->glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
|
||||
f->glFrontFace(GL_CW);
|
||||
f->glCullFace(GL_FRONT);
|
||||
f->glEnable(GL_CULL_FACE);
|
||||
f->glEnable(GL_DEPTH_TEST);
|
||||
|
||||
m_program->enableAttributeArray(vertexAttr);
|
||||
m_program->enableAttributeArray(normalAttr);
|
||||
m_program->setAttributeBuffer(vertexAttr, GL_FLOAT, 0, 3);
|
||||
m_program->setAttributeBuffer(normalAttr, GL_FLOAT, verticesSize, 3);
|
||||
}
|
||||
|
||||
void Renderer::createGeometry()
|
||||
|
@ -970,3 +970,15 @@ int main() { return featureFunction(); }
|
||||
# <project root>/project.pro
|
||||
qtCompileTest(test)
|
||||
#! [182]
|
||||
|
||||
#! [183]
|
||||
# <project root>/project.pro
|
||||
QMAKE_SONAME_PREFIX = @rpath
|
||||
#! [183]
|
||||
|
||||
#! [184]
|
||||
# <project root>/project.pro
|
||||
QMAKE_SONAME_PREFIX = @executable_path/../Frameworks
|
||||
QMAKE_SONAME_PREFIX = @loader_path/Frameworks
|
||||
QMAKE_SONAME_PREFIX = /Library/Frameworks
|
||||
#! [184]
|
||||
|
@ -2071,6 +2071,39 @@
|
||||
qmake or \l{#QMAKESPEC}{qmake.conf} and rarely
|
||||
needs to be modified.
|
||||
|
||||
\section1 QMAKE_SONAME_PREFIX
|
||||
|
||||
If defined, the value of this variable is used as a path to be prepended to
|
||||
the built shared library's \c SONAME identifier. The \c SONAME is the
|
||||
identifier that the dynamic linker will later use to reference the library.
|
||||
In general this reference may be a library name or full library path. On OS
|
||||
X and iOS, the path may be specified relatively using the following
|
||||
placeholders:
|
||||
|
||||
\table
|
||||
\header \li Placeholder \li Effect
|
||||
\row \li @rpath
|
||||
\li Expands to paths defined by LC_RPATH mach-o commands in
|
||||
the current process executable or the referring libraries.
|
||||
\row \li @executable_path
|
||||
\li Expands to the current process executable location.
|
||||
\row \li @loader_path
|
||||
\li Expands to the referring executable or library location.
|
||||
\endtable
|
||||
|
||||
In most cases, using \c @rpath is sufficient and recommended:
|
||||
|
||||
\snippet code/doc_src_qmake-manual.pro 183
|
||||
|
||||
However, the prefix may be also specified using different placeholders, or
|
||||
an absolute path, such as one of the following:
|
||||
|
||||
\snippet code/doc_src_qmake-manual.pro 184
|
||||
|
||||
For more information, see
|
||||
\l{https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/dyld.1.html}{dyld}
|
||||
documentation on dynamic library install names.
|
||||
|
||||
\section1 QMAKE_TARGET
|
||||
|
||||
Specifies the name of the project target. The value of this
|
||||
|
@ -1265,6 +1265,13 @@ void UnixMakefileGenerator::init2()
|
||||
if(!instpath.endsWith(Option::dir_sep))
|
||||
instpath += Option::dir_sep;
|
||||
soname.prepend(instpath);
|
||||
} else if (!project->isEmpty("QMAKE_SONAME_PREFIX")) {
|
||||
QString sonameprefix = project->first("QMAKE_SONAME_PREFIX").toQString();
|
||||
if (!sonameprefix.startsWith('@') && !sonameprefix.startsWith('$'))
|
||||
sonameprefix = Option::fixPathToTargetOS(sonameprefix, false);
|
||||
if (!sonameprefix.endsWith(Option::dir_sep))
|
||||
sonameprefix += Option::dir_sep;
|
||||
soname.prepend(sonameprefix);
|
||||
}
|
||||
project->values("QMAKE_LFLAGS_SONAME").first() += escapeFilePath(soname);
|
||||
}
|
||||
|
2
src/3rdparty/angle/src/common/platform.h
vendored
2
src/3rdparty/angle/src/common/platform.h
vendored
@ -59,8 +59,10 @@
|
||||
# include <d3d10.h>
|
||||
# include <d3d11.h>
|
||||
# include <dxgi.h>
|
||||
# if _MSC_VER >= 1700
|
||||
# include <dxgi1_2.h>
|
||||
# include <d3dcompiler.h>
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# undef near
|
||||
|
4
src/3rdparty/angle/src/libGLESv2/Context.cpp
vendored
4
src/3rdparty/angle/src/libGLESv2/Context.cpp
vendored
@ -368,7 +368,7 @@ void Context::deleteFenceSync(GLsync fenceSync)
|
||||
// wait commands finish. However, since the name becomes invalid, we cannot query the fence,
|
||||
// and since our API is currently designed for being called from a single thread, we can delete
|
||||
// the fence immediately.
|
||||
mResourceManager->deleteFenceSync(reinterpret_cast<GLuint>(fenceSync));
|
||||
mResourceManager->deleteFenceSync(uintptr_t(fenceSync));
|
||||
}
|
||||
|
||||
void Context::deleteVertexArray(GLuint vertexArray)
|
||||
@ -474,7 +474,7 @@ Renderbuffer *Context::getRenderbuffer(GLuint handle)
|
||||
|
||||
FenceSync *Context::getFenceSync(GLsync handle) const
|
||||
{
|
||||
return mResourceManager->getFenceSync(reinterpret_cast<GLuint>(handle));
|
||||
return mResourceManager->getFenceSync(uintptr_t(handle));
|
||||
}
|
||||
|
||||
VertexArray *Context::getVertexArray(GLuint handle) const
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
|
||||
#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
|
||||
|
||||
#if defined(__MINGW32__) && !defined(D3D11_MAP_FLAG_DO_NOT_WAIT)
|
||||
# define D3D11_MAP_FLAG_DO_NOT_WAIT 0x100000L
|
||||
#endif
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
||||
|
@ -116,8 +116,8 @@ Clear11::Clear11(Renderer11 *renderer)
|
||||
|
||||
mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat);
|
||||
if (mRenderer->isLevel9()) {
|
||||
mUintClearShader = { 0 };
|
||||
mIntClearShader = { 0 };
|
||||
memset(&mUintClearShader, 0, sizeof(ClearShader));
|
||||
memset(&mIntClearShader, 0, sizeof(ClearShader));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,14 @@
|
||||
#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
|
||||
#include "libGLESv2/main.h"
|
||||
|
||||
#if defined(__MINGW32__) // Provide undefined struct
|
||||
typedef struct D3D11_QUERY_DATA_SO_STATISTICS
|
||||
{
|
||||
UINT64 NumPrimitivesWritten;
|
||||
UINT64 PrimitivesStorageNeeded;
|
||||
} D3D11_QUERY_DATA_SO_STATISTICS;
|
||||
#endif
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
||||
|
@ -51,4 +51,4 @@ class RenderTarget11 : public RenderTarget
|
||||
|
||||
}
|
||||
|
||||
#endif LIBGLESV2_RENDERER_RENDERTARGET11_H_
|
||||
#endif // LIBGLESV2_RENDERER_RENDERTARGET11_H_
|
||||
|
@ -49,6 +49,31 @@
|
||||
#define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1
|
||||
#endif
|
||||
|
||||
#ifndef D3D11_PS_INPUT_REGISTER_COUNT
|
||||
# define D3D11_PS_INPUT_REGISTER_COUNT 32
|
||||
#endif
|
||||
#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT
|
||||
# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32
|
||||
#endif
|
||||
#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT
|
||||
# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14
|
||||
#endif
|
||||
#ifndef D3D11_SO_BUFFER_SLOT_COUNT
|
||||
# define D3D11_SO_BUFFER_SLOT_COUNT 4
|
||||
#endif
|
||||
#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT
|
||||
# define D3D10_1_SO_BUFFER_SLOT_COUNT 4
|
||||
#endif
|
||||
#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT
|
||||
# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096
|
||||
#endif
|
||||
#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP
|
||||
# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32
|
||||
#endif
|
||||
#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP
|
||||
# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32
|
||||
#endif
|
||||
|
||||
namespace rx
|
||||
{
|
||||
static const DXGI_FORMAT RenderTargetFormats[] =
|
||||
@ -275,7 +300,7 @@ EGLint Renderer11::initialize()
|
||||
}
|
||||
|
||||
// Disable some spurious D3D11 debug warnings to prevent them from flooding the output log
|
||||
#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG)
|
||||
#if !defined(__MINGW32__) && defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG)
|
||||
ID3D11InfoQueue *infoQueue;
|
||||
result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue);
|
||||
|
||||
|
@ -261,7 +261,7 @@ class Renderer11 : public Renderer
|
||||
};
|
||||
MultisampleSupportInfo getMultisampleSupportInfo(DXGI_FORMAT format);
|
||||
|
||||
typedef std::unordered_map<DXGI_FORMAT, MultisampleSupportInfo> MultisampleSupportMap;
|
||||
typedef std::unordered_map<GLenum, MultisampleSupportInfo> MultisampleSupportMap;
|
||||
MultisampleSupportMap mMultisampleSupportMap;
|
||||
|
||||
unsigned int mMaxSupportedSamples;
|
||||
|
@ -12,6 +12,40 @@
|
||||
#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY
|
||||
# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2
|
||||
#endif
|
||||
#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT
|
||||
# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1
|
||||
#endif
|
||||
#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT
|
||||
# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4
|
||||
#endif
|
||||
#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION
|
||||
# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512
|
||||
#endif
|
||||
#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION
|
||||
# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096
|
||||
#endif
|
||||
#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
||||
# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048
|
||||
#endif
|
||||
#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
|
||||
# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256
|
||||
#endif
|
||||
#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
||||
# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096
|
||||
#endif
|
||||
#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION
|
||||
# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384
|
||||
#endif
|
||||
#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION
|
||||
# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048
|
||||
#endif
|
||||
#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
|
||||
# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048
|
||||
#endif
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
||||
@ -273,7 +307,9 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0: return true;
|
||||
@ -291,7 +327,9 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@ -311,7 +349,9 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0: return true;
|
||||
@ -331,7 +371,9 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
@ -349,7 +391,9 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
@ -372,7 +416,9 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
@ -390,7 +436,9 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
|
||||
|
||||
// FIXME(geofflang): Work around NVIDIA driver bug by repacking buffers
|
||||
@ -409,7 +457,9 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@ -427,7 +477,9 @@ static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@ -445,7 +497,9 @@ static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@ -463,7 +517,9 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@ -481,7 +537,9 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@ -622,7 +680,7 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo
|
||||
|
||||
HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
#if !defined(__MINGW32__) && defined(_DEBUG)
|
||||
return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name);
|
||||
#else
|
||||
return S_OK;
|
||||
|
@ -45,6 +45,7 @@ package org.qtproject.qt5.android;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Configuration;
|
||||
@ -110,6 +111,7 @@ public class QtActivityDelegate
|
||||
private String m_mainLib;
|
||||
private long m_metaState;
|
||||
private int m_lastChar = 0;
|
||||
private int m_softInputMode = 0;
|
||||
private boolean m_fullScreen = false;
|
||||
private boolean m_started = false;
|
||||
private HashMap<Integer, QtSurface> m_surfaces = null;
|
||||
@ -246,10 +248,12 @@ public class QtActivityDelegate
|
||||
if (m_imm == null)
|
||||
return;
|
||||
|
||||
if (height > m_layout.getHeight() * 2 / 3)
|
||||
m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
else
|
||||
if (m_softInputMode == 0 && height > m_layout.getHeight() * 2 / 3)
|
||||
m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
else if (m_softInputMode == 0)
|
||||
m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
|
||||
else
|
||||
m_activity.getWindow().setSoftInputMode(m_softInputMode);
|
||||
|
||||
int initialCapsMode = 0;
|
||||
int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||
@ -474,6 +478,12 @@ public class QtActivityDelegate
|
||||
else
|
||||
m_applicationParameters = "";
|
||||
|
||||
try {
|
||||
m_softInputMode = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), 0).softInputMode;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1085,11 +1095,14 @@ public class QtActivityDelegate
|
||||
Log.e(QtNative.QtTAG, "Surface " + id +" not found!");
|
||||
}
|
||||
|
||||
if (view == null)
|
||||
return;
|
||||
|
||||
// Keep last frame in stack until it is replaced to get correct
|
||||
// shutdown transition
|
||||
if (m_surfaces.size() == 0 && m_nativeViews.size() == 0) {
|
||||
m_dummyView = view;
|
||||
} else if (view != null) {
|
||||
} else {
|
||||
m_layout.removeView(view);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,5 @@ SUBDIRS += src
|
||||
# 2) If we made a 'QtANGLE' module, the include directory would be flattened which won't work since
|
||||
# we need to support "#include <GLES2/gl2.h>"
|
||||
CONFIG += minimal_syncqt
|
||||
QMAKE_SYNCQT_OPTIONS = -module QtANGLE/KHR -module QtANGLE/EGL -module QtANGLE/GLES2 -version none
|
||||
angle_d3d11: QMAKE_SYNCQT_OPTIONS += -module QtANGLE/GLES3
|
||||
QMAKE_SYNCQT_OPTIONS = -module QtANGLE/KHR -module QtANGLE/EGL -module QtANGLE/GLES2 -module QtANGLE/GLES3 -version none
|
||||
load(qt_module_headers)
|
||||
|
203
src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch
Normal file
203
src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch
Normal file
@ -0,0 +1,203 @@
|
||||
From bfcd8298f9ba074116de434bf252ea95be968a20 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Knight <andrew.knight@digia.com>
|
||||
Date: Mon, 1 Sep 2014 12:11:17 +0300
|
||||
Subject: [PATCH] ANGLE: Fix -angle-d3d11 on MSVC2010
|
||||
|
||||
Allow the D3D11 renderer to build with the June 2010 DirectX SDK.
|
||||
|
||||
Change-Id: I2343acedab16845d6a0d4a53cf3145f583efc4a7
|
||||
---
|
||||
src/3rdparty/angle/src/common/platform.h | 2 +
|
||||
.../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 4 +-
|
||||
.../renderer/d3d/d3d11/renderer11_utils.cpp | 49 ++++++++++++++++++++++
|
||||
3 files changed, 53 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h
|
||||
index cedc6f2..44c5c7c 100644
|
||||
--- a/src/3rdparty/angle/src/common/platform.h
|
||||
+++ b/src/3rdparty/angle/src/common/platform.h
|
||||
@@ -59,8 +59,10 @@
|
||||
# include <d3d10.h>
|
||||
# include <d3d11.h>
|
||||
# include <dxgi.h>
|
||||
+# if _MSC_VER >= 1700
|
||||
# include <dxgi1_2.h>
|
||||
# include <d3dcompiler.h>
|
||||
+# endif
|
||||
# endif
|
||||
|
||||
# undef near
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
|
||||
index 8db5ea2..5121950 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp
|
||||
@@ -116,8 +116,8 @@ Clear11::Clear11(Renderer11 *renderer)
|
||||
|
||||
mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat);
|
||||
if (mRenderer->isLevel9()) {
|
||||
- mUintClearShader = { 0 };
|
||||
- mIntClearShader = { 0 };
|
||||
+ memset(&mUintClearShader, 0, sizeof(ClearShader));
|
||||
+ memset(&mIntClearShader, 0, sizeof(ClearShader));
|
||||
return;
|
||||
}
|
||||
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
index d3d135f..8e0c21b 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
@@ -12,6 +12,31 @@
|
||||
#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
+#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY
|
||||
+# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2
|
||||
+#endif
|
||||
+#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT
|
||||
+# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1
|
||||
+#endif
|
||||
+#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT
|
||||
+# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4
|
||||
+#endif
|
||||
+#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION
|
||||
+# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512
|
||||
+#endif
|
||||
+#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION
|
||||
+# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096
|
||||
+#endif
|
||||
+#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
||||
+# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048
|
||||
+#endif
|
||||
+#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
|
||||
+# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256
|
||||
+#endif
|
||||
+#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
||||
+# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096
|
||||
+#endif
|
||||
+
|
||||
namespace rx
|
||||
{
|
||||
|
||||
@@ -273,7 +298,9 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0: return true;
|
||||
@@ -291,7 +318,9 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@@ -311,7 +340,9 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0: return true;
|
||||
@@ -331,7 +362,9 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
@@ -349,7 +382,9 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
@@ -372,7 +407,9 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel)
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
@@ -390,7 +427,9 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel
|
||||
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
|
||||
|
||||
// FIXME(geofflang): Work around NVIDIA driver bug by repacking buffers
|
||||
@@ -409,7 +448,9 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@@ -427,7 +468,9 @@ static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@@ -445,7 +488,9 @@ static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@@ -463,7 +508,9 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
@@ -481,7 +528,9 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel)
|
||||
{
|
||||
switch (featureLevel)
|
||||
{
|
||||
+#if _MSC_VER >= 1700
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
+#endif
|
||||
case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
--
|
||||
1.9.0.msysgit.0
|
||||
|
@ -0,0 +1,175 @@
|
||||
From ac4e9bb72ca22fd39bfc43f087108694db2ae8ac Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Knight <andrew.knight@digia.com>
|
||||
Date: Thu, 4 Sep 2014 15:32:17 +0300
|
||||
Subject: [PATCH] ANGLE: Fix compilation with MinGW + D3D11
|
||||
|
||||
Provide workarounds for things GCC doesn't like, and define a number
|
||||
of macros not found in the MinGW headers.
|
||||
|
||||
Change-Id: I254c208209c0071fae5efb6727f2b3cfd5542da6
|
||||
---
|
||||
src/3rdparty/angle/src/libGLESv2/Context.cpp | 4 ++--
|
||||
.../src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp | 4 ++++
|
||||
.../src/libGLESv2/renderer/d3d/d3d11/Query11.cpp | 8 +++++++
|
||||
.../libGLESv2/renderer/d3d/d3d11/RenderTarget11.h | 2 +-
|
||||
.../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 27 +++++++++++++++++++++-
|
||||
.../src/libGLESv2/renderer/d3d/d3d11/Renderer11.h | 2 +-
|
||||
.../renderer/d3d/d3d11/renderer11_utils.cpp | 11 ++++++++-
|
||||
7 files changed, 52 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp
|
||||
index 8201acd..99df85b 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/Context.cpp
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp
|
||||
@@ -368,7 +368,7 @@ void Context::deleteFenceSync(GLsync fenceSync)
|
||||
// wait commands finish. However, since the name becomes invalid, we cannot query the fence,
|
||||
// and since our API is currently designed for being called from a single thread, we can delete
|
||||
// the fence immediately.
|
||||
- mResourceManager->deleteFenceSync(reinterpret_cast<GLuint>(fenceSync));
|
||||
+ mResourceManager->deleteFenceSync(uintptr_t(fenceSync));
|
||||
}
|
||||
|
||||
void Context::deleteVertexArray(GLuint vertexArray)
|
||||
@@ -474,7 +474,7 @@ Renderbuffer *Context::getRenderbuffer(GLuint handle)
|
||||
|
||||
FenceSync *Context::getFenceSync(GLsync handle) const
|
||||
{
|
||||
- return mResourceManager->getFenceSync(reinterpret_cast<GLuint>(handle));
|
||||
+ return mResourceManager->getFenceSync(uintptr_t(handle));
|
||||
}
|
||||
|
||||
VertexArray *Context::getVertexArray(GLuint handle) const
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp
|
||||
index 352da96..1301124 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
|
||||
#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
|
||||
|
||||
+#if defined(__MINGW32__) && !defined(D3D11_MAP_FLAG_DO_NOT_WAIT)
|
||||
+# define D3D11_MAP_FLAG_DO_NOT_WAIT 0x100000L
|
||||
+#endif
|
||||
+
|
||||
namespace rx
|
||||
{
|
||||
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp
|
||||
index 17cf5ca..e5e0032 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp
|
||||
@@ -12,6 +12,14 @@
|
||||
#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
|
||||
#include "libGLESv2/main.h"
|
||||
|
||||
+#if defined(__MINGW32__) // Provide undefined struct
|
||||
+typedef struct D3D11_QUERY_DATA_SO_STATISTICS
|
||||
+{
|
||||
+ UINT64 NumPrimitivesWritten;
|
||||
+ UINT64 PrimitivesStorageNeeded;
|
||||
+} D3D11_QUERY_DATA_SO_STATISTICS;
|
||||
+#endif
|
||||
+
|
||||
namespace rx
|
||||
{
|
||||
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h
|
||||
index ba9f76e..8218295 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h
|
||||
@@ -51,4 +51,4 @@ class RenderTarget11 : public RenderTarget
|
||||
|
||||
}
|
||||
|
||||
-#endif LIBGLESV2_RENDERER_RENDERTARGET11_H_
|
||||
+#endif // LIBGLESV2_RENDERER_RENDERTARGET11_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 651b065..3ba0cc7 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
|
||||
@@ -49,6 +49,31 @@
|
||||
#define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1
|
||||
#endif
|
||||
|
||||
+#ifndef D3D11_PS_INPUT_REGISTER_COUNT
|
||||
+# define D3D11_PS_INPUT_REGISTER_COUNT 32
|
||||
+#endif
|
||||
+#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT
|
||||
+# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32
|
||||
+#endif
|
||||
+#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT
|
||||
+# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14
|
||||
+#endif
|
||||
+#ifndef D3D11_SO_BUFFER_SLOT_COUNT
|
||||
+# define D3D11_SO_BUFFER_SLOT_COUNT 4
|
||||
+#endif
|
||||
+#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT
|
||||
+# define D3D10_1_SO_BUFFER_SLOT_COUNT 4
|
||||
+#endif
|
||||
+#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT
|
||||
+# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096
|
||||
+#endif
|
||||
+#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP
|
||||
+# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32
|
||||
+#endif
|
||||
+#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP
|
||||
+# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32
|
||||
+#endif
|
||||
+
|
||||
namespace rx
|
||||
{
|
||||
static const DXGI_FORMAT RenderTargetFormats[] =
|
||||
@@ -275,7 +300,7 @@ EGLint Renderer11::initialize()
|
||||
}
|
||||
|
||||
// Disable some spurious D3D11 debug warnings to prevent them from flooding the output log
|
||||
-#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG)
|
||||
+#if !defined(__MINGW32__) && defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG)
|
||||
ID3D11InfoQueue *infoQueue;
|
||||
result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue);
|
||||
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
|
||||
index a31f15e..b54f75d 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
|
||||
@@ -261,7 +261,7 @@ class Renderer11 : public Renderer
|
||||
};
|
||||
MultisampleSupportInfo getMultisampleSupportInfo(DXGI_FORMAT format);
|
||||
|
||||
- typedef std::unordered_map<DXGI_FORMAT, MultisampleSupportInfo> MultisampleSupportMap;
|
||||
+ typedef std::unordered_map<GLenum, MultisampleSupportInfo> MultisampleSupportMap;
|
||||
MultisampleSupportMap mMultisampleSupportMap;
|
||||
|
||||
unsigned int mMaxSupportedSamples;
|
||||
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
index 8e0c21b..d914a82 100644
|
||||
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
|
||||
@@ -36,6 +36,15 @@
|
||||
#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION
|
||||
# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096
|
||||
#endif
|
||||
+#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION
|
||||
+# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384
|
||||
+#endif
|
||||
+#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION
|
||||
+# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048
|
||||
+#endif
|
||||
+#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
|
||||
+# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048
|
||||
+#endif
|
||||
|
||||
namespace rx
|
||||
{
|
||||
@@ -671,7 +680,7 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo
|
||||
|
||||
HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name)
|
||||
{
|
||||
-#if defined(_DEBUG)
|
||||
+#if !defined(__MINGW32__) && defined(_DEBUG)
|
||||
return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name);
|
||||
#else
|
||||
return S_OK;
|
||||
--
|
||||
1.9.0.msysgit.0
|
||||
|
@ -37,7 +37,9 @@ DEFINES += _WINDOWS \
|
||||
NOMINMAX \
|
||||
WIN32_LEAN_AND_MEAN=1
|
||||
|
||||
!winrt: DEFINES += ANGLE_ENABLE_D3D9
|
||||
!winrt: DEFINES += ANGLE_ENABLE_D3D9 ANGLE_SKIP_DXGI_1_2_CHECK
|
||||
|
||||
CONFIG += angle_d3d11 # Remove to disable D3D11 renderer
|
||||
|
||||
angle_d3d11 {
|
||||
DEFINES += ANGLE_ENABLE_D3D11 ANGLE_DEFAULT_D3D11=1
|
||||
|
@ -1,10 +1,7 @@
|
||||
CONFIG += installed
|
||||
include(../common/common.pri)
|
||||
|
||||
angle_d3d11: \
|
||||
LIBS_PRIVATE += -ld3d11
|
||||
!winrt: \
|
||||
LIBS_PRIVATE += -ld3d9
|
||||
winrt: LIBS_PRIVATE += -ld3d11
|
||||
|
||||
LIBS_PRIVATE += -ldxguid -L$$QT_BUILD_TREE/lib -l$$qtLibraryTarget(libGLESv2)
|
||||
|
||||
|
@ -4,12 +4,10 @@ include(../common/common.pri)
|
||||
INCLUDEPATH += $$OUT_PWD/.. $$ANGLE_DIR/src/libGLESv2
|
||||
|
||||
# Remember to adapt tools/configure/configureapp.cpp if the Direct X version changes.
|
||||
angle_d3d11: \
|
||||
LIBS_PRIVATE += -ldxgi -ld3d11
|
||||
!winrt: \
|
||||
LIBS_PRIVATE += -ld3d9
|
||||
winrt: \
|
||||
LIBS_PRIVATE += -ld3dcompiler
|
||||
LIBS_PRIVATE += -ld3dcompiler -ldxgi -ld3d11
|
||||
|
||||
LIBS_PRIVATE += -ldxguid
|
||||
|
||||
|
@ -83,10 +83,10 @@
|
||||
# define ARCH_PROCESSOR "unknown"
|
||||
#endif
|
||||
|
||||
// endinanness
|
||||
#if defined(Q_LITTLE_ENDIAN)
|
||||
// endianness
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
# define ARCH_ENDIANNESS "little_endian"
|
||||
#elif defined(Q_BIG_ENDIAN)
|
||||
#elif Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
# define ARCH_ENDIANNESS "big_endian"
|
||||
#endif
|
||||
|
||||
|
@ -742,7 +742,6 @@
|
||||
# define Q_COMPILER_DEFAULT_MEMBERS
|
||||
# define Q_COMPILER_DELETE_MEMBERS
|
||||
# define Q_COMPILER_EXTERN_TEMPLATES
|
||||
# define Q_COMPILER_INITIALIZER_LISTS
|
||||
# define Q_COMPILER_UNIFORM_INIT
|
||||
# define Q_COMPILER_UNICODE_STRINGS
|
||||
# define Q_COMPILER_VARIADIC_TEMPLATES
|
||||
@ -750,6 +749,9 @@
|
||||
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
|
||||
/* C++11 features supported in GCC 4.5: */
|
||||
# define Q_COMPILER_EXPLICIT_CONVERSIONS
|
||||
/* GCC 4.4 implements initializer_list but does not define typedefs required
|
||||
* by the standard. */
|
||||
# define Q_COMPILER_INITIALIZER_LISTS
|
||||
# define Q_COMPILER_LAMBDA
|
||||
# define Q_COMPILER_RAW_STRINGS
|
||||
# endif
|
||||
|
@ -310,7 +310,7 @@ struct DefinedTypesFilter {
|
||||
name to a type so that it can be created and destructed
|
||||
dynamically at run-time. Declare new types with Q_DECLARE_METATYPE()
|
||||
to make them available to QVariant and other template-based functions.
|
||||
Call qRegisterMetaType() to make type available to non-template based
|
||||
Call qRegisterMetaType() to make types available to non-template based
|
||||
functions, such as the queued signal and slot connections.
|
||||
|
||||
Any class or struct that has a public default
|
||||
|
@ -119,9 +119,11 @@ static EvaluationStatus qt_eval_is_supported()
|
||||
|
||||
static int qt_eval_days_left()
|
||||
{
|
||||
const char *expiry_date = const_cast<const char*>(qt_eval_expiry_date + 12);
|
||||
|
||||
QDate today = QDate::currentDate();
|
||||
QDate build = QLibraryInfo::buildDate();
|
||||
return qMax<qint64>(-1, today.daysTo(build) + 30);
|
||||
QDate lastday = QDate::fromString(QString::fromLatin1(expiry_date), Qt::ISODate);
|
||||
return today.daysTo(lastday);
|
||||
}
|
||||
|
||||
static bool qt_eval_is_expired()
|
||||
|
@ -749,7 +749,6 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde
|
||||
break;
|
||||
}
|
||||
if (state != Invalid) {
|
||||
QString str = text;
|
||||
text.replace(index, used, sectiontext.left(used));
|
||||
}
|
||||
break; }
|
||||
@ -770,7 +769,6 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde
|
||||
|
||||
if (num != -1) {
|
||||
state = (used == sectiontext.size() ? Acceptable : Intermediate);
|
||||
QString str = text;
|
||||
text.replace(index, used, sectiontext.left(used));
|
||||
} else {
|
||||
state = Intermediate;
|
||||
|
@ -201,6 +201,17 @@ QT_BEGIN_NAMESPACE
|
||||
\sa clockType(), isMonotonic()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QElapsedTimer::QElapsedTimer()
|
||||
\since 5.4
|
||||
|
||||
Constructs an invalid QElapsedTimer. A timer becomes valid once it has been
|
||||
started.
|
||||
|
||||
\sa isValid(), start()
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn bool QElapsedTimer::operator ==(const QElapsedTimer &other) const
|
||||
|
||||
@ -230,8 +241,8 @@ void QElapsedTimer::invalidate() Q_DECL_NOTHROW
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c false if this object was invalidated by a call to invalidate() and
|
||||
has not been restarted since.
|
||||
Returns \c false if the timer has never been started or invalidated by a
|
||||
call to invalidate().
|
||||
|
||||
\sa invalidate(), start(), restart()
|
||||
*/
|
||||
|
@ -57,6 +57,13 @@ public:
|
||||
MachAbsoluteTime,
|
||||
PerformanceCounter
|
||||
};
|
||||
|
||||
Q_DECL_CONSTEXPR QElapsedTimer()
|
||||
: t1(Q_INT64_C(0x8000000000000000))
|
||||
, t2(Q_INT64_C(0x8000000000000000))
|
||||
{
|
||||
}
|
||||
|
||||
static ClockType clockType() Q_DECL_NOTHROW;
|
||||
static bool isMonotonic() Q_DECL_NOTHROW;
|
||||
|
||||
|
@ -87,6 +87,8 @@ void QElapsedTimer::start() Q_DECL_NOTHROW
|
||||
and then starting the timer again with start(), but it does so in one
|
||||
single operation, avoiding the need to obtain the clock value twice.
|
||||
|
||||
Restarting the timer makes it valid again.
|
||||
|
||||
The following example illustrates how to use this function to calibrate a
|
||||
parameter to a slow operation (for example, an iteration count) so that
|
||||
this operation takes at least 250 milliseconds:
|
||||
|
@ -284,7 +284,7 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
Returns \c true if the rectangle is valid, otherwise returns \c false.
|
||||
|
||||
A valid rectangle has a left() < right() and top() <
|
||||
A valid rectangle has a left() <= right() and top() <=
|
||||
bottom(). Note that non-trivial operations like intersections are
|
||||
not defined for invalid rectangles. A valid rectangle is not empty
|
||||
(i.e., isValid() == !isEmpty()).
|
||||
|
@ -1896,17 +1896,66 @@ QDebug operator<<(QDebug d, const QAccessibleEvent &ev)
|
||||
The \a endOffset is the first character that will not be returned.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\internal
|
||||
Helper for finding line breaks in textBeforeOffset/textAtOffset/textAfterOffset.
|
||||
\a beforeAtAfter is the line we look for. -1 for before, 0 for at and 1 for after.
|
||||
*/
|
||||
static QString textLineBoundary(int beforeAtAfter, const QString &text, int offset, int *startOffset, int *endOffset)
|
||||
{
|
||||
Q_ASSERT(beforeAtAfter >= -1 && beforeAtAfter <= 1);
|
||||
Q_ASSERT(*startOffset == -1 && *endOffset == -1);
|
||||
int length = text.length();
|
||||
Q_ASSERT(offset >= 0 && offset <= length);
|
||||
|
||||
// move offset into the right range (if asking for line before or after
|
||||
if (beforeAtAfter == 1) {
|
||||
offset = text.indexOf(QChar::LineFeed, qMin(offset, length - 1));
|
||||
if (offset < 0)
|
||||
return QString(); // after the last line comes nothing
|
||||
++offset; // move after the newline
|
||||
} else if (beforeAtAfter == -1) {
|
||||
offset = text.lastIndexOf(QChar::LineFeed, qMax(offset - 1, 0));
|
||||
if (offset < 0)
|
||||
return QString(); // before first line comes nothing
|
||||
}
|
||||
|
||||
if (offset > 0)
|
||||
*startOffset = text.lastIndexOf(QChar::LineFeed, offset - 1);
|
||||
++*startOffset; // move to the char after the newline (0 if lastIndexOf returned -1)
|
||||
|
||||
*endOffset = text.indexOf(QChar::LineFeed, qMin(offset, length - 1)) + 1; // include newline char
|
||||
if (*endOffset <= 0 || *endOffset > length)
|
||||
*endOffset = length; // if the text doesn't end with a newline it ends at length
|
||||
|
||||
return text.mid(*startOffset, *endOffset - *startOffset);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the text item of type \a boundaryType that is close to offset \a offset
|
||||
and sets \a startOffset and \a endOffset values to the start and end positions
|
||||
of that item; returns an empty string if there is no such an item.
|
||||
Sets \a startOffset and \a endOffset values to -1 on error.
|
||||
|
||||
This default implementation is provided for small text edits. A word processor or
|
||||
text editor should provide their own efficient implementations. This function makes no
|
||||
distinction between paragraphs and lines.
|
||||
|
||||
\note this function can not take the cursor position into account. By convention
|
||||
an \a offset of -2 means that this function should use the cursor position as offset.
|
||||
Thus an offset of -2 must be converted to the cursor position before calling this
|
||||
function.
|
||||
An offset of -1 is used for the text length and custom implementations of this function
|
||||
have to return the result as if the length was passed in as offset.
|
||||
*/
|
||||
QString QAccessibleTextInterface::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType,
|
||||
int *startOffset, int *endOffset) const
|
||||
{
|
||||
const QString txt = text(0, characterCount());
|
||||
|
||||
if (offset == -1)
|
||||
offset = txt.length();
|
||||
|
||||
*startOffset = *endOffset = -1;
|
||||
if (txt.isEmpty() || offset <= 0 || offset > txt.length())
|
||||
return QString();
|
||||
@ -1922,7 +1971,11 @@ QString QAccessibleTextInterface::textBeforeOffset(int offset, QAccessible::Text
|
||||
case QAccessible::SentenceBoundary:
|
||||
type = QTextBoundaryFinder::Sentence;
|
||||
break;
|
||||
default:
|
||||
case QAccessible::LineBoundary:
|
||||
case QAccessible::ParagraphBoundary:
|
||||
// Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
|
||||
return textLineBoundary(-1, txt, offset, startOffset, endOffset);
|
||||
case QAccessible::NoBoundary:
|
||||
// return empty, this function currently only supports single lines, so there can be no line before
|
||||
return QString();
|
||||
}
|
||||
@ -1954,12 +2007,26 @@ QString QAccessibleTextInterface::textBeforeOffset(int offset, QAccessible::Text
|
||||
and sets \a startOffset and \a endOffset values to the start and end positions
|
||||
of that item; returns an empty string if there is no such an item.
|
||||
Sets \a startOffset and \a endOffset values to -1 on error.
|
||||
|
||||
This default implementation is provided for small text edits. A word processor or
|
||||
text editor should provide their own efficient implementations. This function makes no
|
||||
distinction between paragraphs and lines.
|
||||
|
||||
\note this function can not take the cursor position into account. By convention
|
||||
an \a offset of -2 means that this function should use the cursor position as offset.
|
||||
Thus an offset of -2 must be converted to the cursor position before calling this
|
||||
function.
|
||||
An offset of -1 is used for the text length and custom implementations of this function
|
||||
have to return the result as if the length was passed in as offset.
|
||||
*/
|
||||
QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
|
||||
int *startOffset, int *endOffset) const
|
||||
{
|
||||
const QString txt = text(0, characterCount());
|
||||
|
||||
if (offset == -1)
|
||||
offset = txt.length();
|
||||
|
||||
*startOffset = *endOffset = -1;
|
||||
if (txt.isEmpty() || offset < 0 || offset >= txt.length())
|
||||
return QString();
|
||||
@ -1975,7 +2042,11 @@ QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible::TextB
|
||||
case QAccessible::SentenceBoundary:
|
||||
type = QTextBoundaryFinder::Sentence;
|
||||
break;
|
||||
default:
|
||||
case QAccessible::LineBoundary:
|
||||
case QAccessible::ParagraphBoundary:
|
||||
// Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
|
||||
return textLineBoundary(1, txt, offset, startOffset, endOffset);
|
||||
case QAccessible::NoBoundary:
|
||||
// return empty, this function currently only supports single lines, so there can be no line after
|
||||
return QString();
|
||||
}
|
||||
@ -2018,12 +2089,26 @@ QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible::TextB
|
||||
and sets \a startOffset and \a endOffset values to the start and end positions
|
||||
of that item; returns an empty string if there is no such an item.
|
||||
Sets \a startOffset and \a endOffset values to -1 on error.
|
||||
|
||||
This default implementation is provided for small text edits. A word processor or
|
||||
text editor should provide their own efficient implementations. This function makes no
|
||||
distinction between paragraphs and lines.
|
||||
|
||||
\note this function can not take the cursor position into account. By convention
|
||||
an \a offset of -2 means that this function should use the cursor position as offset.
|
||||
Thus an offset of -2 must be converted to the cursor position before calling this
|
||||
function.
|
||||
An offset of -1 is used for the text length and custom implementations of this function
|
||||
have to return the result as if the length was passed in as offset.
|
||||
*/
|
||||
QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
|
||||
int *startOffset, int *endOffset) const
|
||||
{
|
||||
const QString txt = text(0, characterCount());
|
||||
|
||||
if (offset == -1)
|
||||
offset = txt.length();
|
||||
|
||||
*startOffset = *endOffset = -1;
|
||||
if (txt.isEmpty() || offset < 0 || offset > txt.length())
|
||||
return QString();
|
||||
@ -2042,8 +2127,11 @@ QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible::TextBoun
|
||||
case QAccessible::SentenceBoundary:
|
||||
type = QTextBoundaryFinder::Sentence;
|
||||
break;
|
||||
default:
|
||||
// return the whole line
|
||||
case QAccessible::LineBoundary:
|
||||
case QAccessible::ParagraphBoundary:
|
||||
// Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
|
||||
return textLineBoundary(0, txt, offset, startOffset, endOffset);
|
||||
case QAccessible::NoBoundary:
|
||||
*startOffset = 0;
|
||||
*endOffset = txt.length();
|
||||
return txt;
|
||||
|
@ -69,7 +69,7 @@ Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance)
|
||||
static QString fallbackTheme()
|
||||
{
|
||||
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
|
||||
const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconThemeName);
|
||||
const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconFallbackThemeName);
|
||||
if (themeHint.isValid())
|
||||
return themeHint.toString();
|
||||
}
|
||||
@ -561,15 +561,16 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
|
||||
{
|
||||
QIconEngine::AvailableSizesArgument &arg
|
||||
= *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data);
|
||||
arg.sizes.clear();
|
||||
const int N = m_entries.size();
|
||||
arg.sizes.reserve(N);
|
||||
QList<QSize> sizes;
|
||||
sizes.reserve(N);
|
||||
|
||||
// Gets all sizes from the DirectoryInfo entries
|
||||
for (int i = 0; i < N; ++i) {
|
||||
int size = m_entries.at(i)->dir.size;
|
||||
arg.sizes.append(QSize(size, size));
|
||||
sizes.append(QSize(size, size));
|
||||
}
|
||||
arg.sizes.swap(sizes); // commit
|
||||
}
|
||||
break;
|
||||
case QIconEngine::IconNameHook:
|
||||
|
@ -1368,7 +1368,7 @@ void QImage::setColorTable(const QVector<QRgb> colors)
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
d->colortable = colors;
|
||||
d->colortable = qMove(const_cast<QVector<QRgb>&>(colors));
|
||||
d->has_alpha_clut = false;
|
||||
for (int i = 0; i < d->colortable.size(); ++i) {
|
||||
if (qAlpha(d->colortable.at(i)) != 255) {
|
||||
|
@ -232,7 +232,7 @@ public:
|
||||
void setPixel(const QPoint &pt, uint index_or_rgb);
|
||||
|
||||
QVector<QRgb> colorTable() const;
|
||||
void setColorTable(const QVector<QRgb> colors);
|
||||
void setColorTable(const QVector<QRgb> colors); // ### Qt 6: remove const
|
||||
|
||||
qreal devicePixelRatio() const;
|
||||
void setDevicePixelRatio(qreal scaleFactor);
|
||||
|
@ -42,6 +42,10 @@
|
||||
#ifndef QOPENGLWINDOW_H
|
||||
#define QOPENGLWINDOW_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
|
||||
#include <QtGui/QPaintDeviceWindow>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QImage>
|
||||
@ -97,4 +101,6 @@ private:
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
#endif
|
||||
|
@ -117,12 +117,6 @@ typedef char GLchar;
|
||||
|
||||
# include <QtGui/qopengles2ext.h>
|
||||
# endif // Q_OS_MAC
|
||||
# ifndef GL_DOUBLE
|
||||
# define GL_DOUBLE GL_FLOAT
|
||||
# endif
|
||||
# ifndef GLdouble
|
||||
typedef GLfloat GLdouble;
|
||||
# endif
|
||||
#else // non-ES2 platforms
|
||||
# if defined(Q_OS_MAC)
|
||||
# include <OpenGL/gl.h>
|
||||
|
@ -563,8 +563,10 @@ struct QOpenGLFunctionsPrivate
|
||||
void (QOPENGLF_APIENTRYP VertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
|
||||
|
||||
// Special non-ES OpenGL variants, not to be called directly
|
||||
#ifndef QT_OPENGL_ES_2
|
||||
void (QOPENGLF_APIENTRYP ClearDepth)(GLdouble depth);
|
||||
void (QOPENGLF_APIENTRYP DepthRange)(GLdouble zNear, GLdouble zFar);
|
||||
#endif
|
||||
};
|
||||
|
||||
// GLES2 + OpenGL1 common subset
|
||||
|
@ -102,13 +102,13 @@ void QOpenGL2GradientCache::cleanCache()
|
||||
|
||||
GLuint QOpenGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
quint64 hash_val = 0;
|
||||
|
||||
QGradientStops stops = gradient.stops();
|
||||
for (int i = 0; i < stops.size() && i <= 2; i++)
|
||||
hash_val += stops[i].second.rgba();
|
||||
|
||||
const QMutexLocker lock(&m_mutex);
|
||||
QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
|
||||
|
||||
if (it == cache.constEnd())
|
||||
|
@ -391,6 +391,16 @@ QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject()
|
||||
that supports vertex array objects current for this function to succeed.
|
||||
|
||||
Returns \c true if the OpenGL vertex array object was successfully created.
|
||||
|
||||
When the return value is \c false, vertex array object support is not available. This
|
||||
is not an error: on systems with OpenGL 2.x or OpenGL ES 2.0 vertex array objects may
|
||||
not be supported. The application is free to continue execution in this case, but it
|
||||
then has to be prepared to operate in a VAO-less manner too. This means that instead
|
||||
of merely calling bind(), the value of isCreated() must be checked and the vertex
|
||||
arrays has to be initialized in the traditional way when there is no vertex array
|
||||
object present.
|
||||
|
||||
\sa isCreated()
|
||||
*/
|
||||
bool QOpenGLVertexArrayObject::create()
|
||||
{
|
||||
|
@ -3521,8 +3521,7 @@ static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
|
||||
POINTBLOCK *tmpPtBlock;
|
||||
int numFullPtBlocks = 0;
|
||||
|
||||
if (!(region = new QRegionPrivate))
|
||||
return 0;
|
||||
region = new QRegionPrivate;
|
||||
|
||||
/* special case a rectangle */
|
||||
if (((Count == 4) ||
|
||||
|
@ -132,6 +132,7 @@ static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *leng
|
||||
return result;
|
||||
}
|
||||
|
||||
static QFontEngineFT::Glyph emptyGlyph = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
// -------------------------- Freetype support ------------------------------
|
||||
|
||||
@ -858,6 +859,9 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
|
||||
if (g && g->format == format && (fetchMetricsOnly || g->data))
|
||||
return g;
|
||||
|
||||
if (!g && set && set->isGlyphMissing(glyph))
|
||||
return &emptyGlyph;
|
||||
|
||||
QFontEngineFT::GlyphInfo info;
|
||||
|
||||
Q_ASSERT(format != Format_None);
|
||||
@ -894,8 +898,12 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
|
||||
load_flags |= FT_LOAD_FORCE_AUTOHINT;
|
||||
err = FT_Load_Glyph(face, glyph, load_flags);
|
||||
}
|
||||
if (err != FT_Err_Ok)
|
||||
if (err != FT_Err_Ok) {
|
||||
qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
|
||||
if (set)
|
||||
set->setGlyphMissing(glyph);
|
||||
return &emptyGlyph;
|
||||
}
|
||||
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
|
||||
@ -1633,9 +1641,12 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlag
|
||||
if (!face)
|
||||
face = lockFace();
|
||||
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
|
||||
glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
|
||||
: QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
|
||||
if (!cacheEnabled)
|
||||
if (g)
|
||||
glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
|
||||
else
|
||||
glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
|
||||
: QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
|
||||
if (!cacheEnabled && g != &emptyGlyph)
|
||||
delete g;
|
||||
}
|
||||
}
|
||||
@ -1674,7 +1685,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
|
||||
xmax = qMax(xmax, x + g->width);
|
||||
ymax = qMax(ymax, y + g->height);
|
||||
overall.xoff += g->advance;
|
||||
if (!cacheEnabled)
|
||||
if (!cacheEnabled && g != &emptyGlyph)
|
||||
delete g;
|
||||
} else {
|
||||
int left = FLOOR(face->glyph->metrics.horiBearingX);
|
||||
@ -1717,7 +1728,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
|
||||
overall.xoff = g->advance;
|
||||
if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
|
||||
overall.xoff = overall.xoff.round();
|
||||
if (!cacheEnabled)
|
||||
if (!cacheEnabled && g != &emptyGlyph)
|
||||
delete g;
|
||||
} else {
|
||||
int left = FLOOR(face->glyph->metrics.horiBearingX);
|
||||
@ -1808,7 +1819,7 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe
|
||||
overall.width = g->width;
|
||||
overall.height = g->height;
|
||||
overall.xoff = g->advance;
|
||||
if (!glyphSet)
|
||||
if (!glyphSet && g != &emptyGlyph)
|
||||
delete g;
|
||||
} else {
|
||||
int left = FLOOR(face->glyph->metrics.horiBearingX);
|
||||
|
@ -187,8 +187,11 @@ public:
|
||||
inline Glyph *getGlyph(glyph_t index, QFixed subPixelPosition = 0) const;
|
||||
void setGlyph(glyph_t index, QFixed spp, Glyph *glyph);
|
||||
|
||||
inline bool isGlyphMissing(glyph_t index) const { return missing_glyphs.contains(index); }
|
||||
inline void setGlyphMissing(glyph_t index) const { missing_glyphs.insert(index); }
|
||||
private:
|
||||
mutable QHash<GlyphAndSubPixelPosition, Glyph *> glyph_data; // maps from glyph index to glyph data
|
||||
mutable QSet<glyph_t> missing_glyphs;
|
||||
mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256
|
||||
mutable int fast_glyph_count;
|
||||
};
|
||||
|
@ -2385,8 +2385,7 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
|
||||
return false;
|
||||
}
|
||||
|
||||
void **newMem = memory;
|
||||
newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *));
|
||||
void **newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *));
|
||||
if (!newMem) {
|
||||
layoutState = LayoutFailed;
|
||||
return false;
|
||||
|
@ -65,6 +65,16 @@ QT_BEGIN_NAMESPACE
|
||||
class QNetworkReplyPrivate: public QIODevicePrivate, public QNetworkHeadersPrivate
|
||||
{
|
||||
public:
|
||||
enum State {
|
||||
Idle, // The reply is idle.
|
||||
Buffering, // The reply is buffering outgoing data.
|
||||
Working, // The reply is uploading/downloading data.
|
||||
Finished, // The reply has finished.
|
||||
Aborted, // The reply has been aborted.
|
||||
WaitingForSession, // The reply is waiting for the session to open before connecting.
|
||||
Reconnecting // The reply will reconnect to once roaming has completed.
|
||||
};
|
||||
|
||||
QNetworkReplyPrivate();
|
||||
QNetworkRequest request;
|
||||
QUrl url;
|
||||
|
@ -250,8 +250,8 @@ void QNetworkReplyHttpImpl::close()
|
||||
{
|
||||
Q_D(QNetworkReplyHttpImpl);
|
||||
|
||||
if (d->state == QNetworkReplyHttpImplPrivate::Aborted ||
|
||||
d->state == QNetworkReplyHttpImplPrivate::Finished)
|
||||
if (d->state == QNetworkReplyPrivate::Aborted ||
|
||||
d->state == QNetworkReplyPrivate::Finished)
|
||||
return;
|
||||
|
||||
// According to the documentation close only stops the download
|
||||
@ -268,23 +268,23 @@ void QNetworkReplyHttpImpl::abort()
|
||||
{
|
||||
Q_D(QNetworkReplyHttpImpl);
|
||||
// FIXME
|
||||
if (d->state == QNetworkReplyHttpImplPrivate::Finished || d->state == QNetworkReplyHttpImplPrivate::Aborted)
|
||||
if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted)
|
||||
return;
|
||||
|
||||
QNetworkReply::close();
|
||||
|
||||
if (d->state != QNetworkReplyHttpImplPrivate::Finished) {
|
||||
if (d->state != QNetworkReplyPrivate::Finished) {
|
||||
// call finished which will emit signals
|
||||
// FIXME shouldn't this be emitted Queued?
|
||||
d->error(OperationCanceledError, tr("Operation canceled"));
|
||||
|
||||
// If state is WaitingForSession, calling finished has no effect
|
||||
if (d->state == QNetworkReplyHttpImplPrivate::WaitingForSession)
|
||||
d->state = QNetworkReplyHttpImplPrivate::Working;
|
||||
if (d->state == QNetworkReplyPrivate::WaitingForSession)
|
||||
d->state = QNetworkReplyPrivate::Working;
|
||||
d->finished();
|
||||
}
|
||||
|
||||
d->state = QNetworkReplyHttpImplPrivate::Aborted;
|
||||
d->state = QNetworkReplyPrivate::Aborted;
|
||||
|
||||
emit abortHttpRequest();
|
||||
}
|
||||
@ -1800,13 +1800,13 @@ void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected()
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
case QNetworkReplyImplPrivate::Buffering:
|
||||
case QNetworkReplyImplPrivate::Working:
|
||||
case QNetworkReplyImplPrivate::Reconnecting:
|
||||
case QNetworkReplyPrivate::Buffering:
|
||||
case QNetworkReplyPrivate::Working:
|
||||
case QNetworkReplyPrivate::Reconnecting:
|
||||
// Migrate existing downloads to new network connection.
|
||||
migrateBackend();
|
||||
break;
|
||||
case QNetworkReplyImplPrivate::WaitingForSession:
|
||||
case QNetworkReplyPrivate::WaitingForSession:
|
||||
// Start waiting requests.
|
||||
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
|
||||
break;
|
||||
|
@ -160,16 +160,6 @@ public:
|
||||
|
||||
static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio);
|
||||
|
||||
enum State {
|
||||
Idle, // The reply is idle.
|
||||
Buffering, // The reply is buffering outgoing data.
|
||||
Working, // The reply is uploading/downloading data.
|
||||
Finished, // The reply has finished.
|
||||
Aborted, // The reply has been aborted.
|
||||
WaitingForSession, // The reply is waiting for the session to open before connecting.
|
||||
Reconnecting // The reply will reconnect to once roaming has completed.
|
||||
};
|
||||
|
||||
QNetworkReplyHttpImplPrivate();
|
||||
~QNetworkReplyHttpImplPrivate();
|
||||
|
||||
|
@ -301,13 +301,13 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected()
|
||||
return;
|
||||
|
||||
switch (state) {
|
||||
case QNetworkReplyImplPrivate::Buffering:
|
||||
case QNetworkReplyImplPrivate::Working:
|
||||
case QNetworkReplyImplPrivate::Reconnecting:
|
||||
case QNetworkReplyPrivate::Buffering:
|
||||
case QNetworkReplyPrivate::Working:
|
||||
case QNetworkReplyPrivate::Reconnecting:
|
||||
// Migrate existing downloads to new network connection.
|
||||
migrateBackend();
|
||||
break;
|
||||
case QNetworkReplyImplPrivate::WaitingForSession:
|
||||
case QNetworkReplyPrivate::WaitingForSession:
|
||||
// Start waiting requests.
|
||||
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
|
||||
break;
|
||||
@ -916,7 +916,7 @@ QNetworkReplyImpl::~QNetworkReplyImpl()
|
||||
void QNetworkReplyImpl::abort()
|
||||
{
|
||||
Q_D(QNetworkReplyImpl);
|
||||
if (d->state == QNetworkReplyImplPrivate::Finished || d->state == QNetworkReplyImplPrivate::Aborted)
|
||||
if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted)
|
||||
return;
|
||||
|
||||
// stop both upload and download
|
||||
@ -927,14 +927,14 @@ void QNetworkReplyImpl::abort()
|
||||
|
||||
QNetworkReply::close();
|
||||
|
||||
if (d->state != QNetworkReplyImplPrivate::Finished) {
|
||||
if (d->state != QNetworkReplyPrivate::Finished) {
|
||||
// call finished which will emit signals
|
||||
d->error(OperationCanceledError, tr("Operation canceled"));
|
||||
if (d->state == QNetworkReplyImplPrivate::WaitingForSession)
|
||||
d->state = QNetworkReplyImplPrivate::Working;
|
||||
if (d->state == QNetworkReplyPrivate::WaitingForSession)
|
||||
d->state = QNetworkReplyPrivate::Working;
|
||||
d->finished();
|
||||
}
|
||||
d->state = QNetworkReplyImplPrivate::Aborted;
|
||||
d->state = QNetworkReplyPrivate::Aborted;
|
||||
|
||||
// finished may access the backend
|
||||
if (d->backend) {
|
||||
@ -946,8 +946,8 @@ void QNetworkReplyImpl::abort()
|
||||
void QNetworkReplyImpl::close()
|
||||
{
|
||||
Q_D(QNetworkReplyImpl);
|
||||
if (d->state == QNetworkReplyImplPrivate::Aborted ||
|
||||
d->state == QNetworkReplyImplPrivate::Finished)
|
||||
if (d->state == QNetworkReplyPrivate::Aborted ||
|
||||
d->state == QNetworkReplyPrivate::Finished)
|
||||
return;
|
||||
|
||||
// stop the download
|
||||
@ -1041,7 +1041,7 @@ qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen)
|
||||
if (d->downloadBuffer) {
|
||||
qint64 maxAvail = qMin<qint64>(d->downloadBufferCurrentSize - d->downloadBufferReadPosition, maxlen);
|
||||
if (maxAvail == 0)
|
||||
return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
|
||||
return d->state == QNetworkReplyPrivate::Finished ? -1 : 0;
|
||||
// FIXME what about "Aborted" state?
|
||||
memcpy(data, d->downloadBuffer + d->downloadBufferReadPosition, maxAvail);
|
||||
d->downloadBufferReadPosition += maxAvail;
|
||||
@ -1050,7 +1050,7 @@ qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen)
|
||||
|
||||
|
||||
if (d->readBuffer.isEmpty())
|
||||
return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
|
||||
return d->state == QNetworkReplyPrivate::Finished ? -1 : 0;
|
||||
// FIXME what about "Aborted" state?
|
||||
|
||||
d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
|
||||
@ -1101,7 +1101,7 @@ bool QNetworkReplyImplPrivate::migrateBackend()
|
||||
if (!backend->canResume())
|
||||
return false;
|
||||
|
||||
state = QNetworkReplyImplPrivate::Reconnecting;
|
||||
state = QNetworkReplyPrivate::Reconnecting;
|
||||
|
||||
if (backend) {
|
||||
delete backend;
|
||||
|
@ -118,16 +118,6 @@ public:
|
||||
NotifyCopyFinished
|
||||
};
|
||||
|
||||
enum State {
|
||||
Idle, // The reply is idle.
|
||||
Buffering, // The reply is buffering outgoing data.
|
||||
Working, // The reply is uploading/downloading data.
|
||||
Finished, // The reply has finished.
|
||||
Aborted, // The reply has been aborted.
|
||||
WaitingForSession, // The reply is waiting for the session to open before connecting.
|
||||
Reconnecting // The reply will reconnect to once roaming has completed.
|
||||
};
|
||||
|
||||
typedef QQueue<InternalNotifications> NotificationQueue;
|
||||
|
||||
QNetworkReplyImplPrivate();
|
||||
|
@ -176,10 +176,8 @@ QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
Q_D(QNativeSocketEngine);
|
||||
Q_ASSERT(parent);
|
||||
d->sslSocket = qobject_cast<QSslSocket *>(parent->parent());
|
||||
#else
|
||||
d->sslSocket = Q_NULLPTR;
|
||||
if (parent)
|
||||
d->sslSocket = qobject_cast<QSslSocket *>(parent->parent());
|
||||
#endif
|
||||
|
||||
connect(this, SIGNAL(connectionReady()), SLOT(connectionNotification()), Qt::QueuedConnection);
|
||||
@ -809,8 +807,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
|
||||
return false;
|
||||
}
|
||||
EventRegistrationToken token;
|
||||
udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
|
||||
socketDescriptor = qintptr(socket.Detach());
|
||||
udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
@ -827,6 +825,7 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate()
|
||||
, notifyOnException(false)
|
||||
, closingDown(false)
|
||||
, socketDescriptor(-1)
|
||||
, sslSocket(Q_NULLPTR)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,14 @@ static OidNameMap createOidMap()
|
||||
// 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("1.3.6.1.5.5.7.1.1"), QByteArrayLiteral("authorityInfoAccess"));
|
||||
oids.insert(oids.end(), QByteArrayLiteral("1.3.6.1.5.5.7.48.1"), QByteArrayLiteral("OCSP"));
|
||||
oids.insert(oids.end(), QByteArrayLiteral("1.3.6.1.5.5.7.48.2"), QByteArrayLiteral("caIssuers"));
|
||||
oids.insert(oids.end(), QByteArrayLiteral("2.5.29.14"), QByteArrayLiteral("subjectKeyIdentifier"));
|
||||
oids.insert(oids.end(), QByteArrayLiteral("2.5.29.15"), QByteArrayLiteral("keyUsage"));
|
||||
oids.insert(oids.end(), QByteArrayLiteral("2.5.29.17"), QByteArrayLiteral("subjectAltName"));
|
||||
oids.insert(oids.end(), QByteArrayLiteral("2.5.29.19"), QByteArrayLiteral("basicConstraints"));
|
||||
oids.insert(oids.end(), QByteArrayLiteral("2.5.29.35"), QByteArrayLiteral("authorityKeyIdentifier"));
|
||||
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"));
|
||||
@ -155,6 +163,12 @@ void QAsn1Element::write(QDataStream &stream) const
|
||||
stream.writeRawData(mValue.data(), mValue.size());
|
||||
}
|
||||
|
||||
QAsn1Element QAsn1Element::fromBool(bool val)
|
||||
{
|
||||
return QAsn1Element(QAsn1Element::BooleanType,
|
||||
QByteArray(1, val ? 0xff : 0x00));
|
||||
}
|
||||
|
||||
QAsn1Element QAsn1Element::fromInteger(unsigned int val)
|
||||
{
|
||||
QAsn1Element elem(QAsn1Element::IntegerType);
|
||||
@ -199,6 +213,23 @@ QAsn1Element QAsn1Element::fromObjectId(const QByteArray &id)
|
||||
return elem;
|
||||
}
|
||||
|
||||
bool QAsn1Element::toBool(bool *ok) const
|
||||
{
|
||||
if (*this == fromBool(true)) {
|
||||
if (ok)
|
||||
*ok = true;
|
||||
return true;
|
||||
} else if (*this == fromBool(false)) {
|
||||
if (ok)
|
||||
*ok = true;
|
||||
return false;
|
||||
} else {
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime QAsn1Element::toDateTime() const
|
||||
{
|
||||
if (mValue.endsWith('Z')) {
|
||||
@ -242,6 +273,30 @@ QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
|
||||
return info;
|
||||
}
|
||||
|
||||
qint64 QAsn1Element::toInteger(bool *ok) const
|
||||
{
|
||||
if (mType != QAsn1Element::IntegerType || mValue.isEmpty()) {
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: negative numbers are not handled
|
||||
if (mValue.at(0) & 0x80) {
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 value = mValue.at(0) & 0x7f;
|
||||
for (int i = 1; i < mValue.size(); ++i)
|
||||
value = (value << 8) | quint8(mValue.at(i));
|
||||
|
||||
if (ok)
|
||||
*ok = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
QVector<QAsn1Element> QAsn1Element::toVector() const
|
||||
{
|
||||
QVector<QAsn1Element> items;
|
||||
|
@ -59,11 +59,15 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#define RSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.113549.1.1.1")
|
||||
#define DSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10040.4.1")
|
||||
|
||||
class Q_AUTOTEST_EXPORT QAsn1Element
|
||||
{
|
||||
public:
|
||||
enum ElementType {
|
||||
// universal
|
||||
BooleanType = 0x01,
|
||||
IntegerType = 0x02,
|
||||
BitStringType = 0x03,
|
||||
OctetStringType = 0x04,
|
||||
@ -77,10 +81,6 @@ public:
|
||||
SequenceType = 0x30,
|
||||
SetType = 0x31,
|
||||
|
||||
// application
|
||||
Rfc822NameType = 0x81,
|
||||
DnsNameType = 0x82,
|
||||
|
||||
// context specific
|
||||
Context0Type = 0xA0,
|
||||
Context3Type = 0xA3
|
||||
@ -91,12 +91,15 @@ public:
|
||||
bool read(const QByteArray &data);
|
||||
void write(QDataStream &data) const;
|
||||
|
||||
static QAsn1Element fromBool(bool val);
|
||||
static QAsn1Element fromInteger(unsigned int val);
|
||||
static QAsn1Element fromVector(const QVector<QAsn1Element> &items);
|
||||
static QAsn1Element fromObjectId(const QByteArray &id);
|
||||
|
||||
bool toBool(bool *ok = 0) const;
|
||||
QDateTime toDateTime() const;
|
||||
QMultiMap<QByteArray, QString> toInfo() const;
|
||||
qint64 toInteger(bool *ok = 0) const;
|
||||
QVector<QAsn1Element> toVector() const;
|
||||
QByteArray toObjectId() const;
|
||||
QByteArray toObjectName() const;
|
||||
@ -105,12 +108,21 @@ public:
|
||||
quint8 type() const { return mType; }
|
||||
QByteArray value() const { return mValue; }
|
||||
|
||||
friend inline bool operator==(const QAsn1Element &, const QAsn1Element &);
|
||||
friend inline bool operator!=(const QAsn1Element &, const QAsn1Element &);
|
||||
|
||||
private:
|
||||
quint8 mType;
|
||||
QByteArray mValue;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(QAsn1Element, Q_MOVABLE_TYPE);
|
||||
|
||||
inline bool operator==(const QAsn1Element &e1, const QAsn1Element &e2)
|
||||
{ return e1.mType == e2.mType && e1.mValue == e2.mValue; }
|
||||
|
||||
inline bool operator!=(const QAsn1Element &e1, const QAsn1Element &e2)
|
||||
{ return e1.mType != e2.mType || e1.mValue != e2.mValue; }
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
@ -122,7 +122,6 @@
|
||||
|
||||
#include "qsslcertificate.h"
|
||||
#include "qsslcertificate_p.h"
|
||||
#include "qasn1element_p.h"
|
||||
#include "qsslkey_p.h"
|
||||
|
||||
#include <QtCore/qdir.h>
|
||||
@ -642,155 +641,6 @@ 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++) {
|
||||
|
@ -109,13 +109,16 @@ public:
|
||||
QSsl::KeyAlgorithm publicKeyAlgorithm;
|
||||
QByteArray publicKeyDerData;
|
||||
QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames;
|
||||
QList<QSslCertificateExtension> extensions;
|
||||
|
||||
QByteArray derData;
|
||||
|
||||
bool parse(const QByteArray &data);
|
||||
bool parseExtension(const QByteArray &data, QSslCertificateExtension *extension);
|
||||
#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);
|
||||
|
@ -47,9 +47,17 @@
|
||||
#include "qsslkey_p.h"
|
||||
#include "qsslcertificateextension.h"
|
||||
#include "qsslcertificateextension_p.h"
|
||||
#include "qasn1element_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
enum GeneralNameType
|
||||
{
|
||||
Rfc822NameType = 0x81,
|
||||
DnsNameType = 0x82,
|
||||
UniformResourceIdentifierType = 0x86
|
||||
};
|
||||
|
||||
bool QSslCertificate::operator==(const QSslCertificate &other) const
|
||||
{
|
||||
if (d == other.d)
|
||||
@ -150,8 +158,7 @@ QSslKey QSslCertificate::publicKey() const
|
||||
|
||||
QList<QSslCertificateExtension> QSslCertificate::extensions() const
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return QList<QSslCertificateExtension>();
|
||||
return d->extensions;
|
||||
}
|
||||
|
||||
#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
|
||||
@ -263,4 +270,249 @@ QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteAr
|
||||
return certificates;
|
||||
}
|
||||
|
||||
static QByteArray colonSeparatedHex(const QByteArray &value)
|
||||
{
|
||||
QByteArray hexString;
|
||||
hexString.reserve(value.size() * 3);
|
||||
for (int a = 0; a < value.size(); ++a) {
|
||||
const quint8 b = value.at(a);
|
||||
if (b || !hexString.isEmpty()) { // skip leading zeros
|
||||
hexString += QByteArray::number(b, 16).rightJustified(2, '0');
|
||||
hexString += ':';
|
||||
}
|
||||
}
|
||||
hexString.chop(1);
|
||||
return hexString;
|
||||
}
|
||||
|
||||
bool QSslCertificatePrivate::parse(const QByteArray &data)
|
||||
{
|
||||
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;
|
||||
serialNumberString = colonSeparatedHex(elem.value());
|
||||
|
||||
// algorithm ID
|
||||
if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
// 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 == RSA_ENCRYPTION_OID)
|
||||
publicKeyAlgorithm = QSsl::Rsa;
|
||||
else if (oid == RSA_ENCRYPTION_OID)
|
||||
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) {
|
||||
QSslCertificateExtension extension;
|
||||
if (!parseExtension(elem.value(), &extension))
|
||||
return false;
|
||||
extensions << extension;
|
||||
|
||||
if (extension.oid() == QLatin1String("2.5.29.17")) {
|
||||
// subjectAltName
|
||||
QAsn1Element sanElem;
|
||||
if (sanElem.read(extension.value().toByteArray()) && sanElem.type() == QAsn1Element::SequenceType) {
|
||||
QDataStream nameStream(sanElem.value());
|
||||
QAsn1Element nameElem;
|
||||
while (nameElem.read(nameStream)) {
|
||||
if (nameElem.type() == Rfc822NameType) {
|
||||
subjectAlternativeNames.insert(QSsl::EmailEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
|
||||
} else if (nameElem.type() == DnsNameType) {
|
||||
subjectAlternativeNames.insert(QSsl::DnsEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
derData = data.left(dataStream.device()->pos());
|
||||
null = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSslCertificatePrivate::parseExtension(const QByteArray &data, QSslCertificateExtension *extension)
|
||||
{
|
||||
bool ok;
|
||||
bool critical = false;
|
||||
QAsn1Element oidElem, valElem;
|
||||
|
||||
QDataStream seqStream(data);
|
||||
|
||||
// oid
|
||||
if (!oidElem.read(seqStream) || oidElem.type() != QAsn1Element::ObjectIdentifierType)
|
||||
return false;
|
||||
const QByteArray oid = oidElem.toObjectId();
|
||||
|
||||
// critical and value
|
||||
if (!valElem.read(seqStream))
|
||||
return false;
|
||||
if (valElem.type() == QAsn1Element::BooleanType) {
|
||||
critical = valElem.toBool(&ok);
|
||||
if (!ok || !valElem.read(seqStream))
|
||||
return false;
|
||||
}
|
||||
if (valElem.type() != QAsn1Element::OctetStringType)
|
||||
return false;
|
||||
|
||||
// interpret value
|
||||
QAsn1Element val;
|
||||
bool supported = true;
|
||||
QVariant value;
|
||||
if (oid == QByteArrayLiteral("1.3.6.1.5.5.7.1.1")) {
|
||||
// authorityInfoAccess
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
QVariantMap result;
|
||||
foreach (const QAsn1Element &el, val.toVector()) {
|
||||
QVector<QAsn1Element> items = el.toVector();
|
||||
if (items.size() != 2)
|
||||
return false;
|
||||
const QString key = QString::fromLatin1(items.at(0).toObjectName());
|
||||
switch (items.at(1).type()) {
|
||||
case Rfc822NameType:
|
||||
case DnsNameType:
|
||||
case UniformResourceIdentifierType:
|
||||
result[key] = QString::fromLatin1(items.at(1).value(), items.at(1).value().size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = result;
|
||||
} else if (oid == QByteArrayLiteral("2.5.29.14")) {
|
||||
// subjectKeyIdentifier
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::OctetStringType)
|
||||
return false;
|
||||
value = colonSeparatedHex(val.value()).toUpper();
|
||||
} else if (oid == QByteArrayLiteral("2.5.29.19")) {
|
||||
// basicConstraints
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
|
||||
QVariantMap result;
|
||||
QVector<QAsn1Element> items = val.toVector();
|
||||
if (items.size() > 0) {
|
||||
result[QStringLiteral("ca")] = items.at(0).toBool(&ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
} else {
|
||||
result[QStringLiteral("ca")] = false;
|
||||
}
|
||||
if (items.size() > 1) {
|
||||
result[QStringLiteral("pathLenConstraint")] = items.at(1).toInteger(&ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
value = result;
|
||||
} else if (oid == QByteArrayLiteral("2.5.29.35")) {
|
||||
// authorityKeyIdentifier
|
||||
if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
|
||||
return false;
|
||||
QVariantMap result;
|
||||
foreach (const QAsn1Element &el, val.toVector()) {
|
||||
if (el.type() == 0x80) {
|
||||
result[QStringLiteral("keyid")] = el.value().toHex();
|
||||
} else if (el.type() == 0x82) {
|
||||
result[QStringLiteral("serial")] = colonSeparatedHex(el.value());
|
||||
}
|
||||
}
|
||||
value = result;
|
||||
} else {
|
||||
supported = false;
|
||||
value = valElem.value();
|
||||
}
|
||||
|
||||
extension->d->critical = critical;
|
||||
extension->d->supported = supported;
|
||||
extension->d->oid = QString::fromLatin1(oid);
|
||||
extension->d->name = QString::fromLatin1(oidElem.toObjectName());
|
||||
extension->d->value = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -111,7 +111,8 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
|
||||
|
||||
void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
|
||||
{
|
||||
decodePem(pemFromDer(der), QByteArray(), deepClear);
|
||||
QMap<QByteArray, QByteArray> headers;
|
||||
decodePem(pemFromDer(der, headers), QByteArray(), deepClear);
|
||||
}
|
||||
|
||||
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
|
||||
|
@ -63,6 +63,7 @@
|
||||
|
||||
#include <QtCore/qatomic.h>
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qbytearraymatcher.h>
|
||||
#include <QtCore/qiodevice.h>
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
#include <QtCore/qdebug.h>
|
||||
@ -130,7 +131,7 @@ QByteArray QSslKeyPrivate::pemFooter() const
|
||||
|
||||
Returns a DER key formatted as PEM.
|
||||
*/
|
||||
QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der) const
|
||||
QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
|
||||
{
|
||||
QByteArray pem(der.toBase64());
|
||||
|
||||
@ -144,7 +145,16 @@ QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der) const
|
||||
if (rem)
|
||||
pem.append('\n'); // ###
|
||||
|
||||
pem.prepend(pemHeader() + '\n');
|
||||
QByteArray extra;
|
||||
if (!headers.isEmpty()) {
|
||||
QMap<QByteArray, QByteArray>::const_iterator it = headers.constEnd();
|
||||
do {
|
||||
it--;
|
||||
extra += it.key() + ": " + it.value() + '\n';
|
||||
} while (it != headers.constBegin());
|
||||
extra += '\n';
|
||||
}
|
||||
pem.prepend(pemHeader() + '\n' + extra);
|
||||
pem.append(pemFooter() + '\n');
|
||||
|
||||
return pem;
|
||||
@ -155,7 +165,7 @@ QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der) const
|
||||
|
||||
Returns a PEM key formatted as DER.
|
||||
*/
|
||||
QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem) const
|
||||
QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
|
||||
{
|
||||
const QByteArray header = pemHeader();
|
||||
const QByteArray footer = pemFooter();
|
||||
@ -169,6 +179,39 @@ QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem) const
|
||||
|
||||
der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
|
||||
|
||||
if (der.contains("Proc-Type:")) {
|
||||
// taken from QHttpNetworkReplyPrivate::parseHeader
|
||||
const QByteArrayMatcher lf("\n");
|
||||
const QByteArrayMatcher colon(":");
|
||||
int i = 0;
|
||||
while (i < der.count()) {
|
||||
int j = colon.indexIn(der, i); // field-name
|
||||
if (j == -1)
|
||||
break;
|
||||
const QByteArray field = der.mid(i, j - i).trimmed();
|
||||
j++;
|
||||
// any number of LWS is allowed before and after the value
|
||||
QByteArray value;
|
||||
do {
|
||||
i = lf.indexIn(der, j);
|
||||
if (i == -1)
|
||||
break;
|
||||
if (!value.isEmpty())
|
||||
value += ' ';
|
||||
// check if we have CRLF or only LF
|
||||
bool hasCR = (i && der[i-1] == '\r');
|
||||
int length = i -(hasCR ? 1: 0) - j;
|
||||
value += der.mid(j, length).trimmed();
|
||||
j = ++i;
|
||||
} while (i < der.count() && (der.at(i) == ' ' || der.at(i) == '\t'));
|
||||
if (i == -1)
|
||||
break; // something is wrong
|
||||
|
||||
headers->insert(field, value);
|
||||
}
|
||||
der = der.mid(i);
|
||||
}
|
||||
|
||||
return QByteArray::fromBase64(der); // ignores newlines
|
||||
}
|
||||
|
||||
@ -337,7 +380,8 @@ QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
|
||||
return QByteArray();
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
return d->derFromPem(toPem(passPhrase));
|
||||
QMap<QByteArray, QByteArray> headers;
|
||||
return d->derFromPem(toPem(passPhrase), &headers);
|
||||
#else
|
||||
return d->derData;
|
||||
#endif
|
||||
|
@ -91,8 +91,8 @@ public:
|
||||
bool deepClear = true);
|
||||
QByteArray pemHeader() const;
|
||||
QByteArray pemFooter() const;
|
||||
QByteArray pemFromDer(const QByteArray &der) const;
|
||||
QByteArray derFromPem(const QByteArray &pem) const;
|
||||
QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const;
|
||||
QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const;
|
||||
|
||||
int length() const;
|
||||
QByteArray toPem(const QByteArray &passPhrase) const;
|
||||
@ -106,6 +106,15 @@ public:
|
||||
RSA *rsa;
|
||||
DSA *dsa;
|
||||
#else
|
||||
enum Cipher {
|
||||
DesCbc,
|
||||
DesEde3Cbc,
|
||||
Rc2Cbc
|
||||
};
|
||||
|
||||
Q_AUTOTEST_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
|
||||
Q_AUTOTEST_EXPORT static QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
|
||||
|
||||
Qt::HANDLE opaque;
|
||||
QByteArray derData;
|
||||
int keyLength;
|
||||
|
@ -43,6 +43,8 @@
|
||||
#include "qsslkey_p.h"
|
||||
#include "qasn1element_p.h"
|
||||
|
||||
#include <QtCore/qcryptographichash.h>
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
static const quint8 bits_table[256] = {
|
||||
@ -78,6 +80,31 @@ static int numberOfBits(const QByteArray &modulus)
|
||||
return bits;
|
||||
}
|
||||
|
||||
static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv)
|
||||
{
|
||||
QByteArray key;
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
hash.addData(passPhrase);
|
||||
hash.addData(iv);
|
||||
switch (cipher) {
|
||||
case QSslKeyPrivate::DesCbc:
|
||||
key = hash.result().left(8);
|
||||
break;
|
||||
case QSslKeyPrivate::DesEde3Cbc:
|
||||
key = hash.result();
|
||||
hash.reset();
|
||||
hash.addData(key);
|
||||
hash.addData(passPhrase);
|
||||
hash.addData(iv);
|
||||
key += hash.result().left(8);
|
||||
break;
|
||||
case QSslKeyPrivate::Rc2Cbc:
|
||||
key = hash.result();
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
void QSslKeyPrivate::clear(bool deep)
|
||||
{
|
||||
Q_UNUSED(deep);
|
||||
@ -106,7 +133,7 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
|
||||
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")
|
||||
if (infoItems[0].toObjectId() != RSA_ENCRYPTION_OID)
|
||||
return;
|
||||
// key data
|
||||
if (!elem.read(keyStream) || elem.type() != QAsn1Element::BitStringType || elem.value().isEmpty())
|
||||
@ -117,7 +144,7 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
|
||||
return;
|
||||
keyLength = numberOfBits(elem.value());
|
||||
} else if (algorithm == QSsl::Dsa) {
|
||||
if (infoItems[0].toObjectId() != "1.2.840.10040.4.1")
|
||||
if (infoItems[0].toObjectId() != DSA_ENCRYPTION_OID)
|
||||
return;
|
||||
if (infoItems[1].type() != QAsn1Element::SequenceType)
|
||||
return;
|
||||
@ -155,12 +182,32 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
|
||||
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
|
||||
bool deepClear)
|
||||
{
|
||||
if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
|
||||
Q_UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
QMap<QByteArray, QByteArray> headers;
|
||||
QByteArray data = derFromPem(pem, &headers);
|
||||
if (headers.value("Proc-Type") == "4,ENCRYPTED") {
|
||||
QList<QByteArray> dekInfo = headers.value("DEK-Info").split(',');
|
||||
if (dekInfo.size() != 2) {
|
||||
clear(deepClear);
|
||||
return;
|
||||
}
|
||||
|
||||
decodeDer(derFromPem(pem), deepClear);
|
||||
Cipher cipher;
|
||||
if (dekInfo.first() == "DES-CBC") {
|
||||
cipher = DesCbc;
|
||||
} else if (dekInfo.first() == "DES-EDE3-CBC") {
|
||||
cipher = DesEde3Cbc;
|
||||
} else if (dekInfo.first() == "RC2-CBC") {
|
||||
cipher = Rc2Cbc;
|
||||
} else {
|
||||
clear(deepClear);
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray iv = QByteArray::fromHex(dekInfo.last());
|
||||
const QByteArray key = deriveKey(cipher, passPhrase, iv);
|
||||
data = decrypt(cipher, data, key, iv);
|
||||
}
|
||||
decodeDer(data, deepClear);
|
||||
}
|
||||
|
||||
int QSslKeyPrivate::length() const
|
||||
@ -170,12 +217,27 @@ int QSslKeyPrivate::length() const
|
||||
|
||||
QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
|
||||
{
|
||||
QByteArray data;
|
||||
QMap<QByteArray, QByteArray> headers;
|
||||
|
||||
if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
|
||||
Q_UNIMPLEMENTED();
|
||||
return QByteArray();
|
||||
// ### use a cryptographically secure random number generator
|
||||
QByteArray iv;
|
||||
iv.resize(8);
|
||||
for (int i = 0; i < iv.size(); ++i)
|
||||
iv[i] = (qrand() & 0xff);
|
||||
|
||||
Cipher cipher = DesEde3Cbc;
|
||||
const QByteArray key = deriveKey(cipher, passPhrase, iv);
|
||||
data = encrypt(cipher, derData, key, iv);
|
||||
|
||||
headers.insert("Proc-Type", "4,ENCRYPTED");
|
||||
headers.insert("DEK-Info", "DES-EDE3-CBC," + iv.toHex());
|
||||
} else {
|
||||
data = derData;
|
||||
}
|
||||
|
||||
return pemFromDer(derData);
|
||||
return pemFromDer(data, headers);
|
||||
}
|
||||
|
||||
Qt::HANDLE QSslKeyPrivate::handle() const
|
||||
|
@ -61,3 +61,101 @@ using namespace ABI::Windows::Security::Cryptography::Core;
|
||||
using namespace ABI::Windows::Storage::Streams;
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
struct SslKeyGlobal
|
||||
{
|
||||
SslKeyGlobal()
|
||||
{
|
||||
HRESULT hr;
|
||||
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_CryptographicEngine).Get(),
|
||||
&engine);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
ComPtr<ISymmetricKeyAlgorithmProviderStatics> keyProviderFactory;
|
||||
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_SymmetricKeyAlgorithmProvider).Get(),
|
||||
&keyProviderFactory);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
hr = keyProviderFactory->OpenAlgorithm(HString::MakeReference(L"DES_CBC").Get(),
|
||||
&keyProviders[QSslKeyPrivate::DesCbc]);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
hr = keyProviderFactory->OpenAlgorithm(HString::MakeReference(L"3DES_CBC").Get(),
|
||||
&keyProviders[QSslKeyPrivate::DesEde3Cbc]);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
hr = keyProviderFactory->OpenAlgorithm(HString::MakeReference(L"RC2_CBC").Get(),
|
||||
&keyProviders[QSslKeyPrivate::Rc2Cbc]);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
|
||||
&bufferFactory);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
ComPtr<ICryptographicEngineStatics> engine;
|
||||
QHash<QSslKeyPrivate::Cipher, ComPtr<ISymmetricKeyAlgorithmProvider>> keyProviders;
|
||||
ComPtr<ICryptographicBufferStatics> bufferFactory;
|
||||
};
|
||||
Q_GLOBAL_STATIC(SslKeyGlobal, g)
|
||||
|
||||
static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, QByteArray data, const QByteArray &key, const QByteArray &iv, bool encrypt)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
ISymmetricKeyAlgorithmProvider *keyProvider = g->keyProviders[cipher].Get();
|
||||
Q_ASSERT(keyProvider);
|
||||
|
||||
ComPtr<IBuffer> keyBuffer;
|
||||
hr = g->bufferFactory->CreateFromByteArray(key.length(), (BYTE *)key.data(), &keyBuffer);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
ComPtr<ICryptographicKey> cryptographicKey;
|
||||
hr = keyProvider->CreateSymmetricKey(keyBuffer.Get(), &cryptographicKey);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
UINT32 blockLength;
|
||||
hr = keyProvider->get_BlockLength(&blockLength);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
if (encrypt) { // Add padding
|
||||
const char padding = blockLength - data.length() % blockLength;
|
||||
data += QByteArray(padding, padding);
|
||||
}
|
||||
|
||||
ComPtr<IBuffer> dataBuffer;
|
||||
hr = g->bufferFactory->CreateFromByteArray(data.length(), (BYTE *)data.data(), &dataBuffer);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
ComPtr<IBuffer> ivBuffer;
|
||||
hr = g->bufferFactory->CreateFromByteArray(iv.length(), (BYTE *)iv.data(), &ivBuffer);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
ComPtr<IBuffer> resultBuffer;
|
||||
hr = encrypt ? g->engine->Encrypt(cryptographicKey.Get(), dataBuffer.Get(), ivBuffer.Get(), &resultBuffer)
|
||||
: g->engine->Decrypt(cryptographicKey.Get(), dataBuffer.Get(), ivBuffer.Get(), &resultBuffer);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
UINT32 resultLength;
|
||||
hr = resultBuffer->get_Length(&resultLength);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferAccess;
|
||||
hr = resultBuffer.As(&bufferAccess);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
byte *resultData;
|
||||
hr = bufferAccess->Buffer(&resultData);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
if (!encrypt) { // Remove padding
|
||||
const uchar padding = resultData[resultLength - 1];
|
||||
if (padding > 0 && padding <= blockLength)
|
||||
resultLength -= padding;
|
||||
else
|
||||
qWarning("Invalid padding length of %u; decryption likely failed.", padding);
|
||||
}
|
||||
|
||||
return QByteArray(reinterpret_cast<const char *>(resultData), resultLength);
|
||||
}
|
||||
|
||||
QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
|
||||
{
|
||||
return doCrypt(cipher, data, key, iv, false);
|
||||
}
|
||||
|
||||
QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
|
||||
{
|
||||
return doCrypt(cipher, data, key, iv, true);
|
||||
}
|
||||
|
@ -249,6 +249,15 @@ void QEGLPlatformContext::adopt(const QVariant &nativeHandle, QPlatformOpenGLCon
|
||||
void QEGLPlatformContext::updateFormatFromGL()
|
||||
{
|
||||
#ifndef QT_NO_OPENGL
|
||||
// Have to save & restore to prevent QOpenGLContext::currentContext() from becoming
|
||||
// inconsistent after QOpenGLContext::create().
|
||||
EGLDisplay prevDisplay = eglGetCurrentDisplay();
|
||||
if (prevDisplay == EGL_NO_DISPLAY) // when no context is current
|
||||
prevDisplay = m_eglDisplay;
|
||||
EGLContext prevContext = eglGetCurrentContext();
|
||||
EGLSurface prevSurfaceDraw = eglGetCurrentSurface(EGL_DRAW);
|
||||
EGLSurface prevSurfaceRead = eglGetCurrentSurface(EGL_READ);
|
||||
|
||||
// Make the context current to ensure the GL version query works. This needs a surface too.
|
||||
const EGLint pbufferAttributes[] = {
|
||||
EGL_WIDTH, 1,
|
||||
@ -300,7 +309,7 @@ void QEGLPlatformContext::updateFormatFromGL()
|
||||
}
|
||||
}
|
||||
}
|
||||
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglMakeCurrent(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext);
|
||||
}
|
||||
eglDestroySurface(m_eglDisplay, pbuffer);
|
||||
#endif // QT_NO_OPENGL
|
||||
|
@ -343,6 +343,8 @@ void QEGLPlatformCursor::draw(const QRectF &r)
|
||||
{
|
||||
if (!m_program) {
|
||||
// one time initialization
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
createShaderPrograms();
|
||||
|
||||
if (!m_cursorAtlas.texture) {
|
||||
@ -387,6 +389,7 @@ void QEGLPlatformCursor::draw(const QRectF &r)
|
||||
};
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_cursor.texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
m_program->enableAttributeArray(m_vertexCoordEntry);
|
||||
m_program->enableAttributeArray(m_textureCoordEntry);
|
||||
|
@ -44,6 +44,7 @@
|
||||
|
||||
#include <qpa/qplatformcursor.h>
|
||||
#include <qpa/qplatformscreen.h>
|
||||
#include <QtGui/QOpenGLFunctions>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -86,7 +87,7 @@ private:
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
class QEGLPlatformCursor : public QPlatformCursor
|
||||
class QEGLPlatformCursor : public QPlatformCursor, protected QOpenGLFunctions
|
||||
{
|
||||
public:
|
||||
QEGLPlatformCursor(QPlatformScreen *screen);
|
||||
@ -113,7 +114,7 @@ private:
|
||||
void draw(const QRectF &rect);
|
||||
void update(const QRegion ®ion);
|
||||
void createShaderPrograms();
|
||||
static void createCursorTexture(uint *texture, const QImage &image);
|
||||
void createCursorTexture(uint *texture, const QImage &image);
|
||||
void initCursorAtlas();
|
||||
|
||||
// current cursor information
|
||||
|
@ -96,8 +96,9 @@ void QBasicFontDatabase::populateFontDatabase()
|
||||
QString fontpath = fontDir();
|
||||
|
||||
if(!QFile::exists(fontpath)) {
|
||||
qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
|
||||
qWarning("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
|
||||
qPrintable(fontpath));
|
||||
return;
|
||||
}
|
||||
|
||||
QDir dir(fontpath);
|
||||
|
@ -380,6 +380,9 @@ namespace QtAndroid
|
||||
|
||||
void setSurfaceGeometry(int surfaceId, const QRect &geometry)
|
||||
{
|
||||
if (surfaceId == -1)
|
||||
return;
|
||||
|
||||
QJNIEnvironmentPrivate env;
|
||||
if (!env)
|
||||
return;
|
||||
@ -399,6 +402,9 @@ namespace QtAndroid
|
||||
|
||||
void destroySurface(int surfaceId)
|
||||
{
|
||||
if (surfaceId == -1)
|
||||
return;
|
||||
|
||||
QMutexLocker lock(&m_surfacesMutex);
|
||||
const auto &it = m_surfaces.find(surfaceId);
|
||||
if (it != m_surfaces.end())
|
||||
|
@ -55,20 +55,26 @@ QAndroidEventDispatcher::~QAndroidEventDispatcher()
|
||||
QAndroidEventDispatcherStopper::instance()->removeEventDispatcher(this);
|
||||
}
|
||||
|
||||
enum States {Running = 0, StopRequest = 1, Stopping = 2};
|
||||
|
||||
void QAndroidEventDispatcher::start()
|
||||
{
|
||||
if (m_stopRequest.testAndSetAcquire(1, 0)) {
|
||||
m_dispatcherSemaphore.release();
|
||||
int prevState = m_stopRequest.fetchAndStoreAcquire(Running);
|
||||
if (prevState == Stopping) {
|
||||
m_semaphore.release();
|
||||
wakeUp();
|
||||
} else if (prevState == Running) {
|
||||
qWarning("Error: start without corresponding stop");
|
||||
}
|
||||
//else if prevState == StopRequest, no action needed
|
||||
}
|
||||
|
||||
void QAndroidEventDispatcher::stop()
|
||||
{
|
||||
if (m_stopRequest.testAndSetAcquire(0, 1)) {
|
||||
if (m_stopRequest.testAndSetAcquire(Running, StopRequest))
|
||||
wakeUp();
|
||||
m_stopperSemaphore.acquire();
|
||||
}
|
||||
else
|
||||
qWarning("Error: start/stop out of sync");
|
||||
}
|
||||
|
||||
void QAndroidEventDispatcher::goingToStop(bool stop)
|
||||
@ -80,9 +86,8 @@ void QAndroidEventDispatcher::goingToStop(bool stop)
|
||||
|
||||
int QAndroidEventDispatcher::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timespec *timeout)
|
||||
{
|
||||
if (m_stopRequest.load() == 1) {
|
||||
m_stopperSemaphore.release();
|
||||
m_dispatcherSemaphore.acquire();
|
||||
if (m_stopRequest.testAndSetAcquire(StopRequest, Stopping)) {
|
||||
m_semaphore.acquire();
|
||||
wakeUp();
|
||||
}
|
||||
|
||||
|
@ -66,13 +66,14 @@ protected:
|
||||
private:
|
||||
QAtomicInt m_stopRequest;
|
||||
QAtomicInt m_goingToStop;
|
||||
QSemaphore m_dispatcherSemaphore, m_stopperSemaphore;
|
||||
QSemaphore m_semaphore;
|
||||
};
|
||||
|
||||
class QAndroidEventDispatcherStopper
|
||||
{
|
||||
public:
|
||||
static QAndroidEventDispatcherStopper *instance();
|
||||
static bool stopped() {return !instance()->started; }
|
||||
void startAll();
|
||||
void stopAll();
|
||||
void addEventDispatcher(QAndroidEventDispatcher *dispatcher);
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "qandroidinputcontext.h"
|
||||
#include "androidjnimain.h"
|
||||
#include "androidjniinput.h"
|
||||
#include "qandroideventdispatcher.h"
|
||||
#include <QDebug>
|
||||
#include <qevent.h>
|
||||
#include <qguiapplication.h>
|
||||
@ -995,8 +996,10 @@ Q_INVOKABLE QVariant QAndroidInputContext::queryFocusObjectUnsafe(Qt::InputMetho
|
||||
|
||||
QVariant QAndroidInputContext::queryFocusObjectThreadSafe(Qt::InputMethodQuery query, QVariant argument)
|
||||
{
|
||||
bool inMainThread = qGuiApp->thread() == QThread::currentThread();
|
||||
const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
|
||||
QVariant retval;
|
||||
if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
|
||||
return retval;
|
||||
|
||||
QMetaObject::invokeMethod(this, "queryFocusObjectUnsafe",
|
||||
inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
|
||||
@ -1010,12 +1013,15 @@ QVariant QAndroidInputContext::queryFocusObjectThreadSafe(Qt::InputMethodQuery q
|
||||
QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries)
|
||||
{
|
||||
#warning TODO make qGuiApp->focusObject() thread safe !!!
|
||||
const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
|
||||
if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
|
||||
return QSharedPointer<QInputMethodQueryEvent>();
|
||||
QObject *focusObject = qGuiApp->focusObject();
|
||||
if (!focusObject)
|
||||
return QSharedPointer<QInputMethodQueryEvent>();
|
||||
|
||||
QSharedPointer<QInputMethodQueryEvent> ret = QSharedPointer<QInputMethodQueryEvent>(new QInputMethodQueryEvent(queries));
|
||||
if (qGuiApp->thread()==QThread::currentThread()) {
|
||||
if (inMainThread) {
|
||||
QCoreApplication::sendEvent(focusObject, ret.data());
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this,
|
||||
|
@ -44,6 +44,7 @@
|
||||
|
||||
#include "qandroidplatformscreen.h"
|
||||
#include "androidjnimain.h"
|
||||
#include "qandroideventdispatcher.h"
|
||||
|
||||
#include <QSurfaceFormat>
|
||||
#include <QtGui/private/qwindow_p.h>
|
||||
@ -121,6 +122,9 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
|
||||
|
||||
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
|
||||
{
|
||||
if (QAndroidEventDispatcherStopper::stopped())
|
||||
return m_eglSurface;
|
||||
|
||||
QMutexLocker lock(&m_surfaceMutex);
|
||||
|
||||
if (m_nativeSurfaceId == -1) {
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
#include "qwindowscontext.h"
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
@ -85,9 +86,18 @@ QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore()
|
||||
{
|
||||
}
|
||||
|
||||
void QWindowsDirect2DBackingStore::beginPaint(const QRegion &)
|
||||
void QWindowsDirect2DBackingStore::beginPaint(const QRegion ®ion)
|
||||
{
|
||||
bitmap(nativeWindow(window())->pixmap())->deviceContext()->begin();
|
||||
QPixmap *pixmap = nativeWindow(window())->pixmap();
|
||||
bitmap(pixmap)->deviceContext()->begin();
|
||||
|
||||
QPainter painter(pixmap);
|
||||
QColor clear(Qt::transparent);
|
||||
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
|
||||
foreach (const QRect &r, region.rects())
|
||||
painter.fillRect(r, clear);
|
||||
}
|
||||
|
||||
void QWindowsDirect2DBackingStore::endPaint()
|
||||
@ -107,7 +117,7 @@ void QWindowsDirect2DBackingStore::flush(QWindow *targetWindow, const QRegion &r
|
||||
nativeWindow(targetWindow)->flush(copy.data(), region, offset);
|
||||
}
|
||||
|
||||
nativeWindow(targetWindow)->present();
|
||||
nativeWindow(targetWindow)->present(region);
|
||||
}
|
||||
|
||||
void QWindowsDirect2DBackingStore::resize(const QSize &size, const QRegion ®ion)
|
||||
|
@ -53,8 +53,9 @@ QT_BEGIN_NAMESPACE
|
||||
class QWindowsDirect2DPaintDevicePrivate
|
||||
{
|
||||
public:
|
||||
QWindowsDirect2DPaintDevicePrivate(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags f)
|
||||
: engine(new QWindowsDirect2DPaintEngine(bitmap))
|
||||
QWindowsDirect2DPaintDevicePrivate(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags f,
|
||||
QWindowsDirect2DPaintEngine::Flags paintFlags)
|
||||
: engine(new QWindowsDirect2DPaintEngine(bitmap, paintFlags))
|
||||
, bitmap(bitmap)
|
||||
, flags(f)
|
||||
{}
|
||||
@ -64,8 +65,9 @@ public:
|
||||
QInternal::PaintDeviceFlags flags;
|
||||
};
|
||||
|
||||
QWindowsDirect2DPaintDevice::QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags)
|
||||
: d_ptr(new QWindowsDirect2DPaintDevicePrivate(bitmap, flags))
|
||||
QWindowsDirect2DPaintDevice::QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags,
|
||||
QWindowsDirect2DPaintEngine::Flags paintFlags)
|
||||
: d_ptr(new QWindowsDirect2DPaintDevicePrivate(bitmap, flags, paintFlags))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtGui/QPaintDevice>
|
||||
#include "qwindowsdirect2dpaintengine.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -55,7 +56,8 @@ class QWindowsDirect2DPaintDevice : public QPaintDevice
|
||||
Q_DECLARE_PRIVATE(QWindowsDirect2DPaintDevice)
|
||||
|
||||
public:
|
||||
QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags);
|
||||
QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags,
|
||||
QWindowsDirect2DPaintEngine::Flags paintFlags = QWindowsDirect2DPaintEngine::NoFlag);
|
||||
QPaintEngine *paintEngine() const Q_DECL_OVERRIDE;
|
||||
int devType() const Q_DECL_OVERRIDE;
|
||||
|
||||
|
@ -233,9 +233,10 @@ class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QWindowsDirect2DPaintEngine)
|
||||
public:
|
||||
QWindowsDirect2DPaintEnginePrivate(QWindowsDirect2DBitmap *bm)
|
||||
QWindowsDirect2DPaintEnginePrivate(QWindowsDirect2DBitmap *bm, QWindowsDirect2DPaintEngine::Flags flags)
|
||||
: bitmap(bm)
|
||||
, clipFlags(0)
|
||||
, flags(flags)
|
||||
{
|
||||
pen.reset();
|
||||
brush.reset();
|
||||
@ -247,6 +248,7 @@ public:
|
||||
|
||||
unsigned int clipFlags;
|
||||
QStack<ClipType> pushedClips;
|
||||
QWindowsDirect2DPaintEngine::Flags flags;
|
||||
|
||||
QPointF currentBrushOrigin;
|
||||
|
||||
@ -343,7 +345,7 @@ public:
|
||||
D2D1::IdentityMatrix(),
|
||||
1.0,
|
||||
NULL,
|
||||
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND),
|
||||
D2D1_LAYER_OPTIONS1_NONE),
|
||||
NULL);
|
||||
pushedClips.push(LayerClip);
|
||||
}
|
||||
@ -868,8 +870,9 @@ public:
|
||||
|
||||
const bool antiAlias = bool((q->state()->renderHints & QPainter::TextAntialiasing)
|
||||
&& !(fontDef.styleStrategy & QFont::NoAntialias));
|
||||
dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE
|
||||
: D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
|
||||
const D2D1_TEXT_ANTIALIAS_MODE antialiasMode = (flags & QWindowsDirect2DPaintEngine::UseGrayscaleAntialiasing)
|
||||
? D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE : D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||
dc()->SetTextAntialiasMode(antiAlias ? antialiasMode : D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
|
||||
|
||||
dc()->DrawGlyphRun(pos,
|
||||
&glyphRun,
|
||||
@ -913,8 +916,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap)
|
||||
: QPaintEngineEx(*(new QWindowsDirect2DPaintEnginePrivate(bitmap)))
|
||||
QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap, Flags flags)
|
||||
: QPaintEngineEx(*(new QWindowsDirect2DPaintEnginePrivate(bitmap, flags)))
|
||||
{
|
||||
QPaintEngine::PaintEngineFeatures unsupported =
|
||||
// As of 1.1 Direct2D does not natively support complex composition modes
|
||||
@ -953,7 +956,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev)
|
||||
D2D1::IdentityMatrix(),
|
||||
1.0,
|
||||
NULL,
|
||||
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND),
|
||||
D2D1_LAYER_OPTIONS1_NONE),
|
||||
NULL);
|
||||
} else {
|
||||
QRect clip(0, 0, pdev->width(), pdev->height());
|
||||
|
@ -59,7 +59,13 @@ class QWindowsDirect2DPaintEngine : public QPaintEngineEx
|
||||
Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngine)
|
||||
|
||||
public:
|
||||
QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap);
|
||||
enum Flag {
|
||||
NoFlag = 0,
|
||||
UseGrayscaleAntialiasing = 1,
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap, Flags flags);
|
||||
|
||||
bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE;
|
||||
bool end() Q_DECL_OVERRIDE;
|
||||
@ -119,6 +125,7 @@ private:
|
||||
void adjustForAliasing(QRectF *rect);
|
||||
void adjustForAliasing(QPointF *point);
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsDirect2DPaintEngine::Flags)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
@ -62,10 +62,11 @@ public:
|
||||
, devicePixelRatio(1.0)
|
||||
{}
|
||||
|
||||
QWindowsDirect2DPlatformPixmapPrivate(QWindowsDirect2DBitmap *bitmap)
|
||||
QWindowsDirect2DPlatformPixmapPrivate(QWindowsDirect2DBitmap *bitmap,
|
||||
QWindowsDirect2DPaintEngine::Flags flags)
|
||||
: owns_bitmap(false)
|
||||
, bitmap(bitmap)
|
||||
, device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap))
|
||||
, device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap, flags))
|
||||
, devicePixelRatio(1.0)
|
||||
{}
|
||||
|
||||
@ -91,9 +92,10 @@ QWindowsDirect2DPlatformPixmap::QWindowsDirect2DPlatformPixmap(PixelType pixelTy
|
||||
}
|
||||
|
||||
QWindowsDirect2DPlatformPixmap::QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixelType pixelType,
|
||||
QWindowsDirect2DPaintEngine::Flags flags,
|
||||
QWindowsDirect2DBitmap *bitmap)
|
||||
: QPlatformPixmap(pixelType, Direct2DClass)
|
||||
, d_ptr(new QWindowsDirect2DPlatformPixmapPrivate(bitmap))
|
||||
, d_ptr(new QWindowsDirect2DPlatformPixmapPrivate(bitmap, flags))
|
||||
{
|
||||
setSerialNumber(qt_d2dpixmap_serno++);
|
||||
|
||||
|
@ -42,6 +42,7 @@
|
||||
#ifndef QWINDOWSDIRECT2DPLATFORMPIXMAP_H
|
||||
#define QWINDOWSDIRECT2DPLATFORMPIXMAP_H
|
||||
|
||||
#include "qwindowsdirect2dpaintengine.h"
|
||||
#include <QtGui/qpa/qplatformpixmap.h>
|
||||
#include <QtCore/QScopedPointer>
|
||||
|
||||
@ -57,7 +58,7 @@ public:
|
||||
QWindowsDirect2DPlatformPixmap(PixelType pixelType);
|
||||
|
||||
// We do NOT take ownership of the bitmap through this constructor!
|
||||
QWindowsDirect2DPlatformPixmap(PixelType pixelType, QWindowsDirect2DBitmap *bitmap);
|
||||
QWindowsDirect2DPlatformPixmap(PixelType pixelType, QWindowsDirect2DPaintEngine::Flags flags, QWindowsDirect2DBitmap *bitmap);
|
||||
~QWindowsDirect2DPlatformPixmap();
|
||||
|
||||
void resize(int width, int height) Q_DECL_OVERRIDE;
|
||||
|
@ -54,10 +54,135 @@ QT_BEGIN_NAMESPACE
|
||||
QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data)
|
||||
: QWindowsWindow(window, data)
|
||||
, m_needsFullFlush(true)
|
||||
, m_directRendering(!(data.flags & Qt::FramelessWindowHint && window->format().hasAlpha()))
|
||||
{
|
||||
if (window->type() == Qt::Desktop)
|
||||
return; // No further handling for Qt::Desktop
|
||||
|
||||
if (m_directRendering)
|
||||
setupSwapChain();
|
||||
|
||||
HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext(
|
||||
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
|
||||
m_deviceContext.GetAddressOf());
|
||||
if (FAILED(hr))
|
||||
qWarning("%s: Couldn't create Direct2D Device context: %#x", __FUNCTION__, hr);
|
||||
}
|
||||
|
||||
QWindowsDirect2DWindow::~QWindowsDirect2DWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::setWindowFlags(Qt::WindowFlags flags)
|
||||
{
|
||||
m_directRendering = !(flags & Qt::FramelessWindowHint && window()->format().hasAlpha());
|
||||
if (!m_directRendering)
|
||||
m_swapChain.Reset(); // No need for the swap chain; release from memory
|
||||
else if (!m_swapChain)
|
||||
setupSwapChain();
|
||||
|
||||
QWindowsWindow::setWindowFlags(flags);
|
||||
}
|
||||
|
||||
QPixmap *QWindowsDirect2DWindow::pixmap()
|
||||
{
|
||||
setupBitmap();
|
||||
|
||||
return m_pixmap.data();
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset)
|
||||
{
|
||||
QSize size;
|
||||
if (m_directRendering) {
|
||||
DXGI_SWAP_CHAIN_DESC1 desc;
|
||||
HRESULT hr = m_swapChain->GetDesc1(&desc);
|
||||
QRect geom = geometry();
|
||||
|
||||
if ((FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height()))) {
|
||||
resizeSwapChain(geom.size());
|
||||
m_swapChain->GetDesc1(&desc);
|
||||
}
|
||||
size.setWidth(desc.Width);
|
||||
size.setHeight(desc.Height);
|
||||
} else {
|
||||
size = geometry().size();
|
||||
}
|
||||
|
||||
setupBitmap();
|
||||
if (!m_bitmap)
|
||||
return;
|
||||
|
||||
if (bitmap != m_bitmap.data()) {
|
||||
m_bitmap->deviceContext()->begin();
|
||||
|
||||
ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get();
|
||||
if (!m_needsFullFlush) {
|
||||
QRegion clipped = region;
|
||||
clipped &= QRect(QPoint(), size);
|
||||
|
||||
foreach (const QRect &rect, clipped.rects()) {
|
||||
QRectF rectF(rect);
|
||||
dc->DrawBitmap(bitmap->bitmap(),
|
||||
to_d2d_rect_f(rectF),
|
||||
1.0,
|
||||
D2D1_INTERPOLATION_MODE_LINEAR,
|
||||
to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
|
||||
}
|
||||
} else {
|
||||
QRectF rectF(QPoint(), size);
|
||||
dc->DrawBitmap(bitmap->bitmap(),
|
||||
to_d2d_rect_f(rectF),
|
||||
1.0,
|
||||
D2D1_INTERPOLATION_MODE_LINEAR,
|
||||
to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
|
||||
m_needsFullFlush = false;
|
||||
}
|
||||
|
||||
m_bitmap->deviceContext()->end();
|
||||
}
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::present(const QRegion ®ion)
|
||||
{
|
||||
if (m_directRendering) {
|
||||
m_swapChain->Present(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ComPtr<IDXGISurface> bitmapSurface;
|
||||
HRESULT hr = m_bitmap->bitmap()->GetSurface(&bitmapSurface);
|
||||
Q_ASSERT(SUCCEEDED(hr));
|
||||
ComPtr<IDXGISurface1> dxgiSurface;
|
||||
hr = bitmapSurface.As(&dxgiSurface);
|
||||
Q_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
HDC hdc;
|
||||
hr = dxgiSurface->GetDC(FALSE, &hdc);
|
||||
if (FAILED(hr)) {
|
||||
qErrnoWarning(hr, "Failed to get DC for presenting the surface");
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect bounds = window()->geometry();
|
||||
const SIZE size = { bounds.width(), bounds.height() };
|
||||
const POINT ptDst = { bounds.x(), bounds.y() };
|
||||
const POINT ptSrc = { 0, 0 };
|
||||
const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255.0 * opacity(), AC_SRC_ALPHA };
|
||||
const QRect r = region.boundingRect();
|
||||
const RECT dirty = { r.left(), r.top(), r.left() + r.width(), r.top() + r.height() };
|
||||
UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), NULL,
|
||||
&ptDst, &size, hdc, &ptSrc, 0, &blend, ULW_ALPHA, &dirty };
|
||||
if (!UpdateLayeredWindowIndirect(handle(), &info))
|
||||
qErrnoWarning(GetLastError(), "Failed to update the layered window");
|
||||
|
||||
hr = dxgiSurface->ReleaseDC(NULL);
|
||||
if (FAILED(hr))
|
||||
qErrnoWarning(hr, "Failed to release the DC for presentation");
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::setupSwapChain()
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
||||
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
@ -77,72 +202,7 @@ QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWi
|
||||
if (FAILED(hr))
|
||||
qWarning("%s: Could not create swap chain: %#x", __FUNCTION__, hr);
|
||||
|
||||
hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext(
|
||||
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
|
||||
m_deviceContext.GetAddressOf());
|
||||
if (FAILED(hr))
|
||||
qWarning("%s: Couldn't create Direct2D Device context: %#x", __FUNCTION__, hr);
|
||||
}
|
||||
|
||||
QWindowsDirect2DWindow::~QWindowsDirect2DWindow()
|
||||
{
|
||||
}
|
||||
|
||||
QPixmap *QWindowsDirect2DWindow::pixmap()
|
||||
{
|
||||
setupBitmap();
|
||||
|
||||
return m_pixmap.data();
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset)
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC1 desc;
|
||||
HRESULT hr = m_swapChain->GetDesc1(&desc);
|
||||
QRect geom = geometry();
|
||||
|
||||
if (FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height())) {
|
||||
resizeSwapChain(geom.size());
|
||||
m_swapChain->GetDesc1(&desc);
|
||||
}
|
||||
|
||||
setupBitmap();
|
||||
if (!m_bitmap)
|
||||
return;
|
||||
|
||||
if (bitmap != m_bitmap.data()) {
|
||||
m_bitmap->deviceContext()->begin();
|
||||
|
||||
ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get();
|
||||
if (!m_needsFullFlush) {
|
||||
QRegion clipped = region;
|
||||
clipped &= QRect(0, 0, desc.Width, desc.Height);
|
||||
|
||||
foreach (const QRect &rect, clipped.rects()) {
|
||||
QRectF rectF(rect);
|
||||
dc->DrawBitmap(bitmap->bitmap(),
|
||||
to_d2d_rect_f(rectF),
|
||||
1.0,
|
||||
D2D1_INTERPOLATION_MODE_LINEAR,
|
||||
to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
|
||||
}
|
||||
} else {
|
||||
QRectF rectF(0, 0, desc.Width, desc.Height);
|
||||
dc->DrawBitmap(bitmap->bitmap(),
|
||||
to_d2d_rect_f(rectF),
|
||||
1.0,
|
||||
D2D1_INTERPOLATION_MODE_LINEAR,
|
||||
to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
|
||||
m_needsFullFlush = false;
|
||||
}
|
||||
|
||||
m_bitmap->deviceContext()->end();
|
||||
}
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::present()
|
||||
{
|
||||
m_swapChain->Present(0, 0);
|
||||
m_needsFullFlush = true;
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size)
|
||||
@ -209,14 +269,34 @@ void QWindowsDirect2DWindow::setupBitmap()
|
||||
if (!m_deviceContext)
|
||||
return;
|
||||
|
||||
if (!m_swapChain)
|
||||
if (m_directRendering && !m_swapChain)
|
||||
return;
|
||||
|
||||
HRESULT hr;
|
||||
ComPtr<IDXGISurface1> backBufferSurface;
|
||||
HRESULT hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface));
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr);
|
||||
return;
|
||||
if (m_directRendering) {
|
||||
hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface));
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const QRect rect = geometry();
|
||||
CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, rect.width(), rect.height(), 1, 1);
|
||||
backBufferDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
|
||||
backBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
|
||||
ComPtr<ID3D11Texture2D> backBufferTexture;
|
||||
HRESULT hr = QWindowsDirect2DContext::instance()->d3dDevice()->CreateTexture2D(&backBufferDesc, NULL, &backBufferTexture);
|
||||
if (FAILED(hr)) {
|
||||
qErrnoWarning(hr, "Failed to create backing texture for indirect rendering");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = backBufferTexture.As(&backBufferSurface);
|
||||
if (FAILED(hr)) {
|
||||
qErrnoWarning(hr, "Failed to cast back buffer surface to DXGI surface");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ComPtr<ID2D1Bitmap1> backBufferBitmap;
|
||||
@ -228,7 +308,11 @@ void QWindowsDirect2DWindow::setupBitmap()
|
||||
|
||||
m_bitmap.reset(new QWindowsDirect2DBitmap(backBufferBitmap.Get(), m_deviceContext.Get()));
|
||||
|
||||
QWindowsDirect2DPaintEngine::Flags flags = QWindowsDirect2DPaintEngine::NoFlag;
|
||||
if (!m_directRendering)
|
||||
flags |= QWindowsDirect2DPaintEngine::UseGrayscaleAntialiasing;
|
||||
QWindowsDirect2DPlatformPixmap *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType,
|
||||
flags,
|
||||
m_bitmap.data());
|
||||
m_pixmap.reset(new QPixmap(pp));
|
||||
}
|
||||
|
@ -56,9 +56,12 @@ public:
|
||||
QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data);
|
||||
~QWindowsDirect2DWindow();
|
||||
|
||||
void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE;
|
||||
|
||||
QPixmap *pixmap();
|
||||
void flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset);
|
||||
void present();
|
||||
void present(const QRegion ®ion);
|
||||
void setupSwapChain();
|
||||
void resizeSwapChain(const QSize &size);
|
||||
|
||||
QSharedPointer<QWindowsDirect2DBitmap> copyBackBuffer() const;
|
||||
@ -72,6 +75,7 @@ private:
|
||||
QScopedPointer<QWindowsDirect2DBitmap> m_bitmap;
|
||||
QScopedPointer<QPixmap> m_pixmap;
|
||||
bool m_needsFullFlush;
|
||||
bool m_directRendering;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -65,17 +65,22 @@ static QBlittable::Capabilities dfb_blitter_capabilities()
|
||||
|
||||
QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, IDirectFBSurface *surface)
|
||||
: QBlittable(rect, dfb_blitter_capabilities())
|
||||
, m_surface(surface)
|
||||
, m_surface(surface)
|
||||
, m_debugPaint(false)
|
||||
{
|
||||
m_surface->AddRef(m_surface.data());
|
||||
|
||||
DFBSurfaceCapabilities surfaceCaps;
|
||||
m_surface->GetCapabilities(m_surface.data(), &surfaceCaps);
|
||||
m_premult = (surfaceCaps & DSCAPS_PREMULTIPLIED);
|
||||
if (qgetenv("QT_DIRECTFB_BLITTER_DEBUGPAINT").toInt())
|
||||
m_debugPaint = true;
|
||||
}
|
||||
|
||||
QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, bool alpha)
|
||||
: QBlittable(rect, dfb_blitter_capabilities()), m_premult(false)
|
||||
: QBlittable(rect, dfb_blitter_capabilities())
|
||||
, m_premult(false)
|
||||
, m_debugPaint(false)
|
||||
{
|
||||
DFBSurfaceDescription surfaceDesc;
|
||||
memset(&surfaceDesc,0,sizeof(DFBSurfaceDescription));
|
||||
@ -95,6 +100,9 @@ QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, bool alpha)
|
||||
surfaceDesc.pixelformat = QDirectFbBlitter::pixmapFormat();
|
||||
}
|
||||
|
||||
if (qgetenv("QT_DIRECTFB_BLITTER_DEBUGPAINT").toInt())
|
||||
m_debugPaint = true;
|
||||
|
||||
IDirectFB *dfb = QDirectFbConvenience::dfbInterface();
|
||||
dfb->CreateSurface(dfb , &surfaceDesc, m_surface.outPtr());
|
||||
m_surface->Clear(m_surface.data(), 0, 0, 0, 0);
|
||||
@ -165,6 +173,8 @@ void QDirectFbBlitter::alphaFillRect(const QRectF &rect, const QColor &color, QP
|
||||
result = m_surface->FillRectangle(m_surface.data(), x, y, w, h);
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::alphaFillRect()", result);
|
||||
if (m_debugPaint)
|
||||
drawDebugRect(QRect(x, y, w, h), QColor(Qt::blue));
|
||||
}
|
||||
|
||||
void QDirectFbBlitter::drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity)
|
||||
@ -203,13 +213,19 @@ void QDirectFbBlitter::drawPixmapOpacity(const QRectF &rect, const QPixmap &pixm
|
||||
if (cmode == QPainter::CompositionMode_SourceOver)
|
||||
m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA);
|
||||
|
||||
if ((sRect.w == dRect.w) && (sRect.h == dRect.h))
|
||||
if ((sRect.w == dRect.w) && (sRect.h == dRect.h)) {
|
||||
result = m_surface->Blit(m_surface.data(), s, &sRect, dRect.x, dRect.y);
|
||||
else
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawPixmapOpacity()", result);
|
||||
if (m_debugPaint)
|
||||
drawDebugRect(QRect(dRect.x, dRect.y, sRect.w, sRect.h), QColor(Qt::green));
|
||||
} else {
|
||||
result = m_surface->StretchBlit(m_surface.data(), s, &sRect, &dRect);
|
||||
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawPixmapExtended()", result);
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawPixmapOpacity()", result);
|
||||
if (m_debugPaint)
|
||||
drawDebugRect(QRect(dRect.x, dRect.y, dRect.w, dRect.h), QColor(Qt::red));
|
||||
}
|
||||
}
|
||||
|
||||
bool QDirectFbBlitter::drawCachedGlyphs(const QPaintEngineState *state, QFontEngine::GlyphFormat glyphFormat, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine)
|
||||
@ -287,6 +303,12 @@ bool QDirectFbBlitter::drawCachedGlyphs(const QPaintEngineState *state, QFontEng
|
||||
|
||||
m_surface->BatchBlit(m_surface.data(), cache->sourceSurface(), sourceRects.constData(), destPoints.constData(), nGlyphs);
|
||||
|
||||
if (m_debugPaint) {
|
||||
for (int i = 0; i < nGlyphs; ++i) {
|
||||
drawDebugRect(QRect(destPoints[i].x, destPoints[i].y, sourceRects[i].w, sourceRects[i].h), QColor(Qt::yellow));
|
||||
}
|
||||
}
|
||||
|
||||
if (rs->clip && rs->clip->enabled)
|
||||
m_surface->SetClip(m_surface.data(), 0);
|
||||
return true;
|
||||
@ -403,6 +425,41 @@ void QDirectFbBlitter::doUnlock()
|
||||
m_surface->Unlock(m_surface.data());
|
||||
}
|
||||
|
||||
void QDirectFbBlitter::drawDebugRect(const QRect &rect, const QColor &color)
|
||||
{
|
||||
int x, y, w, h;
|
||||
DFBResult result;
|
||||
|
||||
// check parameters
|
||||
rect.getRect(&x, &y ,&w, &h);
|
||||
if ((w <= 0) || (h <= 0)) return;
|
||||
|
||||
m_surface->SetDrawingFlags(m_surface.data(),
|
||||
DFBSurfaceDrawingFlags(m_premult ? (DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY) : DSDRAW_BLEND));
|
||||
m_surface->SetPorterDuff(m_surface.data(), DSPD_SRC_OVER);
|
||||
|
||||
// set color
|
||||
m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), 120);
|
||||
|
||||
result = m_surface->DrawLine(m_surface.data(), x, y, x + w-1, y);
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
|
||||
result = m_surface->DrawLine(m_surface.data(), x + w-1, y, x + w-1, y + h-1);
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
|
||||
result = m_surface->DrawLine(m_surface.data(), x + w-1, y + h-1, x, y + h-1);
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
|
||||
result = m_surface->DrawLine(m_surface.data(), x, y + h-1, x, y);
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
|
||||
|
||||
m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), 10);
|
||||
result = m_surface->FillRectangle(m_surface.data(), x, y, w, h);
|
||||
if (result != DFB_OK)
|
||||
DirectFBError("QDirectFBBlitter::drawDebugRect()", result);
|
||||
}
|
||||
|
||||
void QDirectFbTextureGlyphCache::resizeTextureData(int width, int height)
|
||||
{
|
||||
m_surface.reset();;
|
||||
|
@ -79,7 +79,10 @@ protected:
|
||||
friend class QDirectFbConvenience;
|
||||
|
||||
private:
|
||||
void drawDebugRect(const QRect &rect, const QColor &color);
|
||||
|
||||
bool m_premult;
|
||||
bool m_debugPaint;
|
||||
};
|
||||
|
||||
class QDirectFbBlitterPlatformPixmap : public QBlittablePlatformPixmap
|
||||
|
@ -8,6 +8,11 @@ DEFINES += MESA_EGL_NO_X11_HEADERS
|
||||
# EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_x11.cpp
|
||||
# LIBS += -lX11 -lX11-xcb -lxcb
|
||||
|
||||
# Uncomment these to enable the KMS hooks.
|
||||
# EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_kms.cpp
|
||||
# CONFIG += link_pkgconfig
|
||||
# PKGCONFIG += libdrm gbm
|
||||
|
||||
SOURCES += $$PWD/qeglfsintegration.cpp \
|
||||
$$PWD/qeglfswindow.cpp \
|
||||
$$PWD/qeglfsscreen.cpp \
|
||||
|
422
src/plugins/platforms/eglfs/qeglfshooks_kms.cpp
Normal file
422
src/plugins/platforms/eglfs/qeglfshooks_kms.cpp
Normal file
@ -0,0 +1,422 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the qmake spec 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 "qeglfshooks.h"
|
||||
#include <QtPlatformSupport/private/qdevicediscovery_p.h>
|
||||
#include <QtCore/private/qcore_unix_p.h>
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtGui/qpa/qplatformwindow.h>
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <gbm.h>
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
class QEglKmsHooks : public QEglFSHooks
|
||||
{
|
||||
public:
|
||||
QEglKmsHooks();
|
||||
|
||||
void platformInit() Q_DECL_OVERRIDE;
|
||||
void platformDestroy() Q_DECL_OVERRIDE;
|
||||
EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
|
||||
QSizeF physicalScreenSize() const Q_DECL_OVERRIDE;
|
||||
QSize screenSize() const Q_DECL_OVERRIDE;
|
||||
int screenDepth() const Q_DECL_OVERRIDE;
|
||||
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const Q_DECL_OVERRIDE;
|
||||
EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
|
||||
const QSize &size,
|
||||
const QSurfaceFormat &format) Q_DECL_OVERRIDE;
|
||||
void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
|
||||
bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
|
||||
void waitForVSync() const Q_DECL_OVERRIDE;
|
||||
|
||||
void waitForVSyncImpl();
|
||||
bool setup_kms();
|
||||
|
||||
struct FrameBuffer {
|
||||
FrameBuffer() : fb(0) {}
|
||||
uint32_t fb;
|
||||
};
|
||||
FrameBuffer *framebufferForBufferObject(gbm_bo *bo);
|
||||
|
||||
private:
|
||||
// device bits
|
||||
QByteArray m_device;
|
||||
int m_dri_fd;
|
||||
gbm_device *m_gbm_device;
|
||||
|
||||
// KMS bits
|
||||
drmModeConnector *m_drm_connector;
|
||||
drmModeEncoder *m_drm_encoder;
|
||||
drmModeModeInfo m_drm_mode;
|
||||
quint32 m_drm_crtc;
|
||||
|
||||
// Drawing bits
|
||||
gbm_surface *m_gbm_surface;
|
||||
};
|
||||
|
||||
static QEglKmsHooks kms_hooks;
|
||||
QEglFSHooks *platformHooks = &kms_hooks;
|
||||
|
||||
QEglKmsHooks::QEglKmsHooks()
|
||||
: m_dri_fd(-1)
|
||||
, m_gbm_device(Q_NULLPTR)
|
||||
, m_drm_connector(Q_NULLPTR)
|
||||
, m_drm_encoder(Q_NULLPTR)
|
||||
, m_drm_crtc(0)
|
||||
, m_gbm_surface(Q_NULLPTR)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QEglKmsHooks::platformInit()
|
||||
{
|
||||
QDeviceDiscovery *d = QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask);
|
||||
QStringList devices = d->scanConnectedDevices();
|
||||
d->deleteLater();
|
||||
|
||||
if (devices.isEmpty())
|
||||
qFatal("Could not find DRM device!");
|
||||
|
||||
m_device = devices.first().toLocal8Bit();
|
||||
m_dri_fd = qt_safe_open(m_device.constData(), O_RDWR | O_CLOEXEC);
|
||||
if (m_dri_fd == -1) {
|
||||
qErrnoWarning("Could not open DRM device %s", m_device.constData());
|
||||
qFatal("DRM device required, aborting.");
|
||||
}
|
||||
|
||||
if (!setup_kms())
|
||||
qFatal("Could not set up KMS on device %s!", m_device.constData());
|
||||
|
||||
m_gbm_device = gbm_create_device(m_dri_fd);
|
||||
if (!m_gbm_device)
|
||||
qFatal("Could not initialize gbm on device %s!", m_device.constData());
|
||||
}
|
||||
|
||||
void QEglKmsHooks::platformDestroy()
|
||||
{
|
||||
gbm_device_destroy(m_gbm_device);
|
||||
m_gbm_device = Q_NULLPTR;
|
||||
|
||||
if (qt_safe_close(m_dri_fd) == -1)
|
||||
qErrnoWarning("Could not close DRM device %s", m_device.constData());
|
||||
|
||||
m_dri_fd = -1;
|
||||
}
|
||||
|
||||
EGLNativeDisplayType QEglKmsHooks::platformDisplay() const
|
||||
{
|
||||
return static_cast<EGLNativeDisplayType>(m_gbm_device);
|
||||
}
|
||||
|
||||
QSizeF QEglKmsHooks::physicalScreenSize() const
|
||||
{
|
||||
return QSizeF(m_drm_connector->mmWidth,
|
||||
m_drm_connector->mmHeight);
|
||||
}
|
||||
|
||||
QSize QEglKmsHooks::screenSize() const
|
||||
{
|
||||
return QSize(m_drm_mode.hdisplay,
|
||||
m_drm_mode.vdisplay);
|
||||
}
|
||||
|
||||
int QEglKmsHooks::screenDepth() const
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
QSurfaceFormat QEglKmsHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
|
||||
{
|
||||
QSurfaceFormat format(inputFormat);
|
||||
format.setRenderableType(QSurfaceFormat::OpenGLES);
|
||||
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
|
||||
format.setRedBufferSize(8);
|
||||
format.setGreenBufferSize(8);
|
||||
format.setBlueBufferSize(8);
|
||||
return format;
|
||||
}
|
||||
|
||||
EGLNativeWindowType QEglKmsHooks::createNativeWindow(QPlatformWindow *platformWindow,
|
||||
const QSize &size,
|
||||
const QSurfaceFormat &format)
|
||||
{
|
||||
Q_UNUSED(platformWindow);
|
||||
Q_UNUSED(size);
|
||||
Q_UNUSED(format);
|
||||
|
||||
if (m_gbm_surface) {
|
||||
qWarning("Only single window apps supported!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_gbm_surface = gbm_surface_create(m_gbm_device,
|
||||
screenSize().width(),
|
||||
screenSize().height(),
|
||||
GBM_FORMAT_XRGB8888,
|
||||
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
||||
if (!m_gbm_surface)
|
||||
qFatal("Could not initialize GBM surface");
|
||||
|
||||
return reinterpret_cast<EGLNativeWindowType>(m_gbm_surface);
|
||||
}
|
||||
|
||||
void QEglKmsHooks::destroyNativeWindow(EGLNativeWindowType window)
|
||||
{
|
||||
gbm_surface *surface = reinterpret_cast<gbm_surface *>(window);
|
||||
if (surface == m_gbm_surface)
|
||||
m_gbm_surface = Q_NULLPTR;
|
||||
gbm_surface_destroy(surface);
|
||||
}
|
||||
|
||||
bool QEglKmsHooks::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
{
|
||||
switch (cap) {
|
||||
case QPlatformIntegration::ThreadedPixmaps:
|
||||
case QPlatformIntegration::OpenGL:
|
||||
case QPlatformIntegration::ThreadedOpenGL:
|
||||
case QPlatformIntegration::BufferQueueingOpenGL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void gbm_bo_destroyed_callback(gbm_bo *bo, void *data)
|
||||
{
|
||||
QEglKmsHooks::FrameBuffer *fb = static_cast<QEglKmsHooks::FrameBuffer *>(data);
|
||||
|
||||
if (fb->fb) {
|
||||
gbm_device *device = gbm_bo_get_device(bo);
|
||||
drmModeRmFB(gbm_device_get_fd(device), fb->fb);
|
||||
}
|
||||
|
||||
delete fb;
|
||||
}
|
||||
|
||||
QEglKmsHooks::FrameBuffer *QEglKmsHooks::framebufferForBufferObject(gbm_bo *bo)
|
||||
{
|
||||
{
|
||||
FrameBuffer *fb = static_cast<FrameBuffer *>(gbm_bo_get_user_data(bo));
|
||||
if (fb)
|
||||
return fb;
|
||||
}
|
||||
|
||||
uint32_t width = gbm_bo_get_width(bo);
|
||||
uint32_t height = gbm_bo_get_height(bo);
|
||||
uint32_t stride = gbm_bo_get_stride(bo);
|
||||
uint32_t handle = gbm_bo_get_handle(bo).u32;
|
||||
|
||||
QScopedPointer<FrameBuffer> fb(new FrameBuffer);
|
||||
|
||||
int ret = drmModeAddFB(m_dri_fd, width, height, 24, 32,
|
||||
stride, handle, &fb->fb);
|
||||
|
||||
if (ret) {
|
||||
qWarning("Failed to create KMS FB!");
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
gbm_bo_set_user_data(bo, fb.data(), gbm_bo_destroyed_callback);
|
||||
return fb.take();
|
||||
}
|
||||
|
||||
static void page_flip_handler(int fd,
|
||||
unsigned int sequence,
|
||||
unsigned int tv_sec,
|
||||
unsigned int tv_usec,
|
||||
void *user_data)
|
||||
{
|
||||
Q_UNUSED(fd);
|
||||
Q_UNUSED(sequence);
|
||||
Q_UNUSED(tv_sec);
|
||||
Q_UNUSED(tv_usec);
|
||||
|
||||
// We are no longer flipping
|
||||
*static_cast<bool *>(user_data) = false;
|
||||
}
|
||||
|
||||
void QEglKmsHooks::waitForVSync() const
|
||||
{
|
||||
const_cast<QEglKmsHooks*>(this)->waitForVSyncImpl();
|
||||
}
|
||||
|
||||
void QEglKmsHooks::waitForVSyncImpl()
|
||||
{
|
||||
if (!m_gbm_surface) {
|
||||
qWarning("Cannot sync before platform init!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gbm_surface_has_free_buffers(m_gbm_surface)) {
|
||||
qWarning("Out of free GBM buffers!");
|
||||
return;
|
||||
}
|
||||
|
||||
gbm_bo *front_buffer = gbm_surface_lock_front_buffer(m_gbm_surface);
|
||||
if (!front_buffer) {
|
||||
qWarning("Could not lock GBM surface front buffer!");
|
||||
return;
|
||||
}
|
||||
|
||||
QEglKmsHooks::FrameBuffer *fb = framebufferForBufferObject(front_buffer);
|
||||
|
||||
int ret = drmModeSetCrtc(m_dri_fd,
|
||||
m_drm_crtc,
|
||||
fb->fb,
|
||||
0, 0,
|
||||
&m_drm_connector->connector_id, 1,
|
||||
&m_drm_mode);
|
||||
if (ret) {
|
||||
qErrnoWarning("Could not set DRM mode!");
|
||||
return;
|
||||
}
|
||||
|
||||
bool flipping = true;
|
||||
ret = drmModePageFlip(m_dri_fd,
|
||||
m_drm_encoder->crtc_id,
|
||||
fb->fb,
|
||||
DRM_MODE_PAGE_FLIP_EVENT,
|
||||
&flipping);
|
||||
if (ret) {
|
||||
qErrnoWarning("Could not queue DRM page flip!");
|
||||
return;
|
||||
}
|
||||
|
||||
drmEventContext drmEvent = {
|
||||
DRM_EVENT_CONTEXT_VERSION,
|
||||
Q_NULLPTR, // vblank handler
|
||||
page_flip_handler // page flip handler
|
||||
};
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(m_dri_fd, &fds);
|
||||
|
||||
time_t start, cur;
|
||||
time(&start);
|
||||
|
||||
while (flipping && (time(&cur) < start + 1)) {
|
||||
timespec v;
|
||||
memset(&v, 0, sizeof(v));
|
||||
v.tv_sec = start + 1 - cur;
|
||||
|
||||
ret = qt_safe_select(m_dri_fd + 1, &fds, Q_NULLPTR, Q_NULLPTR, &v);
|
||||
|
||||
if (ret == 0) {
|
||||
// timeout
|
||||
break;
|
||||
} else if (ret == -1) {
|
||||
qErrnoWarning("Error while selecting on DRM fd");
|
||||
break;
|
||||
} else if (drmHandleEvent(m_dri_fd, &drmEvent)) {
|
||||
qWarning("Could not handle DRM event!");
|
||||
}
|
||||
}
|
||||
|
||||
gbm_surface_release_buffer(m_gbm_surface, front_buffer);
|
||||
}
|
||||
|
||||
bool QEglKmsHooks::setup_kms()
|
||||
{
|
||||
drmModeRes *resources;
|
||||
drmModeConnector *connector;
|
||||
drmModeEncoder *encoder;
|
||||
quint32 crtc = 0;
|
||||
int i;
|
||||
|
||||
resources = drmModeGetResources(m_dri_fd);
|
||||
if (!resources) {
|
||||
qWarning("drmModeGetResources failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < resources->count_connectors; i++) {
|
||||
connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
|
||||
if (connector == NULL)
|
||||
continue;
|
||||
|
||||
if (connector->connection == DRM_MODE_CONNECTED &&
|
||||
connector->count_modes > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
drmModeFreeConnector(connector);
|
||||
}
|
||||
|
||||
if (i == resources->count_connectors) {
|
||||
qWarning("No currently active connector found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < resources->count_encoders; i++) {
|
||||
encoder = drmModeGetEncoder(m_dri_fd, resources->encoders[i]);
|
||||
|
||||
if (encoder == NULL)
|
||||
continue;
|
||||
|
||||
if (encoder->encoder_id == connector->encoder_id)
|
||||
break;
|
||||
|
||||
drmModeFreeEncoder(encoder);
|
||||
}
|
||||
|
||||
for (int j = 0; j < resources->count_crtcs; j++) {
|
||||
if ((encoder->possible_crtcs & (1 << j))) {
|
||||
crtc = resources->crtcs[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (crtc == 0)
|
||||
qFatal("No suitable CRTC available");
|
||||
|
||||
m_drm_connector = connector;
|
||||
m_drm_encoder = encoder;
|
||||
m_drm_mode = connector->modes[0];
|
||||
m_drm_crtc = crtc;
|
||||
|
||||
drmModeFreeResources(resources);
|
||||
|
||||
return true;
|
||||
}
|
@ -120,13 +120,12 @@ QEGLPlatformContext *QEglFSIntegration::createContext(const QSurfaceFormat &form
|
||||
QVariant *nativeHandle) const
|
||||
{
|
||||
QEglFSContext *ctx;
|
||||
QSurfaceFormat adjustedFormat = QEglFSHooks::hooks()->surfaceFormatFor(format);
|
||||
if (!nativeHandle || nativeHandle->isNull()) {
|
||||
EGLConfig config = QEglFSIntegration::chooseConfig(display, format);
|
||||
ctx = new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display,
|
||||
&config, QVariant());
|
||||
EGLConfig config = QEglFSIntegration::chooseConfig(display, adjustedFormat);
|
||||
ctx = new QEglFSContext(adjustedFormat, shareContext, display, &config, QVariant());
|
||||
} else {
|
||||
ctx = new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display,
|
||||
0, *nativeHandle);
|
||||
ctx = new QEglFSContext(adjustedFormat, shareContext, display, 0, *nativeHandle);
|
||||
}
|
||||
*nativeHandle = QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx->eglContext(), display));
|
||||
return ctx;
|
||||
|
@ -166,7 +166,7 @@
|
||||
self.enabled = YES;
|
||||
if (!m_duration) {
|
||||
m_duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||
m_curve = UIViewAnimationCurve([[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16);
|
||||
m_curve = UIViewAnimationCurve([[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue]);
|
||||
}
|
||||
m_context->scrollToCursor();
|
||||
}
|
||||
@ -389,7 +389,7 @@ void QIOSInputContext::scroll(int y)
|
||||
newBounds.origin.y = y;
|
||||
QPointer<QIOSInputContext> self = this;
|
||||
[UIView animateWithDuration:m_keyboardListener->m_duration delay:0
|
||||
options:m_keyboardListener->m_curve | UIViewAnimationOptionBeginFromCurrentState
|
||||
options:(m_keyboardListener->m_curve << 16) | UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{ view.bounds = newBounds; }
|
||||
completion:^(BOOL){
|
||||
if (self)
|
||||
|
@ -184,25 +184,6 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
|
||||
, m_uiWindow(0)
|
||||
, m_orientationListener(0)
|
||||
{
|
||||
for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) {
|
||||
if (existingWindow.screen == m_uiScreen) {
|
||||
m_uiWindow = [m_uiWindow retain];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_uiWindow) {
|
||||
// Create a window and associated view-controller that we can use
|
||||
m_uiWindow = [[UIWindow alloc] initWithFrame:[m_uiScreen bounds]];
|
||||
m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
|
||||
|
||||
// FIXME: Only do once windows are added to the screen, and for any screen
|
||||
if (screen == [UIScreen mainScreen]) {
|
||||
m_uiWindow.screen = m_uiScreen;
|
||||
m_uiWindow.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
if (screen == [UIScreen mainScreen]) {
|
||||
QString deviceIdentifier = deviceModelIdentifier();
|
||||
|
||||
@ -225,6 +206,25 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
|
||||
m_unscaledDpi = 96;
|
||||
}
|
||||
|
||||
for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) {
|
||||
if (existingWindow.screen == m_uiScreen) {
|
||||
m_uiWindow = [m_uiWindow retain];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_uiWindow) {
|
||||
// Create a window and associated view-controller that we can use
|
||||
m_uiWindow = [[UIWindow alloc] initWithFrame:[m_uiScreen bounds]];
|
||||
m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
|
||||
|
||||
// FIXME: Only do once windows are added to the screen, and for any screen
|
||||
if (screen == [UIScreen mainScreen]) {
|
||||
m_uiWindow.screen = m_uiScreen;
|
||||
m_uiWindow.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSScreen::updateStatusBarVisibility);
|
||||
|
||||
updateProperties();
|
||||
@ -373,8 +373,15 @@ qreal QIOSScreen::devicePixelRatio() const
|
||||
|
||||
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
|
||||
{
|
||||
// A UIScreen stays in the native orientation, regardless of rotation
|
||||
return m_uiScreen.bounds.size.width >= m_uiScreen.bounds.size.height ?
|
||||
CGRect nativeBounds =
|
||||
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
||||
QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0 ? m_uiScreen.nativeBounds :
|
||||
#endif
|
||||
m_uiScreen.bounds;
|
||||
|
||||
// All known iOS devices have a native orientation of portrait, but to
|
||||
// be on the safe side we compare the width and height of the bounds.
|
||||
return nativeBounds.size.width >= nativeBounds.size.height ?
|
||||
Qt::LandscapeOrientation : Qt::PortraitOrientation;
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ public:
|
||||
void setParent(const QPlatformWindow *window);
|
||||
void handleContentOrientationChange(Qt::ScreenOrientation orientation);
|
||||
void setVisible(bool visible);
|
||||
void setOpacity(qreal level) Q_DECL_OVERRIDE;
|
||||
|
||||
bool isExposed() const Q_DECL_OVERRIDE;
|
||||
|
||||
|
@ -74,6 +74,7 @@ QIOSWindow::QIOSWindow(QWindow *window)
|
||||
screen()->availableGeometry().width(), screen()->availableGeometry().height());
|
||||
|
||||
setWindowState(window->windowState());
|
||||
setOpacity(window->opacity());
|
||||
}
|
||||
|
||||
QIOSWindow::~QIOSWindow()
|
||||
@ -135,6 +136,11 @@ void QIOSWindow::setVisible(bool visible)
|
||||
}
|
||||
}
|
||||
|
||||
void QIOSWindow::setOpacity(qreal level)
|
||||
{
|
||||
m_view.alpha = qBound(0.0, level, 1.0);
|
||||
}
|
||||
|
||||
void QIOSWindow::setGeometry(const QRect &rect)
|
||||
{
|
||||
m_normalGeometry = rect;
|
||||
|
@ -49,19 +49,11 @@ class StaticVariables
|
||||
public:
|
||||
QInputMethodQueryEvent inputMethodQueryEvent;
|
||||
bool inUpdateKeyboardLayout;
|
||||
QTextCharFormat markedTextFormat;
|
||||
|
||||
StaticVariables()
|
||||
: inputMethodQueryEvent(Qt::ImQueryInput)
|
||||
, inUpdateKeyboardLayout(false)
|
||||
{
|
||||
// There seems to be no way to query how the preedit text
|
||||
// should be drawn. So we need to hard-code the color.
|
||||
QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion;
|
||||
if (iosVersion < QSysInfo::MV_IOS_7_0)
|
||||
markedTextFormat.setBackground(QColor(235, 239, 247));
|
||||
else
|
||||
markedTextFormat.setBackground(QColor(206, 221, 238));
|
||||
}
|
||||
};
|
||||
|
||||
@ -301,8 +293,19 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
|
||||
|
||||
m_markedText = markedText ? QString::fromNSString(markedText) : QString();
|
||||
|
||||
static QTextCharFormat markedTextFormat;
|
||||
if (markedTextFormat.isEmpty()) {
|
||||
// There seems to be no way to query how the preedit text
|
||||
// should be drawn. So we need to hard-code the color.
|
||||
QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion;
|
||||
if (iosVersion < QSysInfo::MV_IOS_7_0)
|
||||
markedTextFormat.setBackground(QColor(235, 239, 247));
|
||||
else
|
||||
markedTextFormat.setBackground(QColor(206, 221, 238));
|
||||
}
|
||||
|
||||
QList<QInputMethodEvent::Attribute> attrs;
|
||||
attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, markedText.length, staticVariables()->markedTextFormat);
|
||||
attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, markedText.length, markedTextFormat);
|
||||
QInputMethodEvent e(m_markedText, attrs);
|
||||
[self sendEventToFocusObject:e];
|
||||
}
|
||||
|
@ -38,7 +38,6 @@
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
//#include <QDebug>
|
||||
|
||||
#include "qkmsscreen.h"
|
||||
#include "qkmscursor.h"
|
||||
@ -52,6 +51,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.kms.screen")
|
||||
|
||||
//Fallback mode (taken from Wayland DRM demo compositor)
|
||||
static drmModeModeInfo builtin_1024x768 = {
|
||||
63500, //clock
|
||||
@ -148,7 +149,7 @@ void QKmsScreen::initializeScreenMode(const drmModeRes *resources, const drmMode
|
||||
m_crtcId = resources->crtcs[i];
|
||||
m_mode = *mode;
|
||||
m_geometry = QRect(0, 0, m_mode.hdisplay, m_mode.vdisplay);
|
||||
qDebug() << "kms initialized with geometry" << m_geometry;
|
||||
qCDebug(lcQpaScreen) << "kms initialized with geometry" << m_geometry;
|
||||
m_depth = 32;
|
||||
m_format = QImage::Format_RGB32;
|
||||
m_physicalSize = QSizeF(connector->mmWidth, connector->mmHeight);
|
||||
@ -158,7 +159,7 @@ void QKmsScreen::initializeScreenMode(const drmModeRes *resources, const drmMode
|
||||
GBM_BO_FORMAT_XRGB8888,
|
||||
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
||||
|
||||
qDebug() << "created gbm surface" << m_gbmSurface << m_mode.hdisplay << m_mode.vdisplay;
|
||||
qCDebug(lcQpaScreen) << "created gbm surface" << m_gbmSurface << m_mode.hdisplay << m_mode.vdisplay;
|
||||
//Cleanup
|
||||
drmModeFreeEncoder(encoder);
|
||||
}
|
||||
@ -180,7 +181,7 @@ void QKmsScreen::initializeWithFormat(const QSurfaceFormat &format)
|
||||
EGLConfig config = q_configFromGLFormat(display, tweakFormat(format), true);
|
||||
|
||||
m_eglWindowSurface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_gbmSurface, NULL);
|
||||
qDebug() << "created window surface";
|
||||
qCDebug(lcQpaScreen) << "created window surface";
|
||||
}
|
||||
|
||||
void QKmsScreen::swapBuffers()
|
||||
|
@ -56,11 +56,14 @@ extern "C" {
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <QtGui/qopengl.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
#include <qpa/qplatformscreen.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
|
||||
|
||||
class QKmsCursor;
|
||||
class QKmsDevice;
|
||||
class QKmsContext;
|
||||
|
@ -35,7 +35,7 @@ contains(QT_CONFIG, directfb) {
|
||||
SUBDIRS += directfb
|
||||
}
|
||||
|
||||
contains(QT_CONFIG, kms) {
|
||||
contains(QT_CONFIG, kms):contains(QT_CONFIG, opengl) {
|
||||
SUBDIRS += kms
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,11 @@
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
#if defined(QT_OPENGL_ES_2_ANGLE) || defined(QT_OPENGL_DYNAMIC)
|
||||
# define EGL_EGLEXT_PROTOTYPES
|
||||
# include <QtANGLE/EGL/eglext.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
@ -140,6 +145,7 @@ bool QWindowsLibEGL::init()
|
||||
|
||||
eglGetError = RESOLVE((EGLint (EGLAPIENTRY *)(void)), eglGetError);
|
||||
eglGetDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)), eglGetDisplay);
|
||||
eglGetPlatformDisplayEXT = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLenum platform, void *native_display, const EGLint *attrib_list)), eglGetPlatformDisplayEXT);
|
||||
eglInitialize = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)), eglInitialize);
|
||||
eglTerminate = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay)), eglTerminate);
|
||||
eglChooseConfig = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)), eglChooseConfig);
|
||||
@ -359,7 +365,31 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create()
|
||||
return 0;
|
||||
}
|
||||
|
||||
EGLDisplay display = libEGL.eglGetDisplay((EGLNativeDisplayType)dc);
|
||||
EGLDisplay display = EGL_NO_DISPLAY;
|
||||
#ifdef EGL_ANGLE_platform_angle_opengl
|
||||
if (libEGL.eglGetPlatformDisplayEXT && qEnvironmentVariableIsSet("QT_ANGLE_PLATFORM")) {
|
||||
const EGLint anglePlatformAttributes[][3] = {
|
||||
{ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE },
|
||||
{ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE },
|
||||
{ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE, EGL_NONE }
|
||||
};
|
||||
const EGLint *attributes = 0;
|
||||
const QByteArray anglePlatform = qgetenv("QT_ANGLE_PLATFORM");
|
||||
if (anglePlatform == "d3d11")
|
||||
attributes = anglePlatformAttributes[0];
|
||||
else if (anglePlatform == "d3d9")
|
||||
attributes = anglePlatformAttributes[1];
|
||||
else if (anglePlatform == "warp")
|
||||
attributes = anglePlatformAttributes[2];
|
||||
else
|
||||
qCWarning(lcQpaGl) << "Invalid value set for QT_ANGLE_PLATFORM:" << anglePlatform;
|
||||
|
||||
if (attributes)
|
||||
display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes);
|
||||
}
|
||||
#endif // EGL_ANGLE_platform_angle_opengl
|
||||
if (display == EGL_NO_DISPLAY)
|
||||
display = libEGL.eglGetDisplay((EGLNativeDisplayType)dc);
|
||||
if (!display) {
|
||||
qWarning("%s: Could not obtain EGL display", Q_FUNC_INFO);
|
||||
return 0;
|
||||
@ -512,6 +542,13 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext,
|
||||
if (pbuffer == EGL_NO_SURFACE)
|
||||
return;
|
||||
|
||||
EGLDisplay prevDisplay = QWindowsEGLStaticContext::libEGL.eglGetCurrentDisplay();
|
||||
if (prevDisplay == EGL_NO_DISPLAY) // when no context is current
|
||||
prevDisplay = m_eglDisplay;
|
||||
EGLContext prevContext = QWindowsEGLStaticContext::libEGL.eglGetCurrentContext();
|
||||
EGLSurface prevSurfaceDraw = QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_DRAW);
|
||||
EGLSurface prevSurfaceRead = QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_READ);
|
||||
|
||||
if (QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) {
|
||||
const GLubyte *s = QWindowsEGLStaticContext::libGLESv2.glGetString(GL_VERSION);
|
||||
if (s) {
|
||||
@ -524,7 +561,7 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext,
|
||||
}
|
||||
m_format.setProfile(QSurfaceFormat::NoProfile);
|
||||
m_format.setOptions(QSurfaceFormat::FormatOptions());
|
||||
QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
QWindowsEGLStaticContext::libEGL.eglMakeCurrent(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext);
|
||||
}
|
||||
QWindowsEGLStaticContext::libEGL.eglDestroySurface(m_eglDisplay, pbuffer);
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ struct QWindowsLibEGL
|
||||
|
||||
EGLint (EGLAPIENTRY * eglGetError)(void);
|
||||
EGLDisplay (EGLAPIENTRY * eglGetDisplay)(EGLNativeDisplayType display_id);
|
||||
EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list);
|
||||
EGLBoolean (EGLAPIENTRY * eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
|
||||
EGLBoolean (EGLAPIENTRY * eglTerminate)(EGLDisplay dpy);
|
||||
EGLBoolean (EGLAPIENTRY * eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list,
|
||||
|
@ -1207,6 +1207,9 @@ QWindowsGLContext::~QWindowsGLContext()
|
||||
|
||||
bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
|
||||
{
|
||||
HGLRC prevContext = QOpenGLStaticContext::opengl32.wglGetCurrentContext();
|
||||
HDC prevSurface = QOpenGLStaticContext::opengl32.wglGetCurrentDC();
|
||||
|
||||
if (!QOpenGLStaticContext::opengl32.wglMakeCurrent(hdc, m_renderingContext)) {
|
||||
qWarning("Failed to make context current.");
|
||||
return false;
|
||||
@ -1217,7 +1220,7 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
|
||||
if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval)
|
||||
*obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt();
|
||||
|
||||
QOpenGLStaticContext::opengl32.wglMakeCurrent(0, 0);
|
||||
QOpenGLStaticContext::opengl32.wglMakeCurrent(prevSurface, prevContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -384,7 +384,7 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
|
||||
// 2) The window receiving the event
|
||||
// If a window is blocked by modality, it can't get the event.
|
||||
const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
|
||||
QWindow *receiver = QWindowsScreen::windowAt(globalPos);
|
||||
QWindow *receiver = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE);
|
||||
bool handleEvent = true;
|
||||
if (!isValidWheelReceiver(receiver)) {
|
||||
receiver = window;
|
||||
|
@ -287,13 +287,12 @@ QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int q
|
||||
\brief Find a top level window taking the flags of ChildWindowFromPointEx.
|
||||
*/
|
||||
|
||||
QWindow *QWindowsScreen::findTopLevelAt(const QPoint &point, unsigned flags)
|
||||
QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const
|
||||
{
|
||||
QWindow* result = 0;
|
||||
if (QPlatformWindow *bw = QWindowsContext::instance()->
|
||||
findPlatformWindowAt(GetDesktopWindow(), point, flags))
|
||||
result = QWindowsWindow::topLevelOf(bw->window());
|
||||
qCDebug(lcQpaWindows) <<__FUNCTION__ << point << flags << result;
|
||||
QWindow *result = 0;
|
||||
if (QWindow *child = QWindowsScreen::windowAt(point * QWindowsScaling::factor(), CWP_SKIPINVISIBLE))
|
||||
result = QWindowsWindow::topLevelOf(child);
|
||||
qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -307,15 +306,6 @@ QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags)
|
||||
return result;
|
||||
}
|
||||
|
||||
QWindow *QWindowsScreen::windowUnderMouse(unsigned flags)
|
||||
{
|
||||
#ifndef QT_NO_CURSOR
|
||||
return QWindowsScreen::windowAt(QWindowsCursor::mousePosition(), flags);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w)
|
||||
{
|
||||
if (w)
|
||||
@ -439,6 +429,23 @@ static inline int indexOfMonitor(const QList<QWindowsScreenData> &screenData,
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Move a window to a new virtual screen, accounting for varying sizes.
|
||||
static void moveToVirtualScreen(QWindow *w, const QScreen *newScreen)
|
||||
{
|
||||
QRect geometry = w->geometry();
|
||||
const QRect oldScreenGeometry = w->screen()->geometry();
|
||||
const QRect newScreenGeometry = newScreen->geometry();
|
||||
QPoint relativePosition = geometry.topLeft() - oldScreenGeometry.topLeft();
|
||||
if (oldScreenGeometry.size() != newScreenGeometry.size()) {
|
||||
const qreal factor =
|
||||
qreal(QPoint(newScreenGeometry.width(), newScreenGeometry.height()).manhattanLength()) /
|
||||
qreal(QPoint(oldScreenGeometry.width(), oldScreenGeometry.height()).manhattanLength());
|
||||
relativePosition = (QPointF(relativePosition) * factor).toPoint();
|
||||
}
|
||||
geometry.moveTopLeft(relativePosition);
|
||||
w->setGeometry(geometry);
|
||||
}
|
||||
|
||||
void QWindowsScreenManager::removeScreen(int index)
|
||||
{
|
||||
qCDebug(lcQpaWindows) << "Removing Monitor:" << m_screens.at(index)->data();
|
||||
@ -449,11 +456,18 @@ void QWindowsScreenManager::removeScreen(int index)
|
||||
// event, but unfortunately after the screen destruction signal. To prevent
|
||||
// QtGui from automatically hiding the QWindow, pretend all Windows move to
|
||||
// the primary screen first (which is likely the correct, final screen).
|
||||
// QTBUG-39320: Windows does not automatically move WS_EX_TOOLWINDOW (dock) windows;
|
||||
// move those manually.
|
||||
if (screen != primaryScreen) {
|
||||
unsigned movedWindowCount = 0;
|
||||
foreach (QWindow *w, QGuiApplication::topLevelWindows()) {
|
||||
if (w->screen() == screen && w->handle() && w->type() != Qt::Desktop) {
|
||||
QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen);
|
||||
if (w->isVisible() && w->windowState() != Qt::WindowMinimized
|
||||
&& (QWindowsWindow::baseWindowOf(w)->exStyle() & WS_EX_TOOLWINDOW)) {
|
||||
moveToVirtualScreen(w, primaryScreen);
|
||||
} else {
|
||||
QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen);
|
||||
}
|
||||
++movedWindowCount;
|
||||
}
|
||||
}
|
||||
|
@ -104,12 +104,8 @@ public:
|
||||
QString name() const Q_DECL_OVERRIDE { return m_data.name; }
|
||||
Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; }
|
||||
QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE;
|
||||
QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE
|
||||
{ return QWindowsScreen::findTopLevelAt(point * QWindowsScaling::factor() , CWP_SKIPINVISIBLE); }
|
||||
|
||||
static QWindow *findTopLevelAt(const QPoint &point, unsigned flags);
|
||||
static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE);
|
||||
static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE);
|
||||
QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE;
|
||||
static QWindow *windowAt(const QPoint &point, unsigned flags);
|
||||
|
||||
QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const Q_DECL_OVERRIDE;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user