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 "qwindowsnativeimage_p.h"
41 
42 #include <QtGui/private/qpaintengine_p.h>
43 #include <QtGui/private/qpaintengine_raster_p.h>
44 
45 QT_BEGIN_NAMESPACE
46 
47 typedef struct {
48     BITMAPINFOHEADER bmiHeader;
49     DWORD redMask;
50     DWORD greenMask;
51     DWORD blueMask;
52 } BITMAPINFO_MASK;
53 
54 /*!
55     \class QWindowsNativeImage
56     \brief Windows Native image
57 
58     Note that size can be 0 (widget autotests with zero size), which
59     causes CreateDIBSection() to fail.
60 
61     \sa QWindowsBackingStore
62     \internal
63 */
64 
createDC()65 static inline HDC createDC()
66 {
67     HDC display_dc = GetDC(0);
68     HDC hdc = CreateCompatibleDC(display_dc);
69     ReleaseDC(0, display_dc);
70     Q_ASSERT(hdc);
71     return hdc;
72 }
73 
createDIB(HDC hdc,int width,int height,QImage::Format format,uchar ** bitsIn)74 static inline HBITMAP createDIB(HDC hdc, int width, int height,
75                                 QImage::Format format,
76                                 uchar **bitsIn)
77 {
78     BITMAPINFO_MASK bmi;
79     memset(&bmi, 0, sizeof(bmi));
80     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
81     bmi.bmiHeader.biWidth       = width;
82     bmi.bmiHeader.biHeight      = -height; // top-down.
83     bmi.bmiHeader.biPlanes      = 1;
84     bmi.bmiHeader.biSizeImage   = 0;
85 
86     if (format == QImage::Format_RGB16) {
87         bmi.bmiHeader.biBitCount = 16;
88         bmi.bmiHeader.biCompression = BI_BITFIELDS;
89         bmi.redMask = 0xF800;
90         bmi.greenMask = 0x07E0;
91         bmi.blueMask = 0x001F;
92     } else {
93         bmi.bmiHeader.biBitCount    = 32;
94         bmi.bmiHeader.biCompression = BI_RGB;
95         bmi.redMask = 0;
96         bmi.greenMask = 0;
97         bmi.blueMask = 0;
98     }
99 
100     uchar *bits = nullptr;
101     HBITMAP bitmap = CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO *>(&bmi),
102                                       DIB_RGB_COLORS, reinterpret_cast<void **>(&bits), 0, 0);
103     if (Q_UNLIKELY(!bitmap || !bits)) {
104         qFatal("%s: CreateDIBSection failed (%dx%d, format: %d)", __FUNCTION__,
105                width, height, int(format));
106     }
107 
108     *bitsIn = bits;
109     return bitmap;
110 }
111 
QWindowsNativeImage(int width,int height,QImage::Format format)112 QWindowsNativeImage::QWindowsNativeImage(int width, int height,
113                                          QImage::Format format) :
114     m_hdc(createDC())
115 {
116     if (width != 0 && height != 0) {
117         uchar *bits;
118         m_bitmap = createDIB(m_hdc, width, height, format, &bits);
119         m_null_bitmap = static_cast<HBITMAP>(SelectObject(m_hdc, m_bitmap));
120         m_image = QImage(bits, width, height, format);
121         Q_ASSERT(m_image.paintEngine()->type() == QPaintEngine::Raster);
122         static_cast<QRasterPaintEngine *>(m_image.paintEngine())->setDC(m_hdc);
123     } else {
124         m_image = QImage(width, height, format);
125     }
126 
127     GdiFlush();
128 }
129 
~QWindowsNativeImage()130 QWindowsNativeImage::~QWindowsNativeImage()
131 {
132     if (m_hdc) {
133         if (m_bitmap) {
134             if (m_null_bitmap)
135                 SelectObject(m_hdc, m_null_bitmap);
136             DeleteObject(m_bitmap);
137         }
138         DeleteDC(m_hdc);
139     }
140 }
141 
systemFormat()142 QImage::Format QWindowsNativeImage::systemFormat()
143 {
144     static int depth = -1;
145     if (depth == -1) {
146         if (HDC defaultDC = GetDC(0)) {
147             depth = GetDeviceCaps(defaultDC, BITSPIXEL);
148             ReleaseDC(0, defaultDC);
149         } else {
150             // FIXME Same remark as in QWindowsFontDatabase::defaultVerticalDPI()
151             // BONUS FIXME: Is 32 too generous/optimistic?
152             depth = 32;
153         }
154     }
155     return depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
156 }
157 
158 QT_END_NAMESPACE
159