|
1 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
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/. */ |
|
5 |
|
6 #include "LayerUtils.h" |
|
7 #include "PremultiplyTables.h" |
|
8 #include "mozilla/Endian.h" |
|
9 |
|
10 namespace mozilla { |
|
11 namespace layers { |
|
12 |
|
13 using namespace mozilla::gfx; |
|
14 |
|
15 static inline const uint8_t PremultiplyValue(uint8_t a, uint8_t v) { |
|
16 return PremultiplyTable[a*256+v]; |
|
17 } |
|
18 |
|
19 static inline const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) { |
|
20 return UnpremultiplyTable[a*256+v]; |
|
21 } |
|
22 |
|
23 #ifdef DEBUG |
|
24 static bool IsLittleEndian() |
|
25 { |
|
26 // Violate strict aliasing, because violating strict aliasing is how |
|
27 // we always pack and unpack between uint32_t and uint8_t[]. |
|
28 uint16_t testShort; |
|
29 static const uint8_t testBytes[2] = { 0xAA, 0xBB }; |
|
30 memcpy(&testShort, testBytes, sizeof(testBytes)); |
|
31 return testShort == 0xBBAA; |
|
32 } |
|
33 #endif // DEBUG |
|
34 |
|
35 #ifdef MOZ_LITTLE_ENDIAN |
|
36 #define ASSERT_ENDIAN() MOZ_ASSERT(IsLittleEndian(), "Defined as little endian, but actually big!") |
|
37 #else |
|
38 #define ASSERT_ENDIAN() MOZ_ASSERT(!IsLittleEndian(), "Defined as big endian, but actually little!") |
|
39 #endif |
|
40 |
|
41 void |
|
42 PremultiplySurface(DataSourceSurface* srcSurface, |
|
43 DataSourceSurface* destSurface) |
|
44 { |
|
45 if (!destSurface) |
|
46 destSurface = srcSurface; |
|
47 |
|
48 IntSize srcSize = srcSurface->GetSize(); |
|
49 MOZ_ASSERT(srcSurface->GetFormat() == destSurface->GetFormat() && |
|
50 srcSize.width == destSurface->GetSize().width && |
|
51 srcSize.height == destSurface->GetSize().height && |
|
52 srcSurface->Stride() == destSurface->Stride(), |
|
53 "Source and destination surfaces don't have identical characteristics"); |
|
54 |
|
55 MOZ_ASSERT(srcSurface->Stride() == srcSize.width * 4, |
|
56 "Source surface stride isn't tightly packed"); |
|
57 |
|
58 // Only premultiply ARGB32 |
|
59 if (srcSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { |
|
60 if (destSurface != srcSurface) { |
|
61 memcpy(destSurface->GetData(), srcSurface->GetData(), |
|
62 srcSurface->Stride() * srcSize.height); |
|
63 } |
|
64 return; |
|
65 } |
|
66 |
|
67 uint8_t *src = srcSurface->GetData(); |
|
68 uint8_t *dst = destSurface->GetData(); |
|
69 |
|
70 // Assert that our endian define is correct. |
|
71 ASSERT_ENDIAN(); |
|
72 |
|
73 uint32_t dim = srcSize.width * srcSize.height; |
|
74 for (uint32_t i = 0; i < dim; ++i) { |
|
75 #ifdef MOZ_LITTLE_ENDIAN |
|
76 uint8_t b = *src++; |
|
77 uint8_t g = *src++; |
|
78 uint8_t r = *src++; |
|
79 uint8_t a = *src++; |
|
80 |
|
81 *dst++ = PremultiplyValue(a, b); |
|
82 *dst++ = PremultiplyValue(a, g); |
|
83 *dst++ = PremultiplyValue(a, r); |
|
84 *dst++ = a; |
|
85 #else |
|
86 uint8_t a = *src++; |
|
87 uint8_t r = *src++; |
|
88 uint8_t g = *src++; |
|
89 uint8_t b = *src++; |
|
90 |
|
91 *dst++ = a; |
|
92 *dst++ = PremultiplyValue(a, r); |
|
93 *dst++ = PremultiplyValue(a, g); |
|
94 *dst++ = PremultiplyValue(a, b); |
|
95 #endif |
|
96 } |
|
97 } |
|
98 |
|
99 |
|
100 } |
|
101 } |