1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Oracle Corporation code.
16 : *
17 : * The Initial Developer of the Original Code is Oracle Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2005
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Stuart Parmenter <pavlov@pavlov.net>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef GFX_COLOR_H
39 : #define GFX_COLOR_H
40 :
41 : #include "gfxTypes.h"
42 :
43 : #include "prbit.h" // for PR_ROTATE_(LEFT,RIGHT)32
44 : #include "prio.h" // for ntohl
45 :
46 : #define GFX_UINT32_FROM_BPTR(pbptr,i) (((PRUint32*)(pbptr))[i])
47 :
48 : #if defined(IS_BIG_ENDIAN)
49 : #define GFX_NTOHL(x) (x)
50 : #define GFX_HAVE_CHEAP_NTOHL
51 : #elif defined(_WIN32)
52 : #if (_MSC_VER >= 1300) // also excludes MinGW
53 : #include <stdlib.h>
54 : #pragma intrinsic(_byteswap_ulong)
55 : #define GFX_NTOHL(x) _byteswap_ulong(x)
56 : #define GFX_HAVE_CHEAP_NTOHL
57 : #else
58 : // A reasonably fast generic little-endian implementation.
59 : #define GFX_NTOHL(x) \
60 : ( (PR_ROTATE_RIGHT32((x),8) & 0xFF00FF00) | \
61 : (PR_ROTATE_LEFT32((x),8) & 0x00FF00FF) )
62 : #endif
63 : #else
64 : #define GFX_NTOHL(x) ntohl(x)
65 : #define GFX_HAVE_CHEAP_NTOHL
66 : #endif
67 :
68 : /**
69 : * GFX_0XFF_PPIXEL_FROM_BPTR(x)
70 : *
71 : * Avoid tortured construction of 32-bit ARGB pixel from 3 individual bytes
72 : * of memory plus constant 0xFF. RGB bytes are already contiguous!
73 : * Equivalent to: GFX_PACKED_PIXEL(0xff,r,g,b)
74 : *
75 : * Attempt to use fast byte-swapping instruction(s), e.g. bswap on x86, in
76 : * preference to a sequence of shift/or operations.
77 : */
78 : #if defined(GFX_HAVE_CHEAP_NTOHL)
79 : #define GFX_0XFF_PPIXEL_FROM_UINT32(x) \
80 : ( (GFX_NTOHL(x) >> 8) | (0xFF << 24) )
81 : #else
82 : // A reasonably fast generic little-endian implementation.
83 : #define GFX_0XFF_PPIXEL_FROM_UINT32(x) \
84 : ( (PR_ROTATE_LEFT32((x),16) | 0xFF00FF00) & ((x) | 0xFFFF00FF) )
85 : #endif
86 :
87 : #define GFX_0XFF_PPIXEL_FROM_BPTR(x) \
88 : ( GFX_0XFF_PPIXEL_FROM_UINT32(GFX_UINT32_FROM_BPTR((x),0)) )
89 :
90 : /**
91 : * GFX_BLOCK_RGB_TO_FRGB(from,to)
92 : * sizeof(*from) == sizeof(char)
93 : * sizeof(*to) == sizeof(PRUint32)
94 : *
95 : * Copy 4 pixels at a time, reading blocks of 12 bytes (RGB x4)
96 : * and writing blocks of 16 bytes (FRGB x4)
97 : */
98 : #define GFX_BLOCK_RGB_TO_FRGB(from,to) \
99 : PR_BEGIN_MACRO \
100 : PRUint32 m0 = GFX_UINT32_FROM_BPTR(from,0), \
101 : m1 = GFX_UINT32_FROM_BPTR(from,1), \
102 : m2 = GFX_UINT32_FROM_BPTR(from,2), \
103 : rgbr = GFX_NTOHL(m0), \
104 : gbrg = GFX_NTOHL(m1), \
105 : brgb = GFX_NTOHL(m2), \
106 : p0, p1, p2, p3; \
107 : p0 = 0xFF000000 | ((rgbr) >> 8); \
108 : p1 = 0xFF000000 | ((rgbr) << 16) | ((gbrg) >> 16); \
109 : p2 = 0xFF000000 | ((gbrg) << 8) | ((brgb) >> 24); \
110 : p3 = 0xFF000000 | (brgb); \
111 : to[0] = p0; to[1] = p1; to[2] = p2; to[3] = p3; \
112 : PR_END_MACRO
113 :
114 : /**
115 : * Fast approximate division by 255. It has the property that
116 : * for all 0 <= n <= 255*255, GFX_DIVIDE_BY_255(n) == n/255.
117 : * But it only uses two adds and two shifts instead of an
118 : * integer division (which is expensive on many processors).
119 : *
120 : * equivalent to ((v)/255)
121 : */
122 : #define GFX_DIVIDE_BY_255(v) \
123 : (((((unsigned)(v)) << 8) + ((unsigned)(v)) + 255) >> 16)
124 :
125 : /**
126 : * Fast premultiply macro
127 : *
128 : * equivalent to (((c)*(a))/255)
129 : */
130 : #define GFX_PREMULTIPLY(c,a) GFX_DIVIDE_BY_255((c)*(a))
131 :
132 : /**
133 : * Macro to pack the 4 8-bit channels (A,R,G,B)
134 : * into a 32-bit packed premultiplied pixel.
135 : *
136 : * The checks for 0 alpha or max alpha ensure that the
137 : * compiler selects the quicked calculation when alpha is constant.
138 : */
139 : #define GFX_PACKED_PIXEL(a,r,g,b) \
140 : ((a) == 0x00) ? 0x00000000 : \
141 : ((a) == 0xFF) ? ((0xFF << 24) | ((r) << 16) | ((g) << 8) | (b)) \
142 : : ((a) << 24) | \
143 : (GFX_PREMULTIPLY(r,a) << 16) | \
144 : (GFX_PREMULTIPLY(g,a) << 8) | \
145 : (GFX_PREMULTIPLY(b,a))
146 :
147 : /**
148 : * Macro to pack the 4 8-bit channels (A,R,G,B)
149 : * into a 32-bit packed NON-premultiplied pixel.
150 : */
151 : #define GFX_PACKED_PIXEL_NO_PREMULTIPLY(a,r,g,b) \
152 : (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
153 :
154 :
155 : /**
156 : * A color value, storing red, green, blue and alpha components.
157 : * This class does not use premultiplied alpha.
158 : *
159 : * XXX should this use doubles (instead of gfxFloat), for consistency with
160 : * cairo?
161 : */
162 0 : struct THEBES_API gfxRGBA {
163 : gfxFloat r, g, b, a;
164 :
165 : enum PackedColorType {
166 : PACKED_ABGR,
167 : PACKED_ABGR_PREMULTIPLIED,
168 :
169 : PACKED_ARGB,
170 : PACKED_ARGB_PREMULTIPLIED,
171 :
172 : PACKED_XRGB
173 : };
174 :
175 0 : gfxRGBA() { }
176 : /**
177 : * Intialize this color using explicit red, green, blue and alpha
178 : * values.
179 : */
180 0 : gfxRGBA(gfxFloat _r, gfxFloat _g, gfxFloat _b, gfxFloat _a=1.0) : r(_r), g(_g), b(_b), a(_a) {}
181 :
182 : /**
183 : * Initialize this color from a packed 32-bit color.
184 : * The color value is interpreted based on colorType;
185 : * all values use the native platform endianness.
186 : *
187 : * @see gfxRGBA::Packed
188 : */
189 0 : gfxRGBA(PRUint32 c, PackedColorType colorType = PACKED_ABGR) {
190 0 : if (colorType == PACKED_ABGR ||
191 : colorType == PACKED_ABGR_PREMULTIPLIED)
192 : {
193 0 : r = ((c >> 0) & 0xff) * (1.0 / 255.0);
194 0 : g = ((c >> 8) & 0xff) * (1.0 / 255.0);
195 0 : b = ((c >> 16) & 0xff) * (1.0 / 255.0);
196 0 : a = ((c >> 24) & 0xff) * (1.0 / 255.0);
197 0 : } else if (colorType == PACKED_ARGB ||
198 : colorType == PACKED_XRGB ||
199 : colorType == PACKED_ARGB_PREMULTIPLIED)
200 : {
201 0 : b = ((c >> 0) & 0xff) * (1.0 / 255.0);
202 0 : g = ((c >> 8) & 0xff) * (1.0 / 255.0);
203 0 : r = ((c >> 16) & 0xff) * (1.0 / 255.0);
204 0 : a = ((c >> 24) & 0xff) * (1.0 / 255.0);
205 : }
206 :
207 0 : if (colorType == PACKED_ABGR_PREMULTIPLIED ||
208 : colorType == PACKED_ARGB_PREMULTIPLIED)
209 : {
210 0 : if (a > 0.0) {
211 0 : r /= a;
212 0 : g /= a;
213 0 : b /= a;
214 : }
215 0 : } else if (colorType == PACKED_XRGB) {
216 0 : a = 1.0;
217 : }
218 0 : }
219 :
220 : bool operator==(const gfxRGBA& other) const
221 : {
222 : return r == other.r && g == other.g && b == other.b && a == other.a;
223 : }
224 : bool operator!=(const gfxRGBA& other) const
225 : {
226 : return !(*this == other);
227 : }
228 :
229 : /**
230 : * Returns this color value as a packed 32-bit integer. This reconstructs
231 : * the int32 based on the given colorType, always in the native byte order.
232 : *
233 : * Note: gcc 4.2.3 on at least Ubuntu (x86) does something strange with
234 : * (PRUint8)(c * 255.0) << x, where the result is different than
235 : * double d = c * 255.0; v = ((PRUint8) d) << x.
236 : */
237 0 : PRUint32 Packed(PackedColorType colorType = PACKED_ABGR) const {
238 0 : gfxFloat rb = (r * 255.0);
239 0 : gfxFloat gb = (g * 255.0);
240 0 : gfxFloat bb = (b * 255.0);
241 0 : gfxFloat ab = (a * 255.0);
242 :
243 0 : if (colorType == PACKED_ABGR) {
244 : return (PRUint8(ab) << 24) |
245 : (PRUint8(bb) << 16) |
246 : (PRUint8(gb) << 8) |
247 0 : (PRUint8(rb) << 0);
248 : }
249 0 : if (colorType == PACKED_ARGB || colorType == PACKED_XRGB) {
250 : return (PRUint8(ab) << 24) |
251 : (PRUint8(rb) << 16) |
252 : (PRUint8(gb) << 8) |
253 0 : (PRUint8(bb) << 0);
254 : }
255 :
256 0 : rb *= a;
257 0 : gb *= a;
258 0 : bb *= a;
259 :
260 0 : if (colorType == PACKED_ABGR_PREMULTIPLIED) {
261 : return (((PRUint8)(ab) << 24) |
262 : ((PRUint8)(bb) << 16) |
263 : ((PRUint8)(gb) << 8) |
264 0 : ((PRUint8)(rb) << 0));
265 : }
266 0 : if (colorType == PACKED_ARGB_PREMULTIPLIED) {
267 : return (((PRUint8)(ab) << 24) |
268 : ((PRUint8)(rb) << 16) |
269 : ((PRUint8)(gb) << 8) |
270 0 : ((PRUint8)(bb) << 0));
271 : }
272 :
273 0 : return 0;
274 : }
275 : };
276 :
277 : #endif /* _GFX_COLOR_H */
|