1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxColor.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,227 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_COLOR_H 1.10 +#define GFX_COLOR_H 1.11 + 1.12 +#include "gfxTypes.h" 1.13 + 1.14 +#include "mozilla/Attributes.h" // for MOZ_ALWAYS_INLINE 1.15 +#include "mozilla/Endian.h" // for mozilla::NativeEndian::swapToBigEndian 1.16 + 1.17 +#define GFX_UINT32_FROM_BPTR(pbptr,i) (((uint32_t*)(pbptr))[i]) 1.18 + 1.19 +/** 1.20 + * GFX_0XFF_PPIXEL_FROM_BPTR(x) 1.21 + * 1.22 + * Avoid tortured construction of 32-bit ARGB pixel from 3 individual bytes 1.23 + * of memory plus constant 0xFF. RGB bytes are already contiguous! 1.24 + * Equivalent to: GFX_PACKED_PIXEL(0xff,r,g,b) 1.25 + * 1.26 + * Attempt to use fast byte-swapping instruction(s), e.g. bswap on x86, in 1.27 + * preference to a sequence of shift/or operations. 1.28 + */ 1.29 +#define GFX_0XFF_PPIXEL_FROM_UINT32(x) \ 1.30 + ( (mozilla::NativeEndian::swapToBigEndian(uint32_t(x)) >> 8) | (0xFFU << 24) ) 1.31 + 1.32 +#define GFX_0XFF_PPIXEL_FROM_BPTR(x) \ 1.33 + ( GFX_0XFF_PPIXEL_FROM_UINT32(GFX_UINT32_FROM_BPTR((x),0)) ) 1.34 + 1.35 +/** 1.36 + * GFX_BLOCK_RGB_TO_FRGB(from,to) 1.37 + * sizeof(*from) == sizeof(char) 1.38 + * sizeof(*to) == sizeof(uint32_t) 1.39 + * 1.40 + * Copy 4 pixels at a time, reading blocks of 12 bytes (RGB x4) 1.41 + * and writing blocks of 16 bytes (FRGB x4) 1.42 + */ 1.43 +#define GFX_BLOCK_RGB_TO_FRGB(from,to) \ 1.44 + PR_BEGIN_MACRO \ 1.45 + uint32_t m0 = GFX_UINT32_FROM_BPTR(from,0), \ 1.46 + m1 = GFX_UINT32_FROM_BPTR(from,1), \ 1.47 + m2 = GFX_UINT32_FROM_BPTR(from,2), \ 1.48 + rgbr = mozilla::NativeEndian::swapToBigEndian(m0), \ 1.49 + gbrg = mozilla::NativeEndian::swapToBigEndian(m1), \ 1.50 + brgb = mozilla::NativeEndian::swapToBigEndian(m2), \ 1.51 + p0, p1, p2, p3; \ 1.52 + p0 = 0xFF000000 | ((rgbr) >> 8); \ 1.53 + p1 = 0xFF000000 | ((rgbr) << 16) | ((gbrg) >> 16); \ 1.54 + p2 = 0xFF000000 | ((gbrg) << 8) | ((brgb) >> 24); \ 1.55 + p3 = 0xFF000000 | (brgb); \ 1.56 + to[0] = p0; to[1] = p1; to[2] = p2; to[3] = p3; \ 1.57 + PR_END_MACRO 1.58 + 1.59 +/** 1.60 + * Fast approximate division by 255. It has the property that 1.61 + * for all 0 <= n <= 255*255, GFX_DIVIDE_BY_255(n) == n/255. 1.62 + * But it only uses two adds and two shifts instead of an 1.63 + * integer division (which is expensive on many processors). 1.64 + * 1.65 + * equivalent to ((v)/255) 1.66 + */ 1.67 +#define GFX_DIVIDE_BY_255(v) \ 1.68 + (((((unsigned)(v)) << 8) + ((unsigned)(v)) + 255) >> 16) 1.69 + 1.70 +/** 1.71 + * Fast premultiply 1.72 + * 1.73 + * equivalent to (((c)*(a))/255) 1.74 + */ 1.75 +uint8_t MOZ_ALWAYS_INLINE gfxPreMultiply(uint8_t c, uint8_t a) { 1.76 + return GFX_DIVIDE_BY_255((c)*(a)); 1.77 +} 1.78 + 1.79 +/** 1.80 + * Pack the 4 8-bit channels (A,R,G,B) 1.81 + * into a 32-bit packed NON-premultiplied pixel. 1.82 + */ 1.83 +uint32_t MOZ_ALWAYS_INLINE 1.84 +gfxPackedPixelNoPreMultiply(uint8_t a, uint8_t r, uint8_t g, uint8_t b) { 1.85 + return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)); 1.86 +} 1.87 + 1.88 +/** 1.89 + * Pack the 4 8-bit channels (A,R,G,B) 1.90 + * into a 32-bit packed premultiplied pixel. 1.91 + */ 1.92 +uint32_t MOZ_ALWAYS_INLINE 1.93 +gfxPackedPixel(uint8_t a, uint8_t r, uint8_t g, uint8_t b) { 1.94 + if (a == 0x00) 1.95 + return 0x00000000; 1.96 + else if (a == 0xFF) { 1.97 + return gfxPackedPixelNoPreMultiply(a, r, g, b); 1.98 + } else { 1.99 + return ((a) << 24) | 1.100 + (gfxPreMultiply(r,a) << 16) | 1.101 + (gfxPreMultiply(g,a) << 8) | 1.102 + (gfxPreMultiply(b,a)); 1.103 + } 1.104 +} 1.105 + 1.106 +/** 1.107 + * A color value, storing red, green, blue and alpha components. 1.108 + * This class does not use premultiplied alpha. 1.109 + * 1.110 + * XXX should this use doubles (instead of gfxFloat), for consistency with 1.111 + * cairo? 1.112 + */ 1.113 +struct gfxRGBA { 1.114 + gfxFloat r, g, b, a; 1.115 + 1.116 + enum PackedColorType { 1.117 + PACKED_ABGR, 1.118 + PACKED_ABGR_PREMULTIPLIED, 1.119 + 1.120 + PACKED_ARGB, 1.121 + PACKED_ARGB_PREMULTIPLIED, 1.122 + 1.123 + PACKED_XRGB 1.124 + }; 1.125 + 1.126 + gfxRGBA() { } 1.127 + /** 1.128 + * Intialize this color using explicit red, green, blue and alpha 1.129 + * values. 1.130 + */ 1.131 + MOZ_CONSTEXPR gfxRGBA(gfxFloat _r, gfxFloat _g, gfxFloat _b, gfxFloat _a=1.0) : r(_r), g(_g), b(_b), a(_a) {} 1.132 + 1.133 + /** 1.134 + * Initialize this color from a packed 32-bit color. 1.135 + * The color value is interpreted based on colorType; 1.136 + * all values use the native platform endianness. 1.137 + * 1.138 + * Resulting gfxRGBA stores non-premultiplied data. 1.139 + * 1.140 + * @see gfxRGBA::Packed 1.141 + */ 1.142 + gfxRGBA(uint32_t c, PackedColorType colorType = PACKED_ABGR) { 1.143 + if (colorType == PACKED_ABGR || 1.144 + colorType == PACKED_ABGR_PREMULTIPLIED) 1.145 + { 1.146 + r = ((c >> 0) & 0xff) * (1.0 / 255.0); 1.147 + g = ((c >> 8) & 0xff) * (1.0 / 255.0); 1.148 + b = ((c >> 16) & 0xff) * (1.0 / 255.0); 1.149 + a = ((c >> 24) & 0xff) * (1.0 / 255.0); 1.150 + } else if (colorType == PACKED_ARGB || 1.151 + colorType == PACKED_XRGB || 1.152 + colorType == PACKED_ARGB_PREMULTIPLIED) 1.153 + { 1.154 + b = ((c >> 0) & 0xff) * (1.0 / 255.0); 1.155 + g = ((c >> 8) & 0xff) * (1.0 / 255.0); 1.156 + r = ((c >> 16) & 0xff) * (1.0 / 255.0); 1.157 + a = ((c >> 24) & 0xff) * (1.0 / 255.0); 1.158 + } 1.159 + 1.160 + if (colorType == PACKED_ABGR_PREMULTIPLIED || 1.161 + colorType == PACKED_ARGB_PREMULTIPLIED) 1.162 + { 1.163 + if (a > 0.0) { 1.164 + r /= a; 1.165 + g /= a; 1.166 + b /= a; 1.167 + } 1.168 + } else if (colorType == PACKED_XRGB) { 1.169 + a = 1.0; 1.170 + } 1.171 + } 1.172 + 1.173 + bool operator==(const gfxRGBA& other) const 1.174 + { 1.175 + return r == other.r && g == other.g && b == other.b && a == other.a; 1.176 + } 1.177 + bool operator!=(const gfxRGBA& other) const 1.178 + { 1.179 + return !(*this == other); 1.180 + } 1.181 + 1.182 + /** 1.183 + * Returns this color value as a packed 32-bit integer. This reconstructs 1.184 + * the int32_t based on the given colorType, always in the native byte order. 1.185 + * 1.186 + * Note: gcc 4.2.3 on at least Ubuntu (x86) does something strange with 1.187 + * (uint8_t)(c * 255.0) << x, where the result is different than 1.188 + * double d = c * 255.0; v = ((uint8_t) d) << x. 1.189 + */ 1.190 + uint32_t Packed(PackedColorType colorType = PACKED_ABGR) const { 1.191 + gfxFloat rb = (r * 255.0); 1.192 + gfxFloat gb = (g * 255.0); 1.193 + gfxFloat bb = (b * 255.0); 1.194 + gfxFloat ab = (a * 255.0); 1.195 + 1.196 + if (colorType == PACKED_ABGR) { 1.197 + return (uint8_t(ab) << 24) | 1.198 + (uint8_t(bb) << 16) | 1.199 + (uint8_t(gb) << 8) | 1.200 + (uint8_t(rb) << 0); 1.201 + } 1.202 + if (colorType == PACKED_ARGB || colorType == PACKED_XRGB) { 1.203 + return (uint8_t(ab) << 24) | 1.204 + (uint8_t(rb) << 16) | 1.205 + (uint8_t(gb) << 8) | 1.206 + (uint8_t(bb) << 0); 1.207 + } 1.208 + 1.209 + rb *= a; 1.210 + gb *= a; 1.211 + bb *= a; 1.212 + 1.213 + if (colorType == PACKED_ABGR_PREMULTIPLIED) { 1.214 + return (((uint8_t)(ab) << 24) | 1.215 + ((uint8_t)(bb) << 16) | 1.216 + ((uint8_t)(gb) << 8) | 1.217 + ((uint8_t)(rb) << 0)); 1.218 + } 1.219 + if (colorType == PACKED_ARGB_PREMULTIPLIED) { 1.220 + return (((uint8_t)(ab) << 24) | 1.221 + ((uint8_t)(rb) << 16) | 1.222 + ((uint8_t)(gb) << 8) | 1.223 + ((uint8_t)(bb) << 0)); 1.224 + } 1.225 + 1.226 + return 0; 1.227 + } 1.228 +}; 1.229 + 1.230 +#endif /* _GFX_COLOR_H */