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

Change-Id: Id4997327cc01bd4bb397a463bdffbd15e80398ef
This commit is contained in:
Oswald Buddenhagen 2014-09-10 11:41:29 +02:00
commit d572ab1bb4
150 changed files with 3623 additions and 1298 deletions

2
configure vendored
View File

@ -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,"

View File

@ -0,0 +1,3 @@
# Include the external websites
sourcedirs += externalsites

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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()

View File

@ -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]

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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
{

View File

@ -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;
}

View File

@ -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
{

View File

@ -51,4 +51,4 @@ class RenderTarget11 : public RenderTarget
}
#endif LIBGLESV2_RENDERER_RENDERTARGET11_H_
#endif // LIBGLESV2_RENDERER_RENDERTARGET11_H_

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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)

View 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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -749,7 +749,6 @@ int QDateTimeParser::parseSection(const QDateTime &currentValue, 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 &currentValue, int sectionInde
if (num != -1) {
state = (used == sectiontext.size() ? Acceptable : Intermediate);
QString str = text;
text.replace(index, used, sectiontext.left(used));
} else {
state = Intermediate;

View File

@ -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()
*/

View File

@ -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;

View File

@ -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:

View File

@ -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()).

View File

@ -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;

View File

@ -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:

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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())

View File

@ -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()
{

View File

@ -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) ||

View File

@ -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);

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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)
{
}

View File

@ -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;

View File

@ -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

View File

@ -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++) {

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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 &region);
void createShaderPrograms();
static void createCursorTexture(uint *texture, const QImage &image);
void createCursorTexture(uint *texture, const QImage &image);
void initCursorAtlas();
// current cursor information

View File

@ -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);

View File

@ -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())

View File

@ -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();
}

View File

@ -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);

View File

@ -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,

View File

@ -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) {

View File

@ -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 &region)
{
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 &region)

View File

@ -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))
{
}

View File

@ -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;

View File

@ -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());

View File

@ -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

View File

@ -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++);

View File

@ -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;

View File

@ -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 &region, 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 &region)
{
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 &region, 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));
}

View File

@ -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 &region, const QPoint &offset);
void present();
void present(const QRegion &region);
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

View File

@ -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();;

View File

@ -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

View File

@ -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 \

View 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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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];
}

View File

@ -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()

View File

@ -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;

View File

@ -35,7 +35,7 @@ contains(QT_CONFIG, directfb) {
SUBDIRS += directfb
}
contains(QT_CONFIG, kms) {
contains(QT_CONFIG, kms):contains(QT_CONFIG, opengl) {
SUBDIRS += kms
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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