Line data Source code
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 53 : 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 0 : RecoverPixel(uint32_t black, uint32_t white)
88 : {
89 0 : const uint32_t GREEN_MASK = 0x0000FF00;
90 0 : const uint32_t ALPHA_MASK = 0xFF000000;
91 :
92 : /* |diff| here is larger when the source image pixel is more transparent.
93 : If both renderings are from the same source image composited with OVER,
94 : then the color values on white will always be greater than those on
95 : black, so |diff| would not overflow. However, overflow may happen, for
96 : example, when a plugin plays a video and the image is rapidly changing.
97 : If there is overflow, then behave as if we limit to the difference to
98 : >= 0, which will make the rendering opaque. (Without this overflow
99 : will make the rendering transparent.) */
100 0 : uint32_t diff = (white & GREEN_MASK) - (black & GREEN_MASK);
101 : /* |diff| is 0xFFFFxx00 on overflow and 0x0000xx00 otherwise, so use this
102 : to limit the transparency. */
103 0 : uint32_t limit = diff & ALPHA_MASK;
104 : /* The alpha bits of the result */
105 0 : uint32_t alpha = (ALPHA_MASK - (diff << 16)) | limit;
106 :
107 0 : return alpha | (black & ~ALPHA_MASK);
108 : }
109 : };
110 :
111 : #endif /* _GFXALPHARECOVERY_H_ */
|