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 QtGui module 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 #ifndef QRGBA64_H
41 #define QRGBA64_H
42 
43 #include <QtGui/qtguiglobal.h>
44 #include <QtCore/qprocessordetection.h>
45 
46 QT_BEGIN_NAMESPACE
47 
48 class QRgba64 {
49     quint64 rgba;
50 
51     // Make sure that the representation always has the order: red green blue alpha, independent
52     // of byte order. This way, vector operations that assume 4 16-bit values see the correct ones.
53     enum Shifts {
54 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
55         RedShift = 48,
56         GreenShift = 32,
57         BlueShift = 16,
58         AlphaShift = 0
59 #else // little endian:
60         RedShift = 0,
61         GreenShift = 16,
62         BlueShift = 32,
63         AlphaShift = 48
64 #endif
65     };
66 
QRgba64(quint64 c)67     explicit Q_ALWAYS_INLINE Q_DECL_CONSTEXPR QRgba64(quint64 c) : rgba(c) { }
68 public:
69     QRgba64() = default;
70 
71     Q_DECL_CONSTEXPR static
fromRgba64(quint64 c)72     QRgba64 fromRgba64(quint64 c)
73     {
74         return QRgba64(c);
75     }
76     Q_DECL_CONSTEXPR static
fromRgba64(quint16 red,quint16 green,quint16 blue,quint16 alpha)77     QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
78     {
79         return fromRgba64(quint64(red)   << RedShift
80                         | quint64(green) << GreenShift
81                         | quint64(blue)  << BlueShift
82                         | quint64(alpha) << AlphaShift);
83     }
fromRgba(quint8 red,quint8 green,quint8 blue,quint8 alpha)84     Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
85     {
86         QRgba64 rgb64 = fromRgba64(red, green, blue, alpha);
87         // Expand the range so that 0x00 maps to 0x0000 and 0xff maps to 0xffff.
88         rgb64.rgba |= rgb64.rgba << 8;
89         return rgb64;
90     }
91     Q_DECL_RELAXED_CONSTEXPR static
fromArgb32(uint rgb)92     QRgba64 fromArgb32(uint rgb)
93     {
94         return fromRgba(quint8(rgb >> 16), quint8(rgb >> 8), quint8(rgb), quint8(rgb >> 24));
95     }
96 
isOpaque()97     Q_DECL_CONSTEXPR bool isOpaque() const
98     {
99         return (rgba & alphaMask()) == alphaMask();
100     }
isTransparent()101     Q_DECL_CONSTEXPR bool isTransparent() const
102     {
103         return (rgba & alphaMask()) == 0;
104     }
105 
red()106     Q_DECL_CONSTEXPR quint16 red()   const { return quint16(rgba >> RedShift);   }
green()107     Q_DECL_CONSTEXPR quint16 green() const { return quint16(rgba >> GreenShift); }
blue()108     Q_DECL_CONSTEXPR quint16 blue()  const { return quint16(rgba >> BlueShift);  }
alpha()109     Q_DECL_CONSTEXPR quint16 alpha() const { return quint16(rgba >> AlphaShift); }
setRed(quint16 _red)110     void setRed(quint16 _red)     { rgba = (rgba & ~(Q_UINT64_C(0xffff) << RedShift))   | (quint64(_red) << RedShift); }
setGreen(quint16 _green)111     void setGreen(quint16 _green) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << GreenShift)) | (quint64(_green) << GreenShift); }
setBlue(quint16 _blue)112     void setBlue(quint16 _blue)   { rgba = (rgba & ~(Q_UINT64_C(0xffff) << BlueShift))  | (quint64(_blue) << BlueShift); }
setAlpha(quint16 _alpha)113     void setAlpha(quint16 _alpha) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << AlphaShift)) | (quint64(_alpha) << AlphaShift); }
114 
red8()115     Q_DECL_CONSTEXPR quint8 red8()   const { return div_257(red()); }
green8()116     Q_DECL_CONSTEXPR quint8 green8() const { return div_257(green()); }
blue8()117     Q_DECL_CONSTEXPR quint8 blue8()  const { return div_257(blue()); }
alpha8()118     Q_DECL_CONSTEXPR quint8 alpha8() const { return div_257(alpha()); }
toArgb32()119     Q_DECL_CONSTEXPR uint toArgb32() const
120     {
121 #if defined(__cpp_constexpr) && __cpp_constexpr-0 >= 201304
122         quint64 br = rgba & Q_UINT64_C(0xffff0000ffff);
123         quint64 ag = (rgba >> 16) & Q_UINT64_C(0xffff0000ffff);
124         br += Q_UINT64_C(0x8000000080);
125         ag += Q_UINT64_C(0x8000000080);
126         br = (br - ((br >> 8) & Q_UINT64_C(0xffff0000ffff))) >> 8;
127         ag = (ag - ((ag >> 8) & Q_UINT64_C(0xffff0000ffff)));
128 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
129         return ((br << 24) & 0xff000000)
130              | ((ag >> 24) & 0xff0000)
131              | ((br >> 24) & 0xff00)
132              | ((ag >> 8)  & 0xff);
133 #else
134         return ((ag >> 16) & 0xff000000)
135              | ((br << 16) & 0xff0000)
136              | (ag         & 0xff00)
137              | ((br >> 32) & 0xff);
138 #endif
139 #else
140         return uint((alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8());
141 #endif
142     }
toRgb16()143     Q_DECL_CONSTEXPR ushort toRgb16() const
144     {
145         return ushort((red() & 0xf800) | ((green() >> 10) << 5) | (blue() >> 11));
146     }
147 
premultiplied()148     Q_DECL_RELAXED_CONSTEXPR QRgba64 premultiplied() const
149     {
150         if (isOpaque())
151             return *this;
152         if (isTransparent())
153             return QRgba64::fromRgba64(0);
154         const quint64 a = alpha();
155         quint64 br = (rgba & Q_UINT64_C(0xffff0000ffff)) * a;
156         quint64 ag = ((rgba >> 16) & Q_UINT64_C(0xffff0000ffff)) * a;
157         br = (br + ((br >> 16) & Q_UINT64_C(0xffff0000ffff)) + Q_UINT64_C(0x800000008000));
158         ag = (ag + ((ag >> 16) & Q_UINT64_C(0xffff0000ffff)) + Q_UINT64_C(0x800000008000));
159 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
160         ag = ag & Q_UINT64_C(0xffff0000ffff0000);
161         br = (br >> 16) & Q_UINT64_C(0xffff00000000);
162         return fromRgba64(a | br | ag);
163 #else
164         br = (br >> 16) & Q_UINT64_C(0xffff0000ffff);
165         ag = ag & Q_UINT64_C(0xffff0000);
166         return fromRgba64((a << 48) | br | ag);
167 #endif
168     }
169 
unpremultiplied()170     Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied() const
171     {
172 #if Q_PROCESSOR_WORDSIZE < 8
173         return unpremultiplied_32bit();
174 #else
175         return unpremultiplied_64bit();
176 #endif
177     }
178 
quint64()179     Q_DECL_CONSTEXPR operator quint64() const
180     {
181         return rgba;
182     }
183 
184     QRgba64 operator=(quint64 _rgba)
185     {
186         rgba = _rgba;
187         return *this;
188     }
189 
190 private:
alphaMask()191     static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint64 alphaMask() { return Q_UINT64_C(0xffff) << AlphaShift; }
192 
div_257_floor(uint x)193     static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint8 div_257_floor(uint x) { return quint8((x - (x >> 8)) >> 8); }
div_257(quint16 x)194     static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint8 div_257(quint16 x) { return div_257_floor(x + 128U); }
unpremultiplied_32bit()195     Q_DECL_RELAXED_CONSTEXPR Q_ALWAYS_INLINE QRgba64 unpremultiplied_32bit() const
196     {
197         if (isOpaque() || isTransparent())
198             return *this;
199         const quint32 a = alpha();
200         const quint16 r = quint16((red()   * 0xffff + a/2) / a);
201         const quint16 g = quint16((green() * 0xffff + a/2) / a);
202         const quint16 b = quint16((blue()  * 0xffff + a/2) / a);
203         return fromRgba64(r, g, b, quint16(a));
204     }
unpremultiplied_64bit()205     Q_DECL_RELAXED_CONSTEXPR Q_ALWAYS_INLINE QRgba64 unpremultiplied_64bit() const
206     {
207         if (isOpaque() || isTransparent())
208             return *this;
209         const quint64 a = alpha();
210         const quint64 fa = (Q_UINT64_C(0xffff00008000) + a/2) / a;
211         const quint16 r = quint16((red()   * fa + 0x80000000) >> 32);
212         const quint16 g = quint16((green() * fa + 0x80000000) >> 32);
213         const quint16 b = quint16((blue()  * fa + 0x80000000) >> 32);
214         return fromRgba64(r, g, b, quint16(a));
215     }
216 };
217 
218 Q_DECLARE_TYPEINFO(QRgba64, Q_PRIMITIVE_TYPE);
219 
qRgba64(quint16 r,quint16 g,quint16 b,quint16 a)220 Q_DECL_CONSTEXPR inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
221 {
222     return QRgba64::fromRgba64(r, g, b, a);
223 }
224 
qRgba64(quint64 c)225 Q_DECL_CONSTEXPR inline QRgba64 qRgba64(quint64 c)
226 {
227     return QRgba64::fromRgba64(c);
228 }
229 
qPremultiply(QRgba64 c)230 Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qPremultiply(QRgba64 c)
231 {
232     return c.premultiplied();
233 }
234 
qUnpremultiply(QRgba64 c)235 Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qUnpremultiply(QRgba64 c)
236 {
237     return c.unpremultiplied();
238 }
239 
qRed(QRgba64 rgb)240 inline Q_DECL_CONSTEXPR uint qRed(QRgba64 rgb)
241 { return rgb.red8(); }
242 
qGreen(QRgba64 rgb)243 inline Q_DECL_CONSTEXPR uint qGreen(QRgba64 rgb)
244 { return rgb.green8(); }
245 
qBlue(QRgba64 rgb)246 inline Q_DECL_CONSTEXPR uint qBlue(QRgba64 rgb)
247 { return rgb.blue8(); }
248 
qAlpha(QRgba64 rgb)249 inline Q_DECL_CONSTEXPR uint qAlpha(QRgba64 rgb)
250 { return rgb.alpha8(); }
251 
252 QT_END_NAMESPACE
253 
254 #endif // QRGBA64_H
255