/src/mozilla-central/gfx/thebes/gfxAlphaRecovery.h
Line | Count | Source (jump to first uncovered line) |
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/. */ |
5 | | |
6 | | #ifndef _GFXALPHARECOVERY_H_ |
7 | | #define _GFXALPHARECOVERY_H_ |
8 | | |
9 | | #include "mozilla/SSE.h" |
10 | | #include "gfxTypes.h" |
11 | | #include "mozilla/gfx/Rect.h" |
12 | | |
13 | | class gfxImageSurface; |
14 | | |
15 | | class gfxAlphaRecovery { |
16 | | public: |
17 | | /** |
18 | | * Some SIMD fast-paths only can be taken if the relative |
19 | | * byte-alignment of images' pointers and strides meets certain |
20 | | * criteria. Aligning image pointers and strides by |
21 | | * |GoodAlignmentLog2()| below will ensure that fast-paths aren't |
22 | | * skipped because of misalignment. Fast-paths may still be taken |
23 | | * even if GoodAlignmentLog2() is not met, in some conditions. |
24 | | */ |
25 | | static uint32_t GoodAlignmentLog2() { return 4; /* for SSE2 */ } |
26 | | |
27 | | /* Given two surfaces of equal size with the same rendering, one onto a |
28 | | * black background and the other onto white, recovers alpha values from |
29 | | * the difference and sets the alpha values on the black surface. |
30 | | * The surfaces must have format RGB24 or ARGB32. |
31 | | * Returns true on success. |
32 | | */ |
33 | | static bool RecoverAlpha (gfxImageSurface *blackSurface, |
34 | | const gfxImageSurface *whiteSurface); |
35 | | |
36 | | #ifdef MOZILLA_MAY_SUPPORT_SSE2 |
37 | | /* This does the same as the previous function, but uses SSE2 |
38 | | * optimizations. Usually this should not be called directly. Be sure to |
39 | | * check mozilla::supports_sse2() before calling this function. |
40 | | */ |
41 | | static bool RecoverAlphaSSE2 (gfxImageSurface *blackSurface, |
42 | | const gfxImageSurface *whiteSurface); |
43 | | |
44 | | /** |
45 | | * A common use-case for alpha recovery is to paint into a |
46 | | * temporary "white image", then paint onto a subrect of the |
47 | | * surface, the "black image", into which alpha-recovered pixels |
48 | | * are eventually to be written. This function returns a rect |
49 | | * aligned so that recovering alpha for that rect will hit SIMD |
50 | | * fast-paths, if possible. It's not always possible to align |
51 | | * |aRect| so that fast-paths will be taken. |
52 | | * |
53 | | * The returned rect is always a superset of |aRect|. |
54 | | */ |
55 | | static mozilla::gfx::IntRect AlignRectForSubimageRecovery(const mozilla::gfx::IntRect& aRect, |
56 | | gfxImageSurface* aSurface); |
57 | | #else |
58 | | static mozilla::gfx::IntRect AlignRectForSubimageRecovery(const mozilla::gfx::IntRect& aRect, |
59 | | gfxImageSurface*) |
60 | | { return aRect; } |
61 | | #endif |
62 | | |
63 | | /** from cairo-xlib-utils.c, modified */ |
64 | | /** |
65 | | * Given the RGB data for two image surfaces, one a source image composited |
66 | | * with OVER onto a black background, and one a source image composited with |
67 | | * OVER onto a white background, reconstruct the original image data into |
68 | | * black_data. |
69 | | * |
70 | | * Consider a single color channel and a given pixel. Suppose the original |
71 | | * premultiplied color value was C and the alpha value was A. Let the final |
72 | | * on-black color be B and the final on-white color be W. All values range |
73 | | * over 0-255. |
74 | | * |
75 | | * Then B=C and W=(255*(255 - A) + C*255)/255. Solving for A, we get |
76 | | * A=255 - (W - C). Therefore it suffices to leave the black_data color |
77 | | * data alone and set the alpha values using that simple formula. It shouldn't |
78 | | * matter what color channel we pick for the alpha computation, but we'll |
79 | | * pick green because if we went through a color channel downsample the green |
80 | | * bits are likely to be the most accurate. |
81 | | * |
82 | | * This function needs to be in the header file since it's used by both |
83 | | * gfxRecoverAlpha.cpp and gfxRecoverAlphaSSE2.cpp. |
84 | | */ |
85 | | |
86 | | static inline uint32_t |
87 | | RecoverPixel(uint32_t black, uint32_t white) |
88 | 0 | { |
89 | 0 | const uint32_t GREEN_MASK = 0x0000FF00; |
90 | 0 | const uint32_t ALPHA_MASK = 0xFF000000; |
91 | 0 |
|
92 | 0 | /* |diff| here is larger when the source image pixel is more transparent. |
93 | 0 | If both renderings are from the same source image composited with OVER, |
94 | 0 | then the color values on white will always be greater than those on |
95 | 0 | black, so |diff| would not overflow. However, overflow may happen, for |
96 | 0 | example, when a plugin plays a video and the image is rapidly changing. |
97 | 0 | If there is overflow, then behave as if we limit to the difference to |
98 | 0 | >= 0, which will make the rendering opaque. (Without this overflow |
99 | 0 | will make the rendering transparent.) */ |
100 | 0 | uint32_t diff = (white & GREEN_MASK) - (black & GREEN_MASK); |
101 | 0 | /* |diff| is 0xFFFFxx00 on overflow and 0x0000xx00 otherwise, so use this |
102 | 0 | to limit the transparency. */ |
103 | 0 | uint32_t limit = diff & ALPHA_MASK; |
104 | 0 | /* The alpha bits of the result */ |
105 | 0 | uint32_t alpha = (ALPHA_MASK - (diff << 16)) | limit; |
106 | 0 |
|
107 | 0 | return alpha | (black & ~ALPHA_MASK); |
108 | 0 | } |
109 | | }; |
110 | | |
111 | | #endif /* _GFXALPHARECOVERY_H_ */ |