DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (5b81998bb7ab)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef GFX_COLOR_H
#define GFX_COLOR_H

#include "gfxTypes.h"

#include "prbit.h" // for PR_ROTATE_(LEFT,RIGHT)32
#include "prio.h"  // for ntohl

#define GFX_UINT32_FROM_BPTR(pbptr,i) (((uint32_t*)(pbptr))[i])

#if defined(IS_BIG_ENDIAN)
  #define GFX_NTOHL(x) (x)
  #define GFX_HAVE_CHEAP_NTOHL
#elif defined(_WIN32)
  #if (_MSC_VER >= 1300) // also excludes MinGW
    #include <stdlib.h>
    #pragma intrinsic(_byteswap_ulong)
    #define GFX_NTOHL(x) _byteswap_ulong(x)
    #define GFX_HAVE_CHEAP_NTOHL
  #else
    // A reasonably fast generic little-endian implementation.
    #define GFX_NTOHL(x) \
         ( (PR_ROTATE_RIGHT32((x),8) & 0xFF00FF00) | \
           (PR_ROTATE_LEFT32((x),8)  & 0x00FF00FF) )
  #endif
#else
  #define GFX_NTOHL(x) ntohl(x)
  #define GFX_HAVE_CHEAP_NTOHL
#endif

/**
 * GFX_0XFF_PPIXEL_FROM_BPTR(x)
 *
 * Avoid tortured construction of 32-bit ARGB pixel from 3 individual bytes
 *   of memory plus constant 0xFF.  RGB bytes are already contiguous!
 * Equivalent to: GFX_PACKED_PIXEL(0xff,r,g,b)
 *
 * Attempt to use fast byte-swapping instruction(s), e.g. bswap on x86, in
 *   preference to a sequence of shift/or operations.
 */
#if defined(GFX_HAVE_CHEAP_NTOHL)
  #define GFX_0XFF_PPIXEL_FROM_UINT32(x) \
       ( (GFX_NTOHL(x) >> 8) | (0xFF << 24) )
#else
  // A reasonably fast generic little-endian implementation.
  #define GFX_0XFF_PPIXEL_FROM_UINT32(x) \
       ( (PR_ROTATE_LEFT32((x),16) | 0xFF00FF00) & ((x) | 0xFFFF00FF) )
#endif

#define GFX_0XFF_PPIXEL_FROM_BPTR(x) \
     ( GFX_0XFF_PPIXEL_FROM_UINT32(GFX_UINT32_FROM_BPTR((x),0)) )

/**
 * GFX_BLOCK_RGB_TO_FRGB(from,to)
 *   sizeof(*from) == sizeof(char)
 *   sizeof(*to)   == sizeof(uint32_t)
 *
 * Copy 4 pixels at a time, reading blocks of 12 bytes (RGB x4)
 *   and writing blocks of 16 bytes (FRGB x4)
 */
#define GFX_BLOCK_RGB_TO_FRGB(from,to) \
  PR_BEGIN_MACRO \
    uint32_t m0 = GFX_UINT32_FROM_BPTR(from,0), \
             m1 = GFX_UINT32_FROM_BPTR(from,1), \
             m2 = GFX_UINT32_FROM_BPTR(from,2), \
             rgbr = GFX_NTOHL(m0), \
             gbrg = GFX_NTOHL(m1), \
             brgb = GFX_NTOHL(m2), \
             p0, p1, p2, p3; \
    p0 = 0xFF000000 | ((rgbr) >>  8); \
    p1 = 0xFF000000 | ((rgbr) << 16) | ((gbrg) >> 16); \
    p2 = 0xFF000000 | ((gbrg) <<  8) | ((brgb) >> 24); \
    p3 = 0xFF000000 | (brgb); \
    to[0] = p0; to[1] = p1; to[2] = p2; to[3] = p3; \
  PR_END_MACRO

/**
 * Fast approximate division by 255. It has the property that
 * for all 0 <= n <= 255*255, GFX_DIVIDE_BY_255(n) == n/255.
 * But it only uses two adds and two shifts instead of an
 * integer division (which is expensive on many processors).
 *
 * equivalent to ((v)/255)
 */
#define GFX_DIVIDE_BY_255(v)  \
     (((((unsigned)(v)) << 8) + ((unsigned)(v)) + 255) >> 16)

/**
 * Fast premultiply macro
 *
 * equivalent to (((c)*(a))/255)
 */
#define GFX_PREMULTIPLY(c,a) GFX_DIVIDE_BY_255((c)*(a))

/** 
 * Macro to pack the 4 8-bit channels (A,R,G,B) 
 * into a 32-bit packed premultiplied pixel.
 *
 * The checks for 0 alpha or max alpha ensure that the
 * compiler selects the quicked calculation when alpha is constant.
 */
#define GFX_PACKED_PIXEL(a,r,g,b)                                       \
    ((a) == 0x00) ? 0x00000000 :                                        \
    ((a) == 0xFF) ? ((0xFF << 24) | ((r) << 16) | ((g) << 8) | (b))     \
                  : ((a) << 24) |                                       \
                    (GFX_PREMULTIPLY(r,a) << 16) |                      \
                    (GFX_PREMULTIPLY(g,a) << 8) |                       \
                    (GFX_PREMULTIPLY(b,a))

/** 
 * Macro to pack the 4 8-bit channels (A,R,G,B) 
 * into a 32-bit packed NON-premultiplied pixel.
 */
#define GFX_PACKED_PIXEL_NO_PREMULTIPLY(a,r,g,b)                        \
    (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))


/**
 * A color value, storing red, green, blue and alpha components.
 * This class does not use premultiplied alpha.
 *
 * XXX should this use doubles (instead of gfxFloat), for consistency with
 * cairo?
 */
struct THEBES_API gfxRGBA {
    gfxFloat r, g, b, a;

    enum PackedColorType {
        PACKED_ABGR,
        PACKED_ABGR_PREMULTIPLIED,

        PACKED_ARGB,
        PACKED_ARGB_PREMULTIPLIED,

        PACKED_XRGB
    };

    gfxRGBA() { }
    /**
     * Intialize this color using explicit red, green, blue and alpha
     * values.
     */
    gfxRGBA(gfxFloat _r, gfxFloat _g, gfxFloat _b, gfxFloat _a=1.0) : r(_r), g(_g), b(_b), a(_a) {}

    /**
     * Initialize this color from a packed 32-bit color.
     * The color value is interpreted based on colorType;
     * all values use the native platform endianness.
     *
     * Resulting gfxRGBA stores non-premultiplied data.
     *
     * @see gfxRGBA::Packed
     */
    gfxRGBA(uint32_t c, PackedColorType colorType = PACKED_ABGR) {
        if (colorType == PACKED_ABGR ||
            colorType == PACKED_ABGR_PREMULTIPLIED)
        {
            r = ((c >> 0) & 0xff) * (1.0 / 255.0);
            g = ((c >> 8) & 0xff) * (1.0 / 255.0);
            b = ((c >> 16) & 0xff) * (1.0 / 255.0);
            a = ((c >> 24) & 0xff) * (1.0 / 255.0);
        } else if (colorType == PACKED_ARGB ||
                   colorType == PACKED_XRGB ||
                   colorType == PACKED_ARGB_PREMULTIPLIED)
        {
            b = ((c >> 0) & 0xff) * (1.0 / 255.0);
            g = ((c >> 8) & 0xff) * (1.0 / 255.0);
            r = ((c >> 16) & 0xff) * (1.0 / 255.0);
            a = ((c >> 24) & 0xff) * (1.0 / 255.0);
        }

        if (colorType == PACKED_ABGR_PREMULTIPLIED ||
            colorType == PACKED_ARGB_PREMULTIPLIED)
        {
            if (a > 0.0) {
                r /= a;
                g /= a;
                b /= a;
            }
        } else if (colorType == PACKED_XRGB) {
            a = 1.0;
        }
    }

    bool operator==(const gfxRGBA& other) const
    {
        return r == other.r && g == other.g && b == other.b && a == other.a;
    }
    bool operator!=(const gfxRGBA& other) const
    {
        return !(*this == other);
    }

    /**
     * Returns this color value as a packed 32-bit integer. This reconstructs
     * the int32 based on the given colorType, always in the native byte order.
     *
     * Note: gcc 4.2.3 on at least Ubuntu (x86) does something strange with
     * (uint8_t)(c * 255.0) << x, where the result is different than
     * double d = c * 255.0; v = ((uint8_t) d) << x. 
     */
    uint32_t Packed(PackedColorType colorType = PACKED_ABGR) const {
        gfxFloat rb = (r * 255.0);
        gfxFloat gb = (g * 255.0);
        gfxFloat bb = (b * 255.0);
        gfxFloat ab = (a * 255.0);

        if (colorType == PACKED_ABGR) {
            return (uint8_t(ab) << 24) |
                   (uint8_t(bb) << 16) |
                   (uint8_t(gb) << 8) |
                   (uint8_t(rb) << 0);
        }
        if (colorType == PACKED_ARGB || colorType == PACKED_XRGB) {
            return (uint8_t(ab) << 24) |
                   (uint8_t(rb) << 16) |
                   (uint8_t(gb) << 8) |
                   (uint8_t(bb) << 0);
        }

        rb *= a;
        gb *= a;
        bb *= a;

        if (colorType == PACKED_ABGR_PREMULTIPLIED) {
            return (((uint8_t)(ab) << 24) |
                    ((uint8_t)(bb) << 16) |
                    ((uint8_t)(gb) << 8) |
                    ((uint8_t)(rb) << 0));
        }
        if (colorType == PACKED_ARGB_PREMULTIPLIED) {
            return (((uint8_t)(ab) << 24) |
                    ((uint8_t)(rb) << 16) |
                    ((uint8_t)(gb) << 8) |
                    ((uint8_t)(bb) << 0));
        }

        return 0;
    }
};

#endif /* _GFX_COLOR_H */