1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QRGBA64_H
5#define QRGBA64_H
6
7#include <QtGui/qtguiglobal.h>
8#include <QtCore/qprocessordetection.h>
9
10QT_BEGIN_NAMESPACE
11
12class QRgba64 {
13 quint64 rgba;
14
15 // Make sure that the representation always has the order: red green blue alpha, independent
16 // of byte order. This way, vector operations that assume 4 16-bit values see the correct ones.
17 enum Shifts {
18#if Q_BYTE_ORDER == Q_BIG_ENDIAN
19 RedShift = 48,
20 GreenShift = 32,
21 BlueShift = 16,
22 AlphaShift = 0
23#else // little endian:
24 RedShift = 0,
25 GreenShift = 16,
26 BlueShift = 32,
27 AlphaShift = 48
28#endif
29 };
30
31 explicit Q_ALWAYS_INLINE constexpr QRgba64(quint64 c) : rgba(c) { }
32public:
33 QRgba64() = default;
34
35 constexpr static
36 QRgba64 fromRgba64(quint64 c)
37 {
38 return QRgba64(c);
39 }
40 constexpr static
41 QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
42 {
43 return fromRgba64(c: quint64(red) << RedShift
44 | quint64(green) << GreenShift
45 | quint64(blue) << BlueShift
46 | quint64(alpha) << AlphaShift);
47 }
48 constexpr static QRgba64 fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
49 {
50 QRgba64 rgb64 = fromRgba64(red, green, blue, alpha);
51 // Expand the range so that 0x00 maps to 0x0000 and 0xff maps to 0xffff.
52 rgb64.rgba |= rgb64.rgba << 8;
53 return rgb64;
54 }
55 constexpr static
56 QRgba64 fromArgb32(uint rgb)
57 {
58 return fromRgba(red: quint8(rgb >> 16), green: quint8(rgb >> 8), blue: quint8(rgb), alpha: quint8(rgb >> 24));
59 }
60
61 constexpr bool isOpaque() const
62 {
63 return (rgba & alphaMask()) == alphaMask();
64 }
65 constexpr bool isTransparent() const
66 {
67 return (rgba & alphaMask()) == 0;
68 }
69
70 constexpr quint16 red() const { return quint16(rgba >> RedShift); }
71 constexpr quint16 green() const { return quint16(rgba >> GreenShift); }
72 constexpr quint16 blue() const { return quint16(rgba >> BlueShift); }
73 constexpr quint16 alpha() const { return quint16(rgba >> AlphaShift); }
74 void setRed(quint16 _red) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << RedShift)) | (quint64(_red) << RedShift); }
75 void setGreen(quint16 _green) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << GreenShift)) | (quint64(_green) << GreenShift); }
76 void setBlue(quint16 _blue) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << BlueShift)) | (quint64(_blue) << BlueShift); }
77 void setAlpha(quint16 _alpha) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << AlphaShift)) | (quint64(_alpha) << AlphaShift); }
78
79 constexpr quint8 red8() const { return div_257(x: red()); }
80 constexpr quint8 green8() const { return div_257(x: green()); }
81 constexpr quint8 blue8() const { return div_257(x: blue()); }
82 constexpr quint8 alpha8() const { return div_257(x: alpha()); }
83 constexpr uint toArgb32() const
84 {
85 quint64 br = rgba & Q_UINT64_C(0xffff0000ffff);
86 quint64 ag = (rgba >> 16) & Q_UINT64_C(0xffff0000ffff);
87 br += Q_UINT64_C(0x8000000080);
88 ag += Q_UINT64_C(0x8000000080);
89 br = (br - ((br >> 8) & Q_UINT64_C(0xffff0000ffff))) >> 8;
90 ag = (ag - ((ag >> 8) & Q_UINT64_C(0xffff0000ffff)));
91#if Q_BYTE_ORDER == Q_BIG_ENDIAN
92 return ((br << 24) & 0xff000000)
93 | ((ag >> 24) & 0xff0000)
94 | ((br >> 24) & 0xff00)
95 | ((ag >> 8) & 0xff);
96#else
97 return ((ag >> 16) & 0xff000000)
98 | ((br << 16) & 0xff0000)
99 | (ag & 0xff00)
100 | ((br >> 32) & 0xff);
101#endif
102 }
103 constexpr ushort toRgb16() const
104 {
105 return ushort((red() & 0xf800) | ((green() >> 10) << 5) | (blue() >> 11));
106 }
107
108 constexpr QRgba64 premultiplied() const
109 {
110 if (isOpaque())
111 return *this;
112 if (isTransparent())
113 return QRgba64::fromRgba64(c: 0);
114 const quint64 a = alpha();
115 quint64 br = (rgba & Q_UINT64_C(0xffff0000ffff)) * a;
116 quint64 ag = ((rgba >> 16) & Q_UINT64_C(0xffff0000ffff)) * a;
117 br = (br + ((br >> 16) & Q_UINT64_C(0xffff0000ffff)) + Q_UINT64_C(0x800000008000));
118 ag = (ag + ((ag >> 16) & Q_UINT64_C(0xffff0000ffff)) + Q_UINT64_C(0x800000008000));
119#if Q_BYTE_ORDER == Q_BIG_ENDIAN
120 ag = ag & Q_UINT64_C(0xffff0000ffff0000);
121 br = (br >> 16) & Q_UINT64_C(0xffff00000000);
122 return fromRgba64(a | br | ag);
123#else
124 br = (br >> 16) & Q_UINT64_C(0xffff0000ffff);
125 ag = ag & Q_UINT64_C(0xffff0000);
126 return fromRgba64(c: (a << 48) | br | ag);
127#endif
128 }
129
130 constexpr QRgba64 unpremultiplied() const
131 {
132#if Q_PROCESSOR_WORDSIZE < 8
133 return unpremultiplied_32bit();
134#else
135 return unpremultiplied_64bit();
136#endif
137 }
138
139 constexpr operator quint64() const
140 {
141 return rgba;
142 }
143
144 QRgba64 &operator=(quint64 _rgba) noexcept
145 {
146 rgba = _rgba;
147 return *this;
148 }
149
150private:
151 static constexpr Q_ALWAYS_INLINE quint64 alphaMask() { return Q_UINT64_C(0xffff) << AlphaShift; }
152
153 static constexpr Q_ALWAYS_INLINE quint8 div_257_floor(uint x) { return quint8((x - (x >> 8)) >> 8); }
154 static constexpr Q_ALWAYS_INLINE quint8 div_257(quint16 x) { return div_257_floor(x: x + 128U); }
155 constexpr Q_ALWAYS_INLINE QRgba64 unpremultiplied_32bit() const
156 {
157 if (isOpaque() || isTransparent())
158 return *this;
159 const quint32 a = alpha();
160 const quint16 r = quint16((red() * 0xffff + a/2) / a);
161 const quint16 g = quint16((green() * 0xffff + a/2) / a);
162 const quint16 b = quint16((blue() * 0xffff + a/2) / a);
163 return fromRgba64(red: r, green: g, blue: b, alpha: quint16(a));
164 }
165 constexpr Q_ALWAYS_INLINE QRgba64 unpremultiplied_64bit() const
166 {
167 if (isOpaque() || isTransparent())
168 return *this;
169 const quint64 a = alpha();
170 const quint64 fa = (Q_UINT64_C(0xffff00008000) + a/2) / a;
171 const quint16 r = quint16((red() * fa + 0x80000000) >> 32);
172 const quint16 g = quint16((green() * fa + 0x80000000) >> 32);
173 const quint16 b = quint16((blue() * fa + 0x80000000) >> 32);
174 return fromRgba64(red: r, green: g, blue: b, alpha: quint16(a));
175 }
176};
177
178Q_DECLARE_TYPEINFO(QRgba64, Q_PRIMITIVE_TYPE);
179
180constexpr inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
181{
182 return QRgba64::fromRgba64(red: r, green: g, blue: b, alpha: a);
183}
184
185constexpr inline QRgba64 qRgba64(quint64 c)
186{
187 return QRgba64::fromRgba64(c);
188}
189
190constexpr inline QRgba64 qPremultiply(QRgba64 c)
191{
192 return c.premultiplied();
193}
194
195constexpr inline QRgba64 qUnpremultiply(QRgba64 c)
196{
197 return c.unpremultiplied();
198}
199
200inline constexpr uint qRed(QRgba64 rgb)
201{ return rgb.red8(); }
202
203inline constexpr uint qGreen(QRgba64 rgb)
204{ return rgb.green8(); }
205
206inline constexpr uint qBlue(QRgba64 rgb)
207{ return rgb.blue8(); }
208
209inline constexpr uint qAlpha(QRgba64 rgb)
210{ return rgb.alpha8(); }
211
212QT_END_NAMESPACE
213
214#endif // QRGBA64_H
215

source code of qtbase/src/gui/painting/qrgba64.h