gfx/thebes/gfxColor.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef GFX_COLOR_H
     7 #define GFX_COLOR_H
     9 #include "gfxTypes.h"
    11 #include "mozilla/Attributes.h" // for MOZ_ALWAYS_INLINE
    12 #include "mozilla/Endian.h" // for mozilla::NativeEndian::swapToBigEndian
    14 #define GFX_UINT32_FROM_BPTR(pbptr,i) (((uint32_t*)(pbptr))[i])
    16 /**
    17  * GFX_0XFF_PPIXEL_FROM_BPTR(x)
    18  *
    19  * Avoid tortured construction of 32-bit ARGB pixel from 3 individual bytes
    20  *   of memory plus constant 0xFF.  RGB bytes are already contiguous!
    21  * Equivalent to: GFX_PACKED_PIXEL(0xff,r,g,b)
    22  *
    23  * Attempt to use fast byte-swapping instruction(s), e.g. bswap on x86, in
    24  *   preference to a sequence of shift/or operations.
    25  */
    26 #define GFX_0XFF_PPIXEL_FROM_UINT32(x) \
    27   ( (mozilla::NativeEndian::swapToBigEndian(uint32_t(x)) >> 8) | (0xFFU << 24) )
    29 #define GFX_0XFF_PPIXEL_FROM_BPTR(x) \
    30      ( GFX_0XFF_PPIXEL_FROM_UINT32(GFX_UINT32_FROM_BPTR((x),0)) )
    32 /**
    33  * GFX_BLOCK_RGB_TO_FRGB(from,to)
    34  *   sizeof(*from) == sizeof(char)
    35  *   sizeof(*to)   == sizeof(uint32_t)
    36  *
    37  * Copy 4 pixels at a time, reading blocks of 12 bytes (RGB x4)
    38  *   and writing blocks of 16 bytes (FRGB x4)
    39  */
    40 #define GFX_BLOCK_RGB_TO_FRGB(from,to) \
    41   PR_BEGIN_MACRO \
    42     uint32_t m0 = GFX_UINT32_FROM_BPTR(from,0), \
    43              m1 = GFX_UINT32_FROM_BPTR(from,1), \
    44              m2 = GFX_UINT32_FROM_BPTR(from,2), \
    45              rgbr = mozilla::NativeEndian::swapToBigEndian(m0), \
    46              gbrg = mozilla::NativeEndian::swapToBigEndian(m1), \
    47              brgb = mozilla::NativeEndian::swapToBigEndian(m2), \
    48              p0, p1, p2, p3; \
    49     p0 = 0xFF000000 | ((rgbr) >>  8); \
    50     p1 = 0xFF000000 | ((rgbr) << 16) | ((gbrg) >> 16); \
    51     p2 = 0xFF000000 | ((gbrg) <<  8) | ((brgb) >> 24); \
    52     p3 = 0xFF000000 | (brgb); \
    53     to[0] = p0; to[1] = p1; to[2] = p2; to[3] = p3; \
    54   PR_END_MACRO
    56 /**
    57  * Fast approximate division by 255. It has the property that
    58  * for all 0 <= n <= 255*255, GFX_DIVIDE_BY_255(n) == n/255.
    59  * But it only uses two adds and two shifts instead of an
    60  * integer division (which is expensive on many processors).
    61  *
    62  * equivalent to ((v)/255)
    63  */
    64 #define GFX_DIVIDE_BY_255(v)  \
    65      (((((unsigned)(v)) << 8) + ((unsigned)(v)) + 255) >> 16)
    67 /**
    68  * Fast premultiply
    69  *
    70  * equivalent to (((c)*(a))/255)
    71  */
    72 uint8_t MOZ_ALWAYS_INLINE gfxPreMultiply(uint8_t c, uint8_t a) {
    73     return GFX_DIVIDE_BY_255((c)*(a));
    74 }
    76 /**
    77  * Pack the 4 8-bit channels (A,R,G,B)
    78  * into a 32-bit packed NON-premultiplied pixel.
    79  */
    80 uint32_t MOZ_ALWAYS_INLINE
    81 gfxPackedPixelNoPreMultiply(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
    82     return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
    83 }
    85 /**
    86  * Pack the 4 8-bit channels (A,R,G,B)
    87  * into a 32-bit packed premultiplied pixel.
    88  */
    89 uint32_t MOZ_ALWAYS_INLINE
    90 gfxPackedPixel(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
    91     if (a == 0x00)
    92         return 0x00000000;
    93     else if (a == 0xFF) {
    94         return gfxPackedPixelNoPreMultiply(a, r, g, b);
    95     } else {
    96         return  ((a) << 24) |
    97                 (gfxPreMultiply(r,a) << 16) |
    98                 (gfxPreMultiply(g,a) << 8)  |
    99                 (gfxPreMultiply(b,a));
   100     }
   101 }
   103 /**
   104  * A color value, storing red, green, blue and alpha components.
   105  * This class does not use premultiplied alpha.
   106  *
   107  * XXX should this use doubles (instead of gfxFloat), for consistency with
   108  * cairo?
   109  */
   110 struct gfxRGBA {
   111     gfxFloat r, g, b, a;
   113     enum PackedColorType {
   114         PACKED_ABGR,
   115         PACKED_ABGR_PREMULTIPLIED,
   117         PACKED_ARGB,
   118         PACKED_ARGB_PREMULTIPLIED,
   120         PACKED_XRGB
   121     };
   123     gfxRGBA() { }
   124     /**
   125      * Intialize this color using explicit red, green, blue and alpha
   126      * values.
   127      */
   128     MOZ_CONSTEXPR gfxRGBA(gfxFloat _r, gfxFloat _g, gfxFloat _b, gfxFloat _a=1.0) : r(_r), g(_g), b(_b), a(_a) {}
   130     /**
   131      * Initialize this color from a packed 32-bit color.
   132      * The color value is interpreted based on colorType;
   133      * all values use the native platform endianness.
   134      *
   135      * Resulting gfxRGBA stores non-premultiplied data.
   136      *
   137      * @see gfxRGBA::Packed
   138      */
   139     gfxRGBA(uint32_t c, PackedColorType colorType = PACKED_ABGR) {
   140         if (colorType == PACKED_ABGR ||
   141             colorType == PACKED_ABGR_PREMULTIPLIED)
   142         {
   143             r = ((c >> 0) & 0xff) * (1.0 / 255.0);
   144             g = ((c >> 8) & 0xff) * (1.0 / 255.0);
   145             b = ((c >> 16) & 0xff) * (1.0 / 255.0);
   146             a = ((c >> 24) & 0xff) * (1.0 / 255.0);
   147         } else if (colorType == PACKED_ARGB ||
   148                    colorType == PACKED_XRGB ||
   149                    colorType == PACKED_ARGB_PREMULTIPLIED)
   150         {
   151             b = ((c >> 0) & 0xff) * (1.0 / 255.0);
   152             g = ((c >> 8) & 0xff) * (1.0 / 255.0);
   153             r = ((c >> 16) & 0xff) * (1.0 / 255.0);
   154             a = ((c >> 24) & 0xff) * (1.0 / 255.0);
   155         }
   157         if (colorType == PACKED_ABGR_PREMULTIPLIED ||
   158             colorType == PACKED_ARGB_PREMULTIPLIED)
   159         {
   160             if (a > 0.0) {
   161                 r /= a;
   162                 g /= a;
   163                 b /= a;
   164             }
   165         } else if (colorType == PACKED_XRGB) {
   166             a = 1.0;
   167         }
   168     }
   170     bool operator==(const gfxRGBA& other) const
   171     {
   172         return r == other.r && g == other.g && b == other.b && a == other.a;
   173     }
   174     bool operator!=(const gfxRGBA& other) const
   175     {
   176         return !(*this == other);
   177     }
   179     /**
   180      * Returns this color value as a packed 32-bit integer. This reconstructs
   181      * the int32_t based on the given colorType, always in the native byte order.
   182      *
   183      * Note: gcc 4.2.3 on at least Ubuntu (x86) does something strange with
   184      * (uint8_t)(c * 255.0) << x, where the result is different than
   185      * double d = c * 255.0; v = ((uint8_t) d) << x. 
   186      */
   187     uint32_t Packed(PackedColorType colorType = PACKED_ABGR) const {
   188         gfxFloat rb = (r * 255.0);
   189         gfxFloat gb = (g * 255.0);
   190         gfxFloat bb = (b * 255.0);
   191         gfxFloat ab = (a * 255.0);
   193         if (colorType == PACKED_ABGR) {
   194             return (uint8_t(ab) << 24) |
   195                    (uint8_t(bb) << 16) |
   196                    (uint8_t(gb) << 8) |
   197                    (uint8_t(rb) << 0);
   198         }
   199         if (colorType == PACKED_ARGB || colorType == PACKED_XRGB) {
   200             return (uint8_t(ab) << 24) |
   201                    (uint8_t(rb) << 16) |
   202                    (uint8_t(gb) << 8) |
   203                    (uint8_t(bb) << 0);
   204         }
   206         rb *= a;
   207         gb *= a;
   208         bb *= a;
   210         if (colorType == PACKED_ABGR_PREMULTIPLIED) {
   211             return (((uint8_t)(ab) << 24) |
   212                     ((uint8_t)(bb) << 16) |
   213                     ((uint8_t)(gb) << 8) |
   214                     ((uint8_t)(rb) << 0));
   215         }
   216         if (colorType == PACKED_ARGB_PREMULTIPLIED) {
   217             return (((uint8_t)(ab) << 24) |
   218                     ((uint8_t)(rb) << 16) |
   219                     ((uint8_t)(gb) << 8) |
   220                     ((uint8_t)(bb) << 0));
   221         }
   223         return 0;
   224     }
   225 };
   227 #endif /* _GFX_COLOR_H */

mercurial