1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qwindowsdirect2dbitmap.h"
41 #include "qwindowsdirect2dcontext.h"
42 #include "qwindowsdirect2dhelpers.h"
43 #include "qwindowsdirect2ddevicecontext.h"
44 
45 #include <QtGui/qimage.h>
46 #include <QtGui/qcolor.h>
47 
48 #include <wrl.h>
49 
50 using Microsoft::WRL::ComPtr;
51 
52 QT_BEGIN_NAMESPACE
53 
54 class QWindowsDirect2DBitmapPrivate
55 {
56 public:
QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext * dc=nullptr,ID2D1Bitmap1 * bm=nullptr)57     QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext *dc = nullptr,
58                                   ID2D1Bitmap1 *bm = nullptr)
59         : deviceContext(new QWindowsDirect2DDeviceContext(dc))
60         , bitmap(bm)
61 
62     {
63         deviceContext->get()->SetTarget(bm);
64     }
65 
bitmapProperties() const66     D2D1_BITMAP_PROPERTIES1 bitmapProperties() const
67     {
68         FLOAT dpiX, dpiY;
69         QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY);
70 
71         return D2D1::BitmapProperties1(
72                     D2D1_BITMAP_OPTIONS_TARGET,
73                     D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
74                                       D2D1_ALPHA_MODE_PREMULTIPLIED),
75                     dpiX, dpiY);
76 
77     }
78 
resize(int width,int height,const void * data=nullptr,int pitch=0)79     bool resize(int width, int height, const void *data = nullptr, int pitch = 0)
80     {
81         deviceContext->get()->SetTarget(nullptr);
82         bitmap.Reset();
83 
84         D2D1_SIZE_U size = {
85             UINT32(width), UINT32(height)
86         };
87 
88         HRESULT hr = deviceContext->get()->CreateBitmap(size, data, UINT32(pitch),
89                                                         bitmapProperties(),
90                                                         bitmap.ReleaseAndGetAddressOf());
91         if (SUCCEEDED(hr))
92             deviceContext->get()->SetTarget(bitmap.Get());
93         else
94             qWarning("%s: Could not create bitmap: %#lx", __FUNCTION__, hr);
95 
96         return SUCCEEDED(hr);
97     }
98 
toImage(const QRect & rect)99     QImage toImage(const QRect &rect)
100     {
101         if (!bitmap)
102             return QImage();
103 
104         ComPtr<ID2D1Bitmap1> mappingCopy;
105 
106         HRESULT hr = S_OK;
107         D2D1_SIZE_U size = bitmap->GetPixelSize();
108 
109         D2D1_BITMAP_PROPERTIES1 properties = bitmapProperties();
110         properties.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ;
111 
112         hr = deviceContext->get()->CreateBitmap(size, nullptr, 0,
113                                                 properties, &mappingCopy);
114         if (FAILED(hr)) {
115             qWarning("%s: Could not create bitmap: %#lx", __FUNCTION__, hr);
116             return QImage();
117         }
118 
119         hr = mappingCopy->CopyFromBitmap(nullptr, bitmap.Get(), nullptr);
120         if (FAILED(hr)) {
121             qWarning("%s: Could not copy from bitmap: %#lx", __FUNCTION__, hr);
122             return QImage();
123         }
124 
125         D2D1_MAPPED_RECT mappedRect;
126         hr = mappingCopy->Map(D2D1_MAP_OPTIONS_READ, &mappedRect);
127         if (FAILED(hr)) {
128             qWarning("%s: Could not map: %#lx", __FUNCTION__, hr);
129             return QImage();
130         }
131 
132         return QImage(static_cast<const uchar *>(mappedRect.bits),
133                       int(size.width), int(size.height), int(mappedRect.pitch),
134                       QImage::Format_ARGB32_Premultiplied).copy(rect);
135     }
136 
137     QScopedPointer<QWindowsDirect2DDeviceContext> deviceContext;
138     ComPtr<ID2D1Bitmap1> bitmap;
139 };
140 
QWindowsDirect2DBitmap()141 QWindowsDirect2DBitmap::QWindowsDirect2DBitmap()
142     : d_ptr(new QWindowsDirect2DBitmapPrivate)
143 {
144 }
145 
QWindowsDirect2DBitmap(ID2D1Bitmap1 * bitmap,ID2D1DeviceContext * dc)146 QWindowsDirect2DBitmap::QWindowsDirect2DBitmap(ID2D1Bitmap1 *bitmap, ID2D1DeviceContext *dc)
147     : d_ptr(new QWindowsDirect2DBitmapPrivate(dc, bitmap))
148 {
149 }
150 
~QWindowsDirect2DBitmap()151 QWindowsDirect2DBitmap::~QWindowsDirect2DBitmap()
152 {
153 }
154 
resize(int width,int height)155 bool QWindowsDirect2DBitmap::resize(int width, int height)
156 {
157     Q_D(QWindowsDirect2DBitmap);
158     return d->resize(width, height);
159 }
160 
fromImage(const QImage & image,Qt::ImageConversionFlags flags)161 bool QWindowsDirect2DBitmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags)
162 {
163     Q_D(QWindowsDirect2DBitmap);
164 
165     QImage converted = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
166     return d->resize(converted.width(), converted.height(),
167                      converted.constBits(), converted.bytesPerLine());
168 }
169 
bitmap() const170 ID2D1Bitmap1* QWindowsDirect2DBitmap::bitmap() const
171 {
172     Q_D(const QWindowsDirect2DBitmap);
173     return d->bitmap.Get();
174 }
175 
deviceContext() const176 QWindowsDirect2DDeviceContext *QWindowsDirect2DBitmap::deviceContext() const
177 {
178     Q_D(const QWindowsDirect2DBitmap);
179     return d->deviceContext.data();
180 }
181 
fill(const QColor & color)182 void QWindowsDirect2DBitmap::fill(const QColor &color)
183 {
184     Q_D(QWindowsDirect2DBitmap);
185 
186     d->deviceContext->begin();
187     d->deviceContext->get()->Clear(to_d2d_color_f(color));
188     d->deviceContext->end();
189 }
190 
toImage(const QRect & rect)191 QImage QWindowsDirect2DBitmap::toImage(const QRect &rect)
192 {
193     Q_D(QWindowsDirect2DBitmap);
194     return d->toImage(rect);
195 }
196 
size() const197 QSize QWindowsDirect2DBitmap::size() const
198 {
199     Q_D(const QWindowsDirect2DBitmap);
200 
201     D2D1_SIZE_U size = d->bitmap->GetPixelSize();
202     return QSize(int(size.width), int(size.height));
203 }
204 
205 QT_END_NAMESPACE
206