diff options
Diffstat (limited to 'src/plugins/platforms/direct2d')
24 files changed, 3513 insertions, 0 deletions
diff --git a/src/plugins/platforms/direct2d/direct2d.json b/src/plugins/platforms/direct2d/direct2d.json new file mode 100644 index 0000000000..aaea92f0ef --- /dev/null +++ b/src/plugins/platforms/direct2d/direct2d.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "direct2d" ] +} diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro new file mode 100644 index 0000000000..4f986b57d7 --- /dev/null +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -0,0 +1,41 @@ +TARGET = qdirect2d + +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QWindowsDirect2DIntegrationPlugin +load(qt_plugin) + +QT *= core-private +QT *= gui-private +QT *= platformsupport-private + +LIBS *= -ld2d1 -ld3d11 -ldwrite + +include(../windows/windows.pri) + +SOURCES += \ + qwindowsdirect2dpaintengine.cpp \ + qwindowsdirect2dpaintdevice.cpp \ + qwindowsdirect2dplatformpixmap.cpp \ + qwindowsdirect2dcontext.cpp \ + qwindowsdirect2dbitmap.cpp \ + qwindowsdirect2dbackingstore.cpp \ + qwindowsdirect2dintegration.cpp \ + qwindowsdirect2dplatformplugin.cpp \ + qwindowsdirect2ddevicecontext.cpp \ + qwindowsdirect2dnativeinterface.cpp \ + qwindowsdirect2dwindow.cpp + +HEADERS += \ + qwindowsdirect2dpaintengine.h \ + qwindowsdirect2dpaintdevice.h \ + qwindowsdirect2dplatformpixmap.h \ + qwindowsdirect2dcontext.h \ + qwindowsdirect2dhelpers.h \ + qwindowsdirect2dbitmap.h \ + qwindowsdirect2dbackingstore.h \ + qwindowsdirect2dintegration.h \ + qwindowsdirect2ddevicecontext.h \ + qwindowsdirect2dnativeinterface.h \ + qwindowsdirect2dwindow.h + +OTHER_FILES += direct2d.json diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp new file mode 100644 index 0000000000..079ad6f127 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dbackingstore.h" +#include "qwindowsdirect2dintegration.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2ddevicecontext.h" +#include "qwindowsdirect2dwindow.h" + +#include "qwindowscontext.h" + +#include <QtGui/QWindow> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsDirect2DBackingStore + \brief Backing store for windows. + \internal + \ingroup qt-lighthouse-win +*/ + +static inline QWindowsDirect2DPlatformPixmap *platformPixmap(QPixmap *p) +{ + return static_cast<QWindowsDirect2DPlatformPixmap *>(p->handle()); +} + +QWindowsDirect2DBackingStore::QWindowsDirect2DBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ +} + +QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore() +{ +} + +QPaintDevice *QWindowsDirect2DBackingStore::paintDevice() +{ + return m_pixmap.data(); +} + +void QWindowsDirect2DBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + QPlatformWindow *pw = window->handle(); + if (pw && m_pixmap) + static_cast<QWindowsDirect2DWindow *>(pw)->flush(platformPixmap(m_pixmap.data())->bitmap(), region, offset); +} + +void QWindowsDirect2DBackingStore::resize(const QSize &size, const QRegion ®ion) +{ + Q_UNUSED(region); + + QScopedPointer<QPixmap> oldPixmap(m_pixmap.take()); + m_pixmap.reset(new QPixmap(size.width(), size.height())); + + if (oldPixmap) { + foreach (const QRect &rect, region.rects()) + platformPixmap(m_pixmap.data())->copy(oldPixmap->handle(), rect); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h new file mode 100644 index 0000000000..9776d234e8 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DBACKINGSTORE_H +#define QWINDOWSDIRECT2DBACKINGSTORE_H + +#include "qwindowsdirect2dplatformpixmap.h" + +#include <QtCore/QScopedPointer> +#include <QtGui/qpa/qplatformbackingstore.h> +#include <QtGui/QPixmap> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DBackingStore : public QPlatformBackingStore +{ + Q_DISABLE_COPY(QWindowsDirect2DBackingStore) + +public: + QWindowsDirect2DBackingStore(QWindow *window); + ~QWindowsDirect2DBackingStore(); + + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; + +private: + QScopedPointer<QPixmap> m_pixmap; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DBACKINGSTORE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp new file mode 100644 index 0000000000..85c56bc73e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include <QtGui/QImage> +#include <QtGui/QColor> + +#include <wrl.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DBitmapPrivate +{ +public: + QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext *dc = 0, ID2D1Bitmap1 *bm = 0) + : bitmap(bm) + , deviceContext(new QWindowsDirect2DDeviceContext(dc)) + { + deviceContext->get()->SetTarget(bm); + } + + D2D1_BITMAP_PROPERTIES1 bitmapProperties() const + { + FLOAT dpiX, dpiY; + QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY); + + return D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_TARGET, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED), + dpiX, dpiY); + + } + + bool resize(int width, int height, const void *data = 0, int pitch = 0) + { + deviceContext->get()->SetTarget(0); + bitmap.Reset(); + + D2D1_SIZE_U size = { + width, height + }; + + HRESULT hr = deviceContext->get()->CreateBitmap(size, data, pitch, + bitmapProperties(), + bitmap.ReleaseAndGetAddressOf()); + if (SUCCEEDED(hr)) + deviceContext->get()->SetTarget(bitmap.Get()); + else + qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr); + + return SUCCEEDED(hr); + } + + QImage toImage(const QRect &rect) + { + if (!bitmap) + return QImage(); + + ComPtr<ID2D1Bitmap1> mappingCopy; + + HRESULT hr = S_OK; + D2D1_SIZE_U size = bitmap->GetPixelSize(); + + D2D1_BITMAP_PROPERTIES1 properties = bitmapProperties(); + properties.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ; + + hr = deviceContext->get()->CreateBitmap(size, NULL, NULL, + properties, &mappingCopy); + if (FAILED(hr)) { + qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr); + return QImage(); + } + + hr = mappingCopy->CopyFromBitmap(NULL, bitmap.Get(), NULL); + if (FAILED(hr)) { + qWarning("%s: Could not copy from bitmap: %#x", __FUNCTION__, hr); + return QImage(); + } + + D2D1_MAPPED_RECT mappedRect; + hr = mappingCopy->Map(D2D1_MAP_OPTIONS_READ, &mappedRect); + if (FAILED(hr)) { + qWarning("%s: Could not map: %#x", __FUNCTION__, hr); + return QImage(); + } + + return QImage(static_cast<const uchar *>(mappedRect.bits), + size.width, size.height, mappedRect.pitch, + QImage::Format_ARGB32_Premultiplied).copy(rect); + } + + QScopedPointer<QWindowsDirect2DDeviceContext> deviceContext; + ComPtr<ID2D1Bitmap1> bitmap; +}; + +QWindowsDirect2DBitmap::QWindowsDirect2DBitmap() + : d_ptr(new QWindowsDirect2DBitmapPrivate) +{ +} + +QWindowsDirect2DBitmap::QWindowsDirect2DBitmap(ID2D1Bitmap1 *bitmap, ID2D1DeviceContext *dc) + : d_ptr(new QWindowsDirect2DBitmapPrivate(dc, bitmap)) +{ +} + +QWindowsDirect2DBitmap::~QWindowsDirect2DBitmap() +{ +} + +bool QWindowsDirect2DBitmap::resize(int width, int height) +{ + Q_D(QWindowsDirect2DBitmap); + return d->resize(width, height); +} + +bool QWindowsDirect2DBitmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags) +{ + Q_D(QWindowsDirect2DBitmap); + + QImage converted = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags); + return d->resize(converted.width(), converted.height(), + converted.constBits(), converted.bytesPerLine()); +} + +ID2D1Bitmap1* QWindowsDirect2DBitmap::bitmap() const +{ + Q_D(const QWindowsDirect2DBitmap); + return d->bitmap.Get(); +} + +QWindowsDirect2DDeviceContext *QWindowsDirect2DBitmap::deviceContext() const +{ + Q_D(const QWindowsDirect2DBitmap); + return d->deviceContext.data(); +} + +void QWindowsDirect2DBitmap::fill(const QColor &color) +{ + Q_D(QWindowsDirect2DBitmap); + + d->deviceContext->begin(); + d->deviceContext->get()->Clear(to_d2d_color_f(color)); + d->deviceContext->end(); +} + +QImage QWindowsDirect2DBitmap::toImage(const QRect &rect) +{ + Q_D(QWindowsDirect2DBitmap); + return d->toImage(rect); +} + +QSize QWindowsDirect2DBitmap::size() const +{ + Q_D(const QWindowsDirect2DBitmap); + + D2D1_SIZE_U size = d->bitmap->GetPixelSize(); + return QSize(size.width, size.height); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h new file mode 100644 index 0000000000..d7015ef342 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DBITMAP_H +#define QWINDOWSDIRECT2DBITMAP_H + +#include <QtCore/QScopedPointer> +#include <QtGui/QImage> + +struct ID2D1DeviceContext; +struct ID2D1Bitmap1; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DDeviceContext; +class QWindowsDirect2DBitmapPrivate; +class QWindowsDirect2DBitmap +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DBitmap) + Q_DISABLE_COPY(QWindowsDirect2DBitmap) +public: + QWindowsDirect2DBitmap(); + QWindowsDirect2DBitmap(ID2D1Bitmap1 *bitmap, ID2D1DeviceContext *dc); + ~QWindowsDirect2DBitmap(); + + bool resize(int width, int height); + bool fromImage(const QImage &image, Qt::ImageConversionFlags flags); + + ID2D1Bitmap1* bitmap() const; + QWindowsDirect2DDeviceContext* deviceContext() const; + + void fill(const QColor &color); + QImage toImage(const QRect &rect = QRect()); + + QSize size() const; + +private: + QScopedPointer<QWindowsDirect2DBitmapPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DBITMAP_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp new file mode 100644 index 0000000000..58002fb0dd --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2dintegration.h" + +#include <d3d11_1.h> +#include <d2d1_1.h> +#include <d2d1_1helper.h> +#include <dxgi1_2.h> +#include <wrl.h> +#include <dwrite.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DContextPrivate +{ +public: + bool init() + { + HRESULT hr; + + D3D_FEATURE_LEVEL level; + + D3D_DRIVER_TYPE typeAttempts[] = { + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP + }; + const int ntypes = int(sizeof(typeAttempts) / sizeof(typeAttempts[0])); + + for (int i = 0; i < ntypes; i++) { + hr = D3D11CreateDevice(NULL, + typeAttempts[i], + NULL, + D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT, + NULL, + 0, + D3D11_SDK_VERSION, + &d3dDevice, + &level, + &d3dDeviceContext); + + if (SUCCEEDED(hr)) + break; + } + + if (FAILED(hr)) { + qWarning("%s: Could not create Direct3D Device: %#x", __FUNCTION__, hr); + return false; + } + + ComPtr<IDXGIDevice> dxgiDevice; + ComPtr<IDXGIAdapter> dxgiAdapter; + + hr = d3dDevice.As(&dxgiDevice); + if (FAILED(hr)) { + qWarning("%s: DXGI Device interface query failed on D3D Device: %#x", __FUNCTION__, hr); + return false; + } + + hr = dxgiDevice->GetParent(IID_PPV_ARGS(&dxgiAdapter)); + if (FAILED(hr)) { + qWarning("%s: Failed to probe DXGI Device for parent DXGI Adapter: %#x", __FUNCTION__, hr); + return false; + } + + hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)); + if (FAILED(hr)) { + qWarning("%s: Failed to probe DXGI Adapter for parent DXGI Factory: %#x", __FUNCTION__, hr); + return false; + } + + D2D1_FACTORY_OPTIONS options = {}; + +#ifdef QT_D2D_DEBUG_OUTPUT + qDebug("Turning on Direct2D debugging messages"); + options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif // QT_D2D_DEBUG_OUTPUT + + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, options, d2dFactory.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D Factory: %#x", __FUNCTION__, hr); + return false; + } + + hr = d2dFactory->CreateDevice(dxgiDevice.Get(), &d2dDevice); + if (FAILED(hr)) { + qWarning("%s: Could not create D2D Device: %#x", __FUNCTION__, hr); + return false; + } + + hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), + static_cast<IUnknown **>(&directWriteFactory)); + if (FAILED(hr)) { + qWarning("%s: Could not create DirectWrite factory: %#x", __FUNCTION__, hr); + return false; + } + + hr = directWriteFactory->GetGdiInterop(&directWriteGdiInterop); + if (FAILED(hr)) { + qWarning("%s: Could not create DirectWrite GDI Interop: %#x", __FUNCTION__, hr); + return false; + } + + return true; + } + + ComPtr<ID3D11Device> d3dDevice; + ComPtr<ID2D1Factory1> d2dFactory; + ComPtr<ID2D1Device> d2dDevice; + ComPtr<IDXGIFactory2> dxgiFactory; + ComPtr<ID3D11DeviceContext> d3dDeviceContext; + ComPtr<IDWriteFactory> directWriteFactory; + ComPtr<IDWriteGdiInterop> directWriteGdiInterop; +}; + +QWindowsDirect2DContext::QWindowsDirect2DContext() + : d_ptr(new QWindowsDirect2DContextPrivate) +{ +} + +QWindowsDirect2DContext::~QWindowsDirect2DContext() {} + +bool QWindowsDirect2DContext::init() +{ + Q_D(QWindowsDirect2DContext); + return d->init(); +} + +QWindowsDirect2DContext *QWindowsDirect2DContext::instance() +{ + return QWindowsDirect2DIntegration::instance()->direct2DContext(); +} + +ID3D11Device *QWindowsDirect2DContext::d3dDevice() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d3dDevice.Get(); +} + +ID2D1Device *QWindowsDirect2DContext::d2dDevice() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d2dDevice.Get(); +} + +ID2D1Factory1 *QWindowsDirect2DContext::d2dFactory() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d2dFactory.Get(); +} + +IDXGIFactory2 *QWindowsDirect2DContext::dxgiFactory() const +{ + Q_D(const QWindowsDirect2DContext); + return d->dxgiFactory.Get(); +} + +ID3D11DeviceContext *QWindowsDirect2DContext::d3dDeviceContext() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d3dDeviceContext.Get(); +} + +IDWriteFactory *QWindowsDirect2DContext::dwriteFactory() const +{ + Q_D(const QWindowsDirect2DContext); + return d->directWriteFactory.Get(); +} + +IDWriteGdiInterop *QWindowsDirect2DContext::dwriteGdiInterop() const +{ + Q_D(const QWindowsDirect2DContext); + return d->directWriteGdiInterop.Get(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h new file mode 100644 index 0000000000..0025463dd5 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DCONTEXT_H +#define QWINDOWSDIRECT2DCONTEXT_H + +#include <QtCore/QScopedPointer> + +struct ID3D11Device; +struct ID2D1Device; +struct ID2D1Factory1; +struct IDXGIFactory2; +struct ID3D11DeviceContext; +struct IDWriteFactory; +struct IDWriteGdiInterop; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DContextPrivate; +class QWindowsDirect2DContext +{ + Q_DECLARE_PRIVATE( QWindowsDirect2DContext ) + +public: + QWindowsDirect2DContext(); + virtual ~QWindowsDirect2DContext(); + + bool init(); + + static QWindowsDirect2DContext *instance(); + + ID3D11Device *d3dDevice() const; + ID2D1Device *d2dDevice() const; + ID2D1Factory1 *d2dFactory() const; + IDXGIFactory2 *dxgiFactory() const; + ID3D11DeviceContext *d3dDeviceContext() const; + IDWriteFactory *dwriteFactory() const; + IDWriteGdiInterop *dwriteGdiInterop() const; + +private: + QScopedPointer<QWindowsDirect2DContextPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DCONTEXT_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp new file mode 100644 index 0000000000..27e94e4be4 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include <wrl.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DDeviceContextPrivate { +public: + QWindowsDirect2DDeviceContextPrivate(ID2D1DeviceContext *dc) + : deviceContext(dc) + , refCount(0) + { + if (!dc) { + HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + &deviceContext); + if (FAILED(hr)) + qFatal("%s: Couldn't create Direct2D Device Context: %#x", __FUNCTION__, hr); + } + + Q_ASSERT(deviceContext); + } + + void begin() + { + Q_ASSERT(deviceContext); + Q_ASSERT(refCount >= 0); + + if (refCount == 0) + deviceContext->BeginDraw(); + + refCount++; + } + + bool end() + { + Q_ASSERT(deviceContext); + Q_ASSERT(refCount > 0); + + bool success = true; + refCount--; + + if (refCount == 0) { + D2D1_TAG tag1, tag2; + HRESULT hr = deviceContext->EndDraw(&tag1, &tag2); + + if (FAILED(hr)) { + success = false; + qWarning("%s: EndDraw failed: %#x, tag1: %lld, tag2: %lld", __FUNCTION__, hr, tag1, tag2); + } + } + + return success; + } + + ComPtr<ID2D1DeviceContext> deviceContext; + int refCount; +}; + +QWindowsDirect2DDeviceContext::QWindowsDirect2DDeviceContext(ID2D1DeviceContext *dc) + : d_ptr(new QWindowsDirect2DDeviceContextPrivate(dc)) +{ +} + +QWindowsDirect2DDeviceContext::~QWindowsDirect2DDeviceContext() +{ + +} + +ID2D1DeviceContext *QWindowsDirect2DDeviceContext::get() const +{ + Q_D(const QWindowsDirect2DDeviceContext); + Q_ASSERT(d->deviceContext); + + return d->deviceContext.Get(); +} + +void QWindowsDirect2DDeviceContext::begin() +{ + Q_D(QWindowsDirect2DDeviceContext); + d->begin(); +} + +bool QWindowsDirect2DDeviceContext::end() +{ + Q_D(QWindowsDirect2DDeviceContext); + return d->end(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h new file mode 100644 index 0000000000..4986efb967 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DDEVICECONTEXT_H +#define QWINDOWSDIRECT2DDEVICECONTEXT_H + +#include "qwindowsdirect2dhelpers.h" + +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +/* + * Convenience class for handling device contexts. We have to call BeginDraw + * before anything can happen, and EndDraw once we're done, for every frame and + * pretty much any kind of operation. + * + * Unfortunately, these calls cannot be interleaved, and there is no way to check + * what state a device context is in. + * + * The end result is that the following throws an error if we don't track it: + * QPixmap pmap; + * QPainter painter(&pmap); + * pmap.clear(); + * + * Here BeginDraw would first be called through the paint device, then when we clear + * the pixmap we would have to call it again. There is no way to know what state + * the device context is in when performing the clear, and activating the dc is an + * error. Bummer. + * + * Hence we keep a reference count here and only activate/deactivate the device + * if the refcount is zero. + * + * In a nutshell: Do not call BeginDraw/EndDraw yourself on the device pointer, do + * so through the begin/end members below. + */ + +class QWindowsDirect2DDeviceContextPrivate; +class QWindowsDirect2DDeviceContext +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DDeviceContext) +public: + QWindowsDirect2DDeviceContext(ID2D1DeviceContext *dc); + ~QWindowsDirect2DDeviceContext(); + + ID2D1DeviceContext *get() const; + + void begin(); + bool end(); + +private: + QScopedPointer<QWindowsDirect2DDeviceContextPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DDEVICECONTEXT_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h new file mode 100644 index 0000000000..98248515e6 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DHELPERS_H +#define QWINDOWSDIRECT2DHELPERS_H + +#include <QtCore/QRectF> +#include <QtCore/QSizeF> +#include <QtCore/QPointF> +#include <QtGui/QColor> +#include <QtGui/QTransform> + +#include <d2d1_1helper.h> + +QT_BEGIN_NAMESPACE + +Q_DECL_CONSTEXPR inline D2D1_RECT_U to_d2d_rect_u(const QRect &qrect) +{ + return D2D1::RectU(qrect.x(), qrect.y(), qrect.x() + qrect.width(), qrect.y() + qrect.height()); +} + +Q_DECL_CONSTEXPR inline D2D1_RECT_F to_d2d_rect_f(const QRectF &qrect) +{ + return D2D1::RectF(qrect.x(), qrect.y(), qrect.x() + qrect.width(), qrect.y() + qrect.height()); +} + +Q_DECL_CONSTEXPR inline D2D1_SIZE_U to_d2d_size_u(const QSizeF &qsize) +{ + return D2D1::SizeU(qsize.width(), qsize.height()); +} + +Q_DECL_CONSTEXPR inline D2D1_SIZE_U to_d2d_size_u(const QSize &qsize) +{ + return D2D1::SizeU(qsize.width(), qsize.height()); +} + +Q_DECL_CONSTEXPR inline D2D1_POINT_2F to_d2d_point_2f(const QPointF &qpoint) +{ + return D2D1::Point2F(qpoint.x(), qpoint.y()); +} + +Q_DECL_CONSTEXPR inline D2D1::ColorF to_d2d_color_f(const QColor &c) +{ + return D2D1::ColorF(c.redF(), c.greenF(), c.blueF(), c.alphaF()); +} + +Q_DECL_CONSTEXPR inline D2D1_MATRIX_3X2_F to_d2d_matrix_3x2_f(const QTransform &transform) +{ + Q_ASSERT(transform.isAffine()); + + return D2D1::Matrix3x2F(transform.m11(), transform.m12(), + transform.m21(), transform.m22(), + transform.m31(), transform.m32()); +} + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DHELPERS_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp new file mode 100644 index 0000000000..1a26d7029e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dintegration.h" +#include "qwindowsdirect2dbackingstore.h" +#include "qwindowsdirect2dplatformpixmap.h" +#include "qwindowsdirect2dnativeinterface.h" +#include "qwindowsdirect2dwindow.h" + +#include "qwindowscontext.h" + +#include <QtCore/QDebug> +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtGui/qpa/qwindowsysteminterface.h> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DIntegrationPrivate +{ +public: + QWindowsDirect2DNativeInterface m_nativeInterface; + QWindowsDirect2DContext m_d2dContext; +}; + +QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringList ¶mList) +{ + QWindowsDirect2DIntegration *integration = new QWindowsDirect2DIntegration(paramList); + + if (!integration->init()) { + delete integration; + integration = 0; + } + + return integration; +} + +QWindowsDirect2DIntegration::~QWindowsDirect2DIntegration() +{ + +} + + QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::instance() + { + return static_cast<QWindowsDirect2DIntegration *>(QWindowsIntegration::instance()); + } + + QPlatformWindow *QWindowsDirect2DIntegration::createPlatformWindow(QWindow *window) const + { + QWindowsWindowData data = createWindowData(window); + return data.hwnd ? new QWindowsDirect2DWindow(window, data) + : Q_NULLPTR; + } + + QPlatformNativeInterface *QWindowsDirect2DIntegration::nativeInterface() const + { + return &d->m_nativeInterface; + } + +QPlatformPixmap *QWindowsDirect2DIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const +{ + switch (type) { + case QPlatformPixmap::BitmapType: + return new QRasterPlatformPixmap(type); + break; + default: + return new QWindowsDirect2DPlatformPixmap(type); + break; + } +} + +QPlatformBackingStore *QWindowsDirect2DIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QWindowsDirect2DBackingStore(window); +} + +QWindowsDirect2DContext *QWindowsDirect2DIntegration::direct2DContext() const +{ + return &d->m_d2dContext; +} + +QWindowsDirect2DIntegration::QWindowsDirect2DIntegration(const QStringList ¶mList) + : QWindowsIntegration(paramList) + , d(new QWindowsDirect2DIntegrationPrivate) +{ +} + +bool QWindowsDirect2DIntegration::init() +{ + return d->m_d2dContext.init(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h new file mode 100644 index 0000000000..a46d5c0126 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DINTEGRATION_H +#define QWINDOWSDIRECT2DINTEGRATION_H + +#include "qwindowsintegration.h" + +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DContext; +class QWindowsDirect2DIntegrationPrivate; + +class QWindowsDirect2DIntegration : public QWindowsIntegration +{ +public: + static QWindowsDirect2DIntegration *create(const QStringList ¶mList); + + virtual ~QWindowsDirect2DIntegration(); + + static QWindowsDirect2DIntegration *instance(); + + QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + + QWindowsDirect2DContext *direct2DContext() const; + +private: + explicit QWindowsDirect2DIntegration(const QStringList ¶mList); + bool init(); + + QScopedPointer<QWindowsDirect2DIntegrationPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DINTEGRATION_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp new file mode 100644 index 0000000000..6792d92de5 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dnativeinterface.h" + +#include <QtGui/QBackingStore> + +QT_BEGIN_NAMESPACE + +void *QWindowsDirect2DNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) +{ + if (!bs || !bs->handle()) { + qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); + return 0; + } + + // getDC is so common we don't want to print an "invalid key" line for it + if (resource == "getDC") + return 0; + + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + return 0; + +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h new file mode 100644 index 0000000000..ee3f7f6eed --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DNATIVEINTERFACE_H +#define QWINDOWSDIRECT2DNATIVEINTERFACE_H + +#include "qwindowsnativeinterface.h" + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DNativeInterface : public QWindowsNativeInterface +{ + Q_OBJECT +public: + void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) Q_DECL_OVERRIDE; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DNATIVEINTERFACE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp new file mode 100644 index 0000000000..85dbaab2ce --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dpaintengine.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include "qwindowswindow.h" + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPaintDevicePrivate +{ +public: + QWindowsDirect2DPaintDevicePrivate(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags f) + : engine(new QWindowsDirect2DPaintEngine(bitmap)) + , bitmap(bitmap) + , flags(f) + {} + + QScopedPointer<QWindowsDirect2DPaintEngine> engine; + QWindowsDirect2DBitmap *bitmap; + QInternal::PaintDeviceFlags flags; +}; + +QWindowsDirect2DPaintDevice::QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags) + : d_ptr(new QWindowsDirect2DPaintDevicePrivate(bitmap, flags)) +{ +} + +QPaintEngine *QWindowsDirect2DPaintDevice::paintEngine() const +{ + Q_D(const QWindowsDirect2DPaintDevice); + + return d->engine.data(); +} + +int QWindowsDirect2DPaintDevice::devType() const +{ + Q_D(const QWindowsDirect2DPaintDevice); + + return d->flags; +} + +int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + Q_D(const QWindowsDirect2DPaintDevice); + + switch (metric) { + case QPaintDevice::PdmWidth: + return d->bitmap->bitmap()->GetPixelSize().width; + break; + case QPaintDevice::PdmHeight: + return d->bitmap->bitmap()->GetPixelSize().height; + break; + case QPaintDevice::PdmNumColors: + return INT_MAX; + break; + case QPaintDevice::PdmDepth: + return 32; + break; + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmPhysicalDpiX: + { + FLOAT x, y; + QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y); + return x; + } + break; + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiY: + { + FLOAT x, y; + QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y); + return y; + } + break; + case QPaintDevice::PdmDevicePixelRatio: + return 1; + break; + case QPaintDevice::PdmWidthMM: + case QPaintDevice::PdmHeightMM: + return -1; + break; + } + + return -1; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h new file mode 100644 index 0000000000..c799083d84 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DPAINTDEVICE_H +#define QWINDOWSDIRECT2DPAINTDEVICE_H + +#include <QtCore/QScopedPointer> +#include <QtGui/QPaintDevice> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DBitmap; + +class QWindowsDirect2DPaintDevicePrivate; +class QWindowsDirect2DPaintDevice : public QPaintDevice +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DPaintDevice) + +public: + QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags); + QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; + int devType() const Q_DECL_OVERRIDE; + +protected: + int metric(PaintDeviceMetric metric) const Q_DECL_OVERRIDE; + +private: + QScopedPointer<QWindowsDirect2DPaintDevicePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DPAINTDEVICE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp new file mode 100644 index 0000000000..e19a6be47b --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -0,0 +1,1168 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dpaintengine.h" +#include "qwindowsdirect2dplatformpixmap.h" +#include "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include "qwindowsfontengine.h" +#include "qwindowsfontenginedirectwrite.h" +#include "qwindowsfontdatabase.h" +#include "qwindowsintegration.h" + +#include <QtGui/private/qpaintengine_p.h> +#include <QtGui/private/qtextengine_p.h> +#include <QtGui/private/qfontengine_p.h> +#include <QtGui/private/qstatictext_p.h> + +#include <wrl.h> +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +// The enum values below are set as tags on the device context +// in the various draw methods. When EndDraw is called the device context +// will report the last set tag number in case of errors +// along with an error code + +// Microsoft keeps a list of d2d error codes here: +// http://msdn.microsoft.com/en-us/library/windows/desktop/dd370979(v=vs.85).aspx +enum { + D2DDebugDrawInitialStateTag = -1, + D2DDebugDrawImageTag = 1, + D2DDebugFillTag, + D2DDebugDrawPixmapTag, + D2DDebugDrawStaticTextItemTag, + D2DDebugDrawTextItemTag +}; +#define D2D_TAG(tag) d->dc()->SetTags(tag, tag) + +Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); + +static inline ID2D1Factory1 *factory() +{ + return QWindowsDirect2DContext::instance()->d2dFactory(); +} + +// XXX reduce code duplication between painterPathToPathGeometry and +// vectorPathToID2D1PathGeometry, the two are quite similar + +static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &path) +{ + ComPtr<ID2D1PathGeometry1> geometry; + ComPtr<ID2D1GeometrySink> sink; + + HRESULT hr = factory()->CreatePathGeometry(&geometry); + if (FAILED(hr)) { + qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + return NULL; + } + + hr = geometry->Open(&sink); + if (FAILED(hr)) { + qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); + return NULL; + } + + switch (path.fillRule()) { + case Qt::WindingFill: + sink->SetFillMode(D2D1_FILL_MODE_WINDING); + break; + case Qt::OddEvenFill: + sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); + break; + } + + bool inFigure = false; + + for (int i = 0; i < path.elementCount(); i++) { + const QPainterPath::Element element = path.elementAt(i); + + switch (element.type) { + case QPainterPath::MoveToElement: + if (inFigure) + sink->EndFigure(D2D1_FIGURE_END_OPEN); + + sink->BeginFigure(to_d2d_point_2f(element), D2D1_FIGURE_BEGIN_FILLED); + inFigure = true; + break; + + case QPainterPath::LineToElement: + sink->AddLine(to_d2d_point_2f(element)); + break; + + case QPainterPath::CurveToElement: + { + const QPainterPath::Element data1 = path.elementAt(++i); + const QPainterPath::Element data2 = path.elementAt(++i); + + Q_ASSERT(i < path.elementCount()); + + Q_ASSERT(data1.type == QPainterPath::CurveToDataElement); + Q_ASSERT(data2.type == QPainterPath::CurveToDataElement); + + D2D1_BEZIER_SEGMENT segment; + + segment.point1 = to_d2d_point_2f(element); + segment.point2 = to_d2d_point_2f(data1); + segment.point3 = to_d2d_point_2f(data2); + + sink->AddBezier(segment); + } + break; + + case QPainterPath::CurveToDataElement: + qWarning("%s: Unhandled Curve Data Element", __FUNCTION__); + break; + } + } + + if (inFigure) + sink->EndFigure(D2D1_FIGURE_END_OPEN); + + sink->Close(); + + return geometry; +} + +static ComPtr<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPath &path, bool alias) +{ + ComPtr<ID2D1PathGeometry1> pathGeometry; + HRESULT hr = factory()->CreatePathGeometry(pathGeometry.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + return NULL; + } + + if (path.isEmpty()) + return pathGeometry; + + ComPtr<ID2D1GeometrySink> sink; + hr = pathGeometry->Open(sink.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); + return NULL; + } + + sink->SetFillMode(path.hasWindingFill() ? D2D1_FILL_MODE_WINDING + : D2D1_FILL_MODE_ALTERNATE); + + bool inFigure = false; + + const QPainterPath::ElementType *types = path.elements(); + const int count = path.elementCount(); + const qreal *points = 0; + + QScopedArrayPointer<qreal> rounded_points; + + if (alias) { + // Aliased painting, round to whole numbers + rounded_points.reset(new qreal[count * 2]); + points = rounded_points.data(); + + for (int i = 0; i < (count * 2); i++) + rounded_points[i] = qRound(path.points()[i]); + } else { + // Antialiased painting, keep original numbers + points = path.points(); + } + + Q_ASSERT(points); + + if (types) { + qreal x, y; + + for (int i = 0; i < count; i++) { + x = points[i * 2]; + y = points[i * 2 + 1]; + + switch (types[i]) { + case QPainterPath::MoveToElement: + if (inFigure) + sink->EndFigure(D2D1_FIGURE_END_OPEN); + + sink->BeginFigure(D2D1::Point2F(x, y), D2D1_FIGURE_BEGIN_FILLED); + inFigure = true; + break; + + case QPainterPath::LineToElement: + sink->AddLine(D2D1::Point2F(x, y)); + break; + + case QPainterPath::CurveToElement: + { + Q_ASSERT((i + 2) < count); + Q_ASSERT(types[i+1] == QPainterPath::CurveToDataElement); + Q_ASSERT(types[i+2] == QPainterPath::CurveToDataElement); + + i++; + const qreal x2 = points[i * 2]; + const qreal y2 = points[i * 2 + 1]; + + i++; + const qreal x3 = points[i * 2]; + const qreal y3 = points[i * 2 + 1]; + + D2D1_BEZIER_SEGMENT segment = { + D2D1::Point2F(x, y), + D2D1::Point2F(x2, y2), + D2D1::Point2F(x3, y3) + }; + + sink->AddBezier(segment); + } + break; + + case QPainterPath::CurveToDataElement: + qWarning("%s: Unhandled Curve Data Element", __FUNCTION__); + break; + } + } + } else { + sink->BeginFigure(D2D1::Point2F(points[0], points[1]), D2D1_FIGURE_BEGIN_FILLED); + inFigure = true; + + for (int i = 1; i < count; i++) + sink->AddLine(D2D1::Point2F(points[i * 2], points[i * 2 + 1])); + } + + if (inFigure) { + if (path.hasImplicitClose()) + sink->AddLine(D2D1::Point2F(points[0], points[1])); + + sink->EndFigure(D2D1_FIGURE_END_OPEN); + } + + sink->Close(); + + return pathGeometry; +} + +class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate +{ + Q_DECLARE_PUBLIC(QWindowsDirect2DPaintEngine) +public: + QWindowsDirect2DPaintEnginePrivate(QWindowsDirect2DBitmap *bm) + : bitmap(bm) + , clipPushed(false) + { + pen.reset(); + brush.reset(); + + dc()->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + } + + QWindowsDirect2DBitmap *bitmap; + + QPainterPath clipPath; + bool clipPushed; + + QPointF currentBrushOrigin; + + struct { + bool emulate; + QPen qpen; + ComPtr<ID2D1Brush> brush; + ComPtr<ID2D1StrokeStyle1> strokeStyle; + + inline void reset() { + emulate = false; + qpen = QPen(); + brush.Reset(); + strokeStyle.Reset(); + } + } pen; + + struct { + bool emulate; + QBrush qbrush; + ComPtr<ID2D1Brush> brush; + + inline void reset() { + emulate = false; + brush.Reset(); + qbrush = QBrush(); + } + } brush; + + inline ID2D1DeviceContext *dc() const + { + Q_ASSERT(bitmap); + return bitmap->deviceContext()->get(); + } + + inline D2D1_INTERPOLATION_MODE interpolationMode() const + { + Q_Q(const QWindowsDirect2DPaintEngine); + // XXX are we choosing the right d2d interpolation modes? + return (q->state()->renderHints & QPainter::SmoothPixmapTransform) ? D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC + : D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + } + + inline D2D1_ANTIALIAS_MODE antialiasMode() const + { + Q_Q(const QWindowsDirect2DPaintEngine); + return (q->state()->renderHints & QPainter::Antialiasing) ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE + : D2D1_ANTIALIAS_MODE_ALIASED; + } + + void updateTransform() + { + Q_Q(const QWindowsDirect2DPaintEngine); + // Note the loss of info going from 3x3 to 3x2 matrix here + dc()->SetTransform(to_d2d_matrix_3x2_f(q->state()->transform())); + } + + void updateOpacity() + { + Q_Q(const QWindowsDirect2DPaintEngine); + qreal opacity = q->state()->opacity; + if (brush.brush) + brush.brush->SetOpacity(opacity); + if (pen.brush) + pen.brush->SetOpacity(opacity); + } + + void pushClip() + { + popClip(); + + ComPtr<ID2D1PathGeometry1> geometry = painterPathToPathGeometry(clipPath); + if (!geometry) + return; + + dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), + geometry.Get(), + antialiasMode(), + D2D1::IdentityMatrix(), + 1.0, + NULL, + D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND), + NULL); + clipPushed = true; + } + + void popClip() + { + if (clipPushed) { + dc()->PopLayer(); + clipPushed = false; + } + } + + void updateClipEnabled() + { + Q_Q(const QWindowsDirect2DPaintEngine); + if (!q->state()->clipEnabled) + popClip(); + else if (!clipPushed) + pushClip(); + } + + void updateClipPath(const QPainterPath &path, Qt::ClipOperation operation) + { + switch (operation) { + case Qt::NoClip: + popClip(); + break; + case Qt::ReplaceClip: + clipPath = path; + pushClip(); + break; + case Qt::IntersectClip: + clipPath &= path; + pushClip(); + break; + } + } + + void updateCompositionMode() + { + Q_Q(const QWindowsDirect2DPaintEngine); + QPainter::CompositionMode mode = q->state()->compositionMode(); + + switch (mode) { + case QPainter::CompositionMode_Source: + dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); + break; + case QPainter::CompositionMode_SourceOver: + dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER); + break; + + default: + qWarning("Unsupported composition mode: %d", mode); + break; + } + } + + void updateBrush(const QBrush &newBrush) + { + Q_Q(const QWindowsDirect2DPaintEngine); + + if (qbrush_fast_equals(brush.qbrush, newBrush)) + return; + + brush.brush = to_d2d_brush(newBrush, &brush.emulate); + brush.qbrush = newBrush; + + if (brush.brush) { + brush.brush->SetOpacity(q->state()->opacity); + applyBrushOrigin(currentBrushOrigin); + } + } + + void updateBrushOrigin() + { + Q_Q(const QWindowsDirect2DPaintEngine); + + negateCurrentBrushOrigin(); + applyBrushOrigin(q->state()->brushOrigin); + } + + void negateCurrentBrushOrigin() + { + if (brush.brush && !currentBrushOrigin.isNull()) { + D2D1_MATRIX_3X2_F transform; + brush.brush->GetTransform(&transform); + + brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform)) + * D2D1::Matrix3x2F::Translation(-currentBrushOrigin.x(), + -currentBrushOrigin.y())); + } + } + + void applyBrushOrigin(const QPointF &origin) + { + if (brush.brush && !origin.isNull()) { + D2D1_MATRIX_3X2_F transform; + brush.brush->GetTransform(&transform); + + brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform)) + * D2D1::Matrix3x2F::Translation(origin.x(), origin.y())); + } + + currentBrushOrigin = origin; + } + + void updatePen() + { + Q_Q(const QWindowsDirect2DPaintEngine); + const QPen &newPen = q->state()->pen; + + if (qpen_fast_equals(newPen, pen.qpen)) + return; + + pen.reset(); + pen.qpen = newPen; + + if (newPen.style() == Qt::NoPen) + return; + + pen.brush = to_d2d_brush(newPen.brush(), &pen.emulate); + if (!pen.brush) + return; + + pen.brush->SetOpacity(q->state()->opacity); + + D2D1_STROKE_STYLE_PROPERTIES1 props = {}; + + switch (newPen.capStyle()) { + case Qt::SquareCap: + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_SQUARE; + break; + case Qt::RoundCap: + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_ROUND; + case Qt::FlatCap: + default: + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_FLAT; + break; + } + + switch (newPen.joinStyle()) { + case Qt::BevelJoin: + props.lineJoin = D2D1_LINE_JOIN_BEVEL; + break; + case Qt::RoundJoin: + props.lineJoin = D2D1_LINE_JOIN_ROUND; + break; + case Qt::MiterJoin: + default: + props.lineJoin = D2D1_LINE_JOIN_MITER; + break; + } + + props.miterLimit = newPen.miterLimit() * qreal(2.0); // D2D and Qt miter specs differ + props.dashOffset = newPen.dashOffset(); + props.transformType = qIsNull(newPen.widthF()) ? D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE + : newPen.isCosmetic() ? D2D1_STROKE_TRANSFORM_TYPE_FIXED + : D2D1_STROKE_TRANSFORM_TYPE_NORMAL; + + switch (newPen.style()) { + case Qt::SolidLine: + props.dashStyle = D2D1_DASH_STYLE_SOLID; + break; + + case Qt::DotLine: + case Qt::DashDotLine: + case Qt::DashDotDotLine: + // Try and match Qt's raster engine in output as closely as possible + if (newPen.widthF() <= 1.0) + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_FLAT; + + // fall through + default: + props.dashStyle = D2D1_DASH_STYLE_CUSTOM; + break; + } + + HRESULT hr; + + if (props.dashStyle == D2D1_DASH_STYLE_CUSTOM) { + QVector<qreal> dashes = newPen.dashPattern(); + QVector<FLOAT> converted(dashes.size()); + + for (int i = 0; i < dashes.size(); i++) { + converted[i] = dashes[i]; + } + + hr = factory()->CreateStrokeStyle(props, converted.constData(), converted.size(), &pen.strokeStyle); + } else { + hr = factory()->CreateStrokeStyle(props, NULL, 0, &pen.strokeStyle); + } + + if (FAILED(hr)) + qWarning("%s: Could not create stroke style: %#x", __FUNCTION__, hr); + } + + ComPtr<ID2D1Brush> to_d2d_brush(const QBrush &newBrush, bool *needsEmulation) + { + HRESULT hr; + ComPtr<ID2D1Brush> result; + + Q_ASSERT(needsEmulation); + + *needsEmulation = false; + + switch (newBrush.style()) { + case Qt::NoBrush: + break; + + case Qt::SolidPattern: + { + ComPtr<ID2D1SolidColorBrush> solid; + + hr = dc()->CreateSolidColorBrush(to_d2d_color_f(newBrush.color()), &solid); + if (FAILED(hr)) { + qWarning("%s: Could not create solid color brush: %#x", __FUNCTION__, hr); + break; + } + + hr = solid.As(&result); + if (FAILED(hr)) + qWarning("%s: Could not convert solid color brush: %#x", __FUNCTION__, hr); + } + break; + + case Qt::Dense1Pattern: + case Qt::Dense2Pattern: + case Qt::Dense3Pattern: + case Qt::Dense4Pattern: + case Qt::Dense5Pattern: + case Qt::Dense6Pattern: + case Qt::Dense7Pattern: + case Qt::HorPattern: + case Qt::VerPattern: + case Qt::CrossPattern: + case Qt::BDiagPattern: + case Qt::FDiagPattern: + case Qt::DiagCrossPattern: + { + ComPtr<ID2D1BitmapBrush1> bitmapBrush; + D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = { + D2D1_EXTEND_MODE_WRAP, + D2D1_EXTEND_MODE_WRAP, + interpolationMode() + }; + + QImage brushImg = qt_imageForBrush(newBrush.style(), false); + brushImg.setColor(0, newBrush.color().rgba()); + brushImg.setColor(1, qRgba(0, 0, 0, 0)); + + QWindowsDirect2DBitmap bitmap; + bool success = bitmap.fromImage(brushImg, Qt::AutoColor); + if (!success) { + qWarning("%s: Could not create Direct2D bitmap from Qt pattern brush image", __FUNCTION__); + break; + } + + hr = dc()->CreateBitmapBrush(bitmap.bitmap(), + bitmapBrushProperties, + &bitmapBrush); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); + break; + } + + hr = bitmapBrush.As(&result); + if (FAILED(hr)) + qWarning("%s: Could not convert Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); + } + break; + + case Qt::LinearGradientPattern: + case Qt::RadialGradientPattern: + case Qt::ConicalGradientPattern: + *needsEmulation = true; + break; + + case Qt::TexturePattern: + { + ComPtr<ID2D1BitmapBrush1> bitmapBrush; + D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = { + D2D1_EXTEND_MODE_WRAP, + D2D1_EXTEND_MODE_WRAP, + interpolationMode() + }; + + QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(newBrush.texture().handle()); + QWindowsDirect2DBitmap *bitmap = pp->bitmap(); + hr = dc()->CreateBitmapBrush(bitmap->bitmap(), + bitmapBrushProperties, + &bitmapBrush); + + if (FAILED(hr)) { + qWarning("%s: Could not create texture brush: %#x", __FUNCTION__, hr); + break; + } + + hr = bitmapBrush.As(&result); + if (FAILED(hr)) + qWarning("%s: Could not convert texture brush: %#x", __FUNCTION__, hr); + } + break; + } + + if (result && !newBrush.transform().isIdentity()) + result->SetTransform(to_d2d_matrix_3x2_f(newBrush.transform())); + + return result; + } + + void updateHints() + { + dc()->SetAntialiasMode(antialiasMode()); + } +}; + +QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap) + : QPaintEngineEx(*(new QWindowsDirect2DPaintEnginePrivate(bitmap))) +{ + QPaintEngine::PaintEngineFeatures unsupported = + // As of 1.1 Direct2D gradient support is deficient for linear and radial gradients + QPaintEngine::LinearGradientFill + | QPaintEngine::RadialGradientFill + + // As of 1.1 Direct2D does not support conical gradients at all + | QPaintEngine::ConicalGradientFill + + // As of 1.1 Direct2D does not natively support complex composition modes + // However, using Direct2D effects that implement them should be possible + | QPaintEngine::PorterDuff + | QPaintEngine::BlendModes + | QPaintEngine::RasterOpModes + + // As of 1.1 Direct2D does not natively support perspective transforms + // However, writing a custom effect that implements them should be possible + // The built-in 3D transform effect unfortunately changes output image size, making + // it unusable for us. + | QPaintEngine::PerspectiveTransform; + + gccaps &= ~unsupported; +} + +bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) +{ + Q_D(QWindowsDirect2DPaintEngine); + + d->bitmap->deviceContext()->begin(); + d->dc()->SetTransform(D2D1::Matrix3x2F::Identity()); + + QRect clip(0, 0, pdev->width(), pdev->height()); + if (!systemClip().isEmpty()) + clip &= systemClip().boundingRect(); + + d->dc()->PushAxisAlignedClip(to_d2d_rect_f(clip), D2D1_ANTIALIAS_MODE_ALIASED); + + D2D_TAG(D2DDebugDrawInitialStateTag); + + return true; +} + +bool QWindowsDirect2DPaintEngine::end() +{ + Q_D(QWindowsDirect2DPaintEngine); + // First pop any user-applied clipping + d->popClip(); + // Now the system clip from begin() above + d->dc()->PopAxisAlignedClip(); + return d->bitmap->deviceContext()->end(); +} + +QPaintEngine::Type QWindowsDirect2DPaintEngine::type() const +{ + return QPaintEngine::Direct2D; +} + +void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &brush) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugFillTag); + + if (path.isEmpty()) + return; + + d->updateBrush(brush); + + if (d->brush.emulate) { + // We mostly (only?) get here when gradients are required. + // We could probably natively support linear and radial gradients that have pad reflect + + QImage img(d->bitmap->size(), QImage::Format_ARGB32); + img.fill(Qt::transparent); + + QPainter p; + QPaintEngine *engine = img.paintEngine(); + if (engine->isExtended() && p.begin(&img)) { + QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine); + extended->fill(path, brush); + if (!p.end()) + qWarning("%s: Paint Engine end returned false", __FUNCTION__); + + drawImage(img.rect(), img, img.rect()); + } else { + qWarning("%s: Could not fall back to QImage", __FUNCTION__); + } + + return; + } + + if (!d->brush.brush) + return; + + ComPtr<ID2D1Geometry> geometry = vectorPathToID2D1PathGeometry(path, d->antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED); + if (!geometry) { + qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); + return; + } + + d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get()); +} + +// For clipping we convert everything to painter paths since it allows +// calculating intersections easily. It might be faster to convert to +// ID2D1Geometry and use its operations, although that needs to measured. +// The implementation would be more complex in any case. + +void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + clip(path.convertToPainterPath(), op); +} + +void QWindowsDirect2DPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + QPainterPath p; + p.addRect(rect); + clip(p, op); +} + +void QWindowsDirect2DPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + QPainterPath p; + p.addRegion(region); + clip(p, op); +} + +void QWindowsDirect2DPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateClipPath(path, op); +} + +void QWindowsDirect2DPaintEngine::clipEnabledChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateClipEnabled(); +} + +void QWindowsDirect2DPaintEngine::penChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updatePen(); +} + +void QWindowsDirect2DPaintEngine::brushChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateBrush(state()->brush); +} + +void QWindowsDirect2DPaintEngine::brushOriginChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateBrushOrigin(); +} + +void QWindowsDirect2DPaintEngine::opacityChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateOpacity(); +} + +void QWindowsDirect2DPaintEngine::compositionModeChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateCompositionMode(); +} + +void QWindowsDirect2DPaintEngine::renderHintsChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateHints(); +} + +void QWindowsDirect2DPaintEngine::transformChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateTransform(); +} + +void QWindowsDirect2DPaintEngine::drawImage(const QRectF &rectangle, const QImage &image, + const QRectF &sr, Qt::ImageConversionFlags flags) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawImageTag); + + QPixmap pixmap = QPixmap::fromImage(image, flags); + drawPixmap(rectangle, pixmap, sr); +} + +void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, + const QPixmap &pm, + const QRectF &sr) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawPixmapTag); + + if (pm.isNull()) + return; + + if (pm.handle()->pixelType() == QPlatformPixmap::BitmapType) { + QImage i = pm.toImage(); + i.setColor(0, qRgba(0, 0, 0, 0)); + i.setColor(1, d->pen.qpen.color().rgba()); + drawImage(r, i, sr); + return; + } + + QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle()); + QWindowsDirect2DBitmap *bitmap = pp->bitmap(); + + if (bitmap->bitmap() != d->bitmap->bitmap()) { + // Good, src bitmap != dst bitmap + if (sr.isValid()) + d->dc()->DrawBitmap(bitmap->bitmap(), + to_d2d_rect_f(r), state()->opacity, + d->interpolationMode(), + to_d2d_rect_f(sr)); + else + d->dc()->DrawBitmap(bitmap->bitmap(), + to_d2d_rect_f(r), state()->opacity, + d->interpolationMode()); + } else { + // Ok, so the source pixmap and destination pixmap is the same. + // D2D is not fond of this scenario, deal with it through + // an intermediate bitmap + QWindowsDirect2DBitmap intermediate; + + if (sr.isValid()) { + bool r = intermediate.resize(sr.width(), sr.height()); + if (!r) { + qWarning("%s: Could not resize intermediate bitmap to source rect size", __FUNCTION__); + return; + } + + D2D1_RECT_U d2d_sr = to_d2d_rect_u(sr.toRect()); + HRESULT hr = intermediate.bitmap()->CopyFromBitmap(NULL, + bitmap->bitmap(), + &d2d_sr); + if (FAILED(hr)) { + qWarning("%s: Could not copy source rect area from source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr); + return; + } + } else { + bool r = intermediate.resize(bitmap->size().width(), + bitmap->size().height()); + if (!r) { + qWarning("%s: Could not resize intermediate bitmap to source bitmap size", __FUNCTION__); + return; + } + + HRESULT hr = intermediate.bitmap()->CopyFromBitmap(NULL, + bitmap->bitmap(), + NULL); + if (FAILED(hr)) { + qWarning("%s: Could not copy source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr); + return; + } + } + + d->dc()->DrawBitmap(intermediate.bitmap(), + to_d2d_rect_f(r), state()->opacity, + d->interpolationMode()); + } +} + +static ComPtr<IDWriteFontFace> fontFaceFromFontEngine(QFontEngine *fe) +{ + ComPtr<IDWriteFontFace> fontFace; + + switch (fe->type()) { + case QFontEngine::Win: + { + QWindowsFontEngine *wfe = static_cast<QWindowsFontEngine *>(fe); + QSharedPointer<QWindowsFontEngineData> wfed = wfe->fontEngineData(); + + HGDIOBJ oldfont = wfe->selectDesignFont(); + HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFaceFromHdc(wfed->hdc, &fontFace); + DeleteObject(SelectObject(wfed->hdc, oldfont)); + if (FAILED(hr)) + qWarning("%s: Could not create DirectWrite fontface from HDC: %#x", __FUNCTION__, hr); + + } + break; + +#ifndef QT_NO_DIRECTWRITE + + case QFontEngine::DirectWrite: + { + QWindowsFontEngineDirectWrite *wfedw = static_cast<QWindowsFontEngineDirectWrite *>(fe); + fontFace = wfedw->directWriteFontFace(); + } + break; + +#endif // QT_NO_DIRECTWRITE + + default: + qWarning("%s: Unknown font engine!", __FUNCTION__); + break; + } + + return fontFace; +} + +void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawStaticTextItemTag); + + if (qpen_style(d->pen.qpen) == Qt::NoPen) + return; + + if (staticTextItem->numGlyphs == 0) + return; + + // If we can't support the current configuration with Direct2D, fall back to slow path + // Most common cases are perspective transform and gradient brush as pen + if ((state()->transform().isAffine() == false) || d->pen.emulate) { + QPaintEngineEx::drawStaticTextItem(staticTextItem); + return; + } + + ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(staticTextItem->fontEngine()); + if (!fontFace) { + qWarning("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__); + QPaintEngineEx::drawStaticTextItem(staticTextItem); + return; + } + + QVector<UINT16> glyphIndices(staticTextItem->numGlyphs); + QVector<FLOAT> glyphAdvances(staticTextItem->numGlyphs); + QVector<DWRITE_GLYPH_OFFSET> glyphOffsets(staticTextItem->numGlyphs); + + // XXX Are we generating a lot of cache misses here? + for (int i = 0; i < staticTextItem->numGlyphs; i++) { + glyphIndices[i] = UINT16(staticTextItem->glyphs[i]); // Imperfect conversion here + + // This looks a little funky because the positions are precalculated + glyphAdvances[i] = 0; + glyphOffsets[i].advanceOffset = staticTextItem->glyphPositions[i].x.toReal(); + // Qt and Direct2D seem to disagree on the direction of the ascender offset... + glyphOffsets[i].ascenderOffset = staticTextItem->glyphPositions[i].y.toReal() * -1; + } + + drawGlyphRun(D2D1::Point2F(0, 0), + fontFace.Get(), + staticTextItem->font, + staticTextItem->numGlyphs, + glyphIndices.constData(), + glyphAdvances.constData(), + glyphOffsets.constData(), + false); +} + +void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawTextItemTag); + + if (qpen_style(d->pen.qpen) == Qt::NoPen) + return; + + const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + if (ti.glyphs.numGlyphs == 0) + return; + + // If we can't support the current configuration with Direct2D, fall back to slow path + // Most common cases are perspective transform and gradient brush as pen + if ((state()->transform().isAffine() == false) || d->pen.emulate) { + QPaintEngine::drawTextItem(p, textItem); + return; + } + + ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(ti.fontEngine); + if (!fontFace) { + qWarning("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__); + QPaintEngine::drawTextItem(p, textItem); + return; + } + + QVector<UINT16> glyphIndices(ti.glyphs.numGlyphs); + QVector<FLOAT> glyphAdvances(ti.glyphs.numGlyphs); + QVector<DWRITE_GLYPH_OFFSET> glyphOffsets(ti.glyphs.numGlyphs); + + // XXX Are we generating a lot of cache misses here? + for (int i = 0; i < ti.glyphs.numGlyphs; i++) { + glyphIndices[i] = UINT16(ti.glyphs.glyphs[i]); // Imperfect conversion here + glyphAdvances[i] = ti.glyphs.effectiveAdvance(i).toReal(); + glyphOffsets[i].advanceOffset = ti.glyphs.offsets[i].x.toReal(); + + // XXX Should we negate the y value like for static text items? + glyphOffsets[i].ascenderOffset = ti.glyphs.offsets[i].y.toReal(); + } + + const bool rtl = (ti.flags & QTextItem::RightToLeft); + const QPointF offset(rtl ? ti.width.toReal() : 0, 0); + + drawGlyphRun(to_d2d_point_2f(p + offset), + fontFace.Get(), + ti.font(), + ti.glyphs.numGlyphs, + glyphIndices.constData(), + glyphAdvances.constData(), + glyphOffsets.constData(), + rtl); +} + +// Points (1/72 inches) to Microsoft's Device Independent Pixels (1/96 inches) +inline static Q_DECL_CONSTEXPR FLOAT pointSizeToDIP(qreal pointSize) +{ + return pointSize + (pointSize / qreal(3.0)); +} + +inline static FLOAT pixelSizeToDIP(int pixelSize) +{ + FLOAT dpiX, dpiY; + factory()->GetDesktopDpi(&dpiX, &dpiY); + + return FLOAT(pixelSize) / (dpiY / 96.0f); +} + +inline static FLOAT fontSizeInDIP(const QFont &font) +{ + // Direct2d wants the font size in DIPs (Device Independent Pixels), each of which is 1/96 inches. + if (font.pixelSize() == -1) { + // font size was set as points + return pointSizeToDIP(font.pointSizeF()); + } else { + // font size was set as pixels + return pixelSizeToDIP(font.pixelSize()); + } +} + +void QWindowsDirect2DPaintEngine::drawGlyphRun(const D2D1_POINT_2F &pos, + IDWriteFontFace *fontFace, + const QFont &font, + int numGlyphs, + const UINT16 *glyphIndices, + const FLOAT *glyphAdvances, + const DWRITE_GLYPH_OFFSET *glyphOffsets, + bool rtl) +{ + Q_D(QWindowsDirect2DPaintEngine); + + DWRITE_GLYPH_RUN glyphRun = { + fontFace, // IDWriteFontFace *fontFace; + fontSizeInDIP(font), // FLOAT fontEmSize; + numGlyphs, // UINT32 glyphCount; + glyphIndices, // const UINT16 *glyphIndices; + glyphAdvances, // const FLOAT *glyphAdvances; + glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets; + FALSE, // BOOL isSideways; + rtl ? 1 : 0 // UINT32 bidiLevel; + }; + + const bool antiAlias = bool((state()->renderHints & QPainter::TextAntialiasing) + && !(font.styleStrategy() & QFont::NoAntialias)); + d->dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE + : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); + + d->dc()->DrawGlyphRun(pos, + &glyphRun, + NULL, + d->pen.brush.Get(), + DWRITE_MEASURING_MODE_GDI_CLASSIC); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h new file mode 100644 index 0000000000..6c74a07e88 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DPAINTENGINE_H +#define QWINDOWSDIRECT2DPAINTENGINE_H + +#include <QtCore/QScopedPointer> +#include <QtGui/private/qpaintengineex_p.h> + +#include <d2d1_1.h> +#include <dwrite_1.h> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPaintEnginePrivate; +class QWindowsDirect2DBitmap; + +class QWindowsDirect2DPaintEngine : public QPaintEngineEx +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngine) + +public: + QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap); + + bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE; + bool end() Q_DECL_OVERRIDE; + + Type type() const Q_DECL_OVERRIDE; + + void fill(const QVectorPath &path, const QBrush &brush) Q_DECL_OVERRIDE; + + void clip(const QVectorPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE; + void clip(const QRect &rect, Qt::ClipOperation op) Q_DECL_OVERRIDE; + void clip(const QRegion ®ion, Qt::ClipOperation op) Q_DECL_OVERRIDE; + void clip(const QPainterPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE; + + void clipEnabledChanged() Q_DECL_OVERRIDE; + void penChanged() Q_DECL_OVERRIDE; + void brushChanged() Q_DECL_OVERRIDE; + void brushOriginChanged() Q_DECL_OVERRIDE; + void opacityChanged() Q_DECL_OVERRIDE; + void compositionModeChanged() Q_DECL_OVERRIDE; + void renderHintsChanged() Q_DECL_OVERRIDE; + void transformChanged() Q_DECL_OVERRIDE; + + void drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE; + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE; + + void drawStaticTextItem(QStaticTextItem *staticTextItem) Q_DECL_OVERRIDE; + void drawTextItem(const QPointF &p, const QTextItem &textItem) Q_DECL_OVERRIDE; + +private: + void drawGlyphRun(const D2D1_POINT_2F &pos, IDWriteFontFace *fontFace, const QFont &font, + int numGlyphs, const UINT16 *glyphIndices, const FLOAT *glyphAdvances, + const DWRITE_GLYPH_OFFSET *glyphOffsets, bool rtl); +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DPAINTENGINE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp new file mode 100644 index 0000000000..072c4b3c0e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dplatformpixmap.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2dhelpers.h" + +#include <QtGui/QPainter> +#include <QtGui/QImage> +#include <QtGui/QPaintDevice> +#include <QtGui/QPaintEngine> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPlatformPixmapPrivate +{ +public: + QWindowsDirect2DPlatformPixmapPrivate() + : bitmap(new QWindowsDirect2DBitmap) + , device(new QWindowsDirect2DPaintDevice(bitmap.data(), QInternal::Pixmap)) + , devicePixelRatio(1.0) + {} + + QScopedPointer<QWindowsDirect2DBitmap> bitmap; + QScopedPointer<QWindowsDirect2DPaintDevice> device; + qreal devicePixelRatio; +}; + +static int qt_d2dpixmap_serno = 0; + +QWindowsDirect2DPlatformPixmap::QWindowsDirect2DPlatformPixmap(PixelType pixelType) + : QPlatformPixmap(pixelType, Direct2DClass) + , d_ptr(new QWindowsDirect2DPlatformPixmapPrivate) +{ + setSerialNumber(qt_d2dpixmap_serno++); +} + +QWindowsDirect2DPlatformPixmap::~QWindowsDirect2DPlatformPixmap() +{ + +} + +void QWindowsDirect2DPlatformPixmap::resize(int width, int height) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + + if (!d->bitmap->resize(width, height)) { + qWarning("%s: Could not resize bitmap", __FUNCTION__); + return; + } + + is_null = false; + w = width; + h = height; + this->d = 32; +} + +void QWindowsDirect2DPlatformPixmap::fromImage(const QImage &image, + Qt::ImageConversionFlags flags) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + + if (!d->bitmap->fromImage(image, flags)) { + qWarning("%s: Could not init from image", __FUNCTION__); + return; + } + + is_null = false; + w = image.width(); + h = image.height(); + this->d = 32; +} + +int QWindowsDirect2DPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + + Q_GUI_EXPORT int qt_paint_device_metric(const QPaintDevice *device, QPaintDevice::PaintDeviceMetric metric); + return qt_paint_device_metric(d->device.data(), metric); +} + +void QWindowsDirect2DPlatformPixmap::fill(const QColor &color) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + d->bitmap->fill(color); +} + +bool QWindowsDirect2DPlatformPixmap::hasAlphaChannel() const +{ + return true; +} + +QImage QWindowsDirect2DPlatformPixmap::toImage() const +{ + return toImage(QRect()); +} + +QImage QWindowsDirect2DPlatformPixmap::toImage(const QRect &rect) const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + + bool active = d->device->paintEngine()->isActive(); + + if (active) + d->device->paintEngine()->end(); + + QImage result = d->bitmap->toImage(rect); + + if (active) + d->device->paintEngine()->begin(d->device.data()); + + return result; +} + +QPaintEngine* QWindowsDirect2DPlatformPixmap::paintEngine() const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + return d->device->paintEngine(); +} + +qreal QWindowsDirect2DPlatformPixmap::devicePixelRatio() const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + return d->devicePixelRatio; +} + +void QWindowsDirect2DPlatformPixmap::setDevicePixelRatio(qreal scaleFactor) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + d->devicePixelRatio = scaleFactor; +} + +QWindowsDirect2DBitmap *QWindowsDirect2DPlatformPixmap::bitmap() const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + return d->bitmap.data(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h new file mode 100644 index 0000000000..e6684ea423 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DPLATFORMPIXMAP_H +#define QWINDOWSDIRECT2DPLATFORMPIXMAP_H + +#include <QtGui/qpa/qplatformpixmap.h> +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPlatformPixmapPrivate; +class QWindowsDirect2DBitmap; + +class QWindowsDirect2DPlatformPixmap : public QPlatformPixmap +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DPlatformPixmap) +public: + QWindowsDirect2DPlatformPixmap(PixelType pixelType); + ~QWindowsDirect2DPlatformPixmap(); + + virtual void resize(int width, int height); + virtual void fromImage(const QImage &image, + Qt::ImageConversionFlags flags); + + virtual int metric(QPaintDevice::PaintDeviceMetric metric) const; + virtual void fill(const QColor &color); + + virtual bool hasAlphaChannel() const; + + virtual QImage toImage() const; + virtual QImage toImage(const QRect &rect) const; + + virtual QPaintEngine* paintEngine() const; + + virtual qreal devicePixelRatio() const; + virtual void setDevicePixelRatio(qreal scaleFactor); + + QWindowsDirect2DBitmap *bitmap() const; + +private: + QScopedPointer<QWindowsDirect2DPlatformPixmapPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DPLATFORMPIXMAP_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp new file mode 100644 index 0000000000..f75bb49fd9 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dintegration.h" + +#include <QtGui/qpa/qplatformintegrationplugin.h> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "direct2d.json") +public: + QPlatformIntegration *create(const QString&, const QStringList&); +}; + +QPlatformIntegration *QWindowsDirect2DIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + if (system.compare(system, QStringLiteral("direct2d"), Qt::CaseInsensitive) == 0) + return QWindowsDirect2DIntegration::create(paramList); + return 0; +} + +QT_END_NAMESPACE + +#include "qwindowsdirect2dplatformplugin.moc" diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp new file mode 100644 index 0000000000..bf860f982e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dwindow.h" +#include "qwindowsdirect2ddevicecontext.h" +#include "qwindowsdirect2dhelpers.h" + +#include <d3d11.h> +#include <d2d1_1.h> +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data) + : QWindowsWindow(window, data) + , m_needsFullFlush(true) +{ + DXGI_SWAP_CHAIN_DESC1 desc = {}; + + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 1; + desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + + HRESULT hr = QWindowsDirect2DContext::instance()->dxgiFactory()->CreateSwapChainForHwnd( + QWindowsDirect2DContext::instance()->d3dDevice(), // [in] IUnknown *pDevice + handle(), // [in] HWND hWnd + &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc + NULL, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc + NULL, // [in] IDXGIOutput *pRestrictToOutput + m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain + + 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() +{ +} + +void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset) +{ + DXGI_SWAP_CHAIN_DESC1 desc; + HRESULT hr = m_swapChain->GetDesc1(&desc); + QRect geom = geometry(); + + if (FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height())) { + resizeSwapChain(geom.size()); + m_swapChain->GetDesc1(&desc); + } + + setupBitmap(); + if (!m_bitmap) + return; + + 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(); + m_swapChain->Present(1, 0); +} + +void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size) +{ + if (!m_swapChain) + return; + + m_bitmap.reset(); + m_deviceContext->SetTarget(Q_NULLPTR); + + HRESULT hr = m_swapChain->ResizeBuffers(0, + size.width(), size.height(), + DXGI_FORMAT_UNKNOWN, + 0); + if (FAILED(hr)) + qWarning("%s: Could not resize swap chain: %#x", __FUNCTION__, hr); + + m_needsFullFlush = true; +} + +void QWindowsDirect2DWindow::setupBitmap() +{ + if (m_bitmap) + return; + + if (!m_deviceContext) + return; + + if (!m_swapChain) + return; + + 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; + } + + ComPtr<ID2D1Bitmap1> backBufferBitmap; + hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), NULL, backBufferBitmap.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#x", __FUNCTION__, hr); + return; + } + + m_bitmap.reset(new QWindowsDirect2DBitmap(backBufferBitmap.Get(), m_deviceContext.Get())); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h new file mode 100644 index 0000000000..7996904639 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DWINDOW_H +#define QWINDOWSDIRECT2DWINDOW_H + +#include "qwindowswindow.h" +#include "qwindowsdirect2dbitmap.h" + +#include <dxgi1_2.h> +#include <wrl.h> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DWindow : public QWindowsWindow +{ +public: + QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data); + ~QWindowsDirect2DWindow(); + + void flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset); + +private: + void resizeSwapChain(const QSize &size); + void setupBitmap(); + +private: + Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain; + Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_deviceContext; + QScopedPointer<QWindowsDirect2DBitmap> m_bitmap; + bool m_needsFullFlush; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DWINDOW_H |