1 /* -*- Mode: C++; tab-width: 20; 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/. */
6 #ifndef _GFXALPHARECOVERY_H_
7 #define _GFXALPHARECOVERY_H_
10 #include "mozilla/gfx/Rect.h"
12 class gfxImageSurface
;
14 class gfxAlphaRecovery
{
17 * Some SIMD fast-paths only can be taken if the relative
18 * byte-alignment of images' pointers and strides meets certain
19 * criteria. Aligning image pointers and strides by
20 * |GoodAlignmentLog2()| below will ensure that fast-paths aren't
21 * skipped because of misalignment. Fast-paths may still be taken
22 * even if GoodAlignmentLog2() is not met, in some conditions.
24 static uint32_t GoodAlignmentLog2() { return 4; /* for SSE2 */ }
26 /* Given two surfaces of equal size with the same rendering, one onto a
27 * black background and the other onto white, recovers alpha values from
28 * the difference and sets the alpha values on the black surface.
29 * The surfaces must have format RGB24 or ARGB32.
30 * Returns true on success.
32 static bool RecoverAlpha(gfxImageSurface
* blackSurface
,
33 const gfxImageSurface
* whiteSurface
);
35 /* This does the same as the previous function, but uses SIMD
36 * optimizations. Usually this should not be called directly.
39 static bool RecoverAlphaGeneric(gfxImageSurface
* blackSurface
,
40 const gfxImageSurface
* whiteSurface
);
42 /** from cairo-xlib-utils.c, modified */
44 * Given the RGB data for two image surfaces, one a source image composited
45 * with OVER onto a black background, and one a source image composited with
46 * OVER onto a white background, reconstruct the original image data into
49 * Consider a single color channel and a given pixel. Suppose the original
50 * premultiplied color value was C and the alpha value was A. Let the final
51 * on-black color be B and the final on-white color be W. All values range
54 * Then B=C and W=(255*(255 - A) + C*255)/255. Solving for A, we get
55 * A=255 - (W - C). Therefore it suffices to leave the black_data color
56 * data alone and set the alpha values using that simple formula. It shouldn't
57 * matter what color channel we pick for the alpha computation, but we'll
58 * pick green because if we went through a color channel downsample the green
59 * bits are likely to be the most accurate.
61 * This function needs to be in the header file since it's used by both
62 * gfxRecoverAlpha.cpp and gfxRecoverAlphaGeneric.hpp.
65 static inline uint32_t RecoverPixel(uint32_t black
, uint32_t white
) {
66 const uint32_t GREEN_MASK
= 0x0000FF00;
67 const uint32_t ALPHA_MASK
= 0xFF000000;
69 /* |diff| here is larger when the source image pixel is more
70 transparent. If both renderings are from the same source image
71 composited with OVER, then the color values on white will always be
72 greater than those on black, so |diff| would not overflow. However,
73 overflow may happen, for example, when a plugin plays a video and
74 the image is rapidly changing. If there is overflow, then behave as
75 if we limit to the difference to
76 >= 0, which will make the rendering opaque. (Without this overflow
77 will make the rendering transparent.) */
78 uint32_t diff
= (white
& GREEN_MASK
) - (black
& GREEN_MASK
);
79 /* |diff| is 0xFFFFxx00 on overflow and 0x0000xx00 otherwise, so use
80 this to limit the transparency. */
81 uint32_t limit
= diff
& ALPHA_MASK
;
82 /* The alpha bits of the result */
83 uint32_t alpha
= (ALPHA_MASK
- (diff
<< 16)) | limit
;
85 return alpha
| (black
& ~ALPHA_MASK
);
89 #endif /* _GFXALPHARECOVERY_H_ */