summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxAlphaRecovery.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/thebes/gfxAlphaRecovery.h111
1 files changed, 111 insertions, 0 deletions
diff --git a/gfx/thebes/gfxAlphaRecovery.h b/gfx/thebes/gfxAlphaRecovery.h
new file mode 100644
index 0000000000..53b38f2ac0
--- /dev/null
+++ b/gfx/thebes/gfxAlphaRecovery.h
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _GFXALPHARECOVERY_H_
+#define _GFXALPHARECOVERY_H_
+
+#include "mozilla/SSE.h"
+#include "gfxTypes.h"
+#include "mozilla/gfx/Rect.h"
+
+class gfxImageSurface;
+
+class gfxAlphaRecovery {
+ public:
+ /**
+ * Some SIMD fast-paths only can be taken if the relative
+ * byte-alignment of images' pointers and strides meets certain
+ * criteria. Aligning image pointers and strides by
+ * |GoodAlignmentLog2()| below will ensure that fast-paths aren't
+ * skipped because of misalignment. Fast-paths may still be taken
+ * even if GoodAlignmentLog2() is not met, in some conditions.
+ */
+ static uint32_t GoodAlignmentLog2() { return 4; /* for SSE2 */ }
+
+ /* Given two surfaces of equal size with the same rendering, one onto a
+ * black background and the other onto white, recovers alpha values from
+ * the difference and sets the alpha values on the black surface.
+ * The surfaces must have format RGB24 or ARGB32.
+ * Returns true on success.
+ */
+ static bool RecoverAlpha(gfxImageSurface* blackSurface,
+ const gfxImageSurface* whiteSurface);
+
+#ifdef MOZILLA_MAY_SUPPORT_SSE2
+ /* This does the same as the previous function, but uses SSE2
+ * optimizations. Usually this should not be called directly. Be sure to
+ * check mozilla::supports_sse2() before calling this function.
+ */
+ static bool RecoverAlphaSSE2(gfxImageSurface* blackSurface,
+ const gfxImageSurface* whiteSurface);
+
+ /**
+ * A common use-case for alpha recovery is to paint into a
+ * temporary "white image", then paint onto a subrect of the
+ * surface, the "black image", into which alpha-recovered pixels
+ * are eventually to be written. This function returns a rect
+ * aligned so that recovering alpha for that rect will hit SIMD
+ * fast-paths, if possible. It's not always possible to align
+ * |aRect| so that fast-paths will be taken.
+ *
+ * The returned rect is always a superset of |aRect|.
+ */
+ static mozilla::gfx::IntRect AlignRectForSubimageRecovery(
+ const mozilla::gfx::IntRect& aRect, gfxImageSurface* aSurface);
+#else
+ static mozilla::gfx::IntRect AlignRectForSubimageRecovery(
+ const mozilla::gfx::IntRect& aRect, gfxImageSurface*) {
+ return aRect;
+ }
+#endif
+
+ /** from cairo-xlib-utils.c, modified */
+ /**
+ * Given the RGB data for two image surfaces, one a source image composited
+ * with OVER onto a black background, and one a source image composited with
+ * OVER onto a white background, reconstruct the original image data into
+ * black_data.
+ *
+ * Consider a single color channel and a given pixel. Suppose the original
+ * premultiplied color value was C and the alpha value was A. Let the final
+ * on-black color be B and the final on-white color be W. All values range
+ * over 0-255.
+ *
+ * Then B=C and W=(255*(255 - A) + C*255)/255. Solving for A, we get
+ * A=255 - (W - C). Therefore it suffices to leave the black_data color
+ * data alone and set the alpha values using that simple formula. It shouldn't
+ * matter what color channel we pick for the alpha computation, but we'll
+ * pick green because if we went through a color channel downsample the green
+ * bits are likely to be the most accurate.
+ *
+ * This function needs to be in the header file since it's used by both
+ * gfxRecoverAlpha.cpp and gfxRecoverAlphaSSE2.cpp.
+ */
+
+ static inline uint32_t RecoverPixel(uint32_t black, uint32_t white) {
+ const uint32_t GREEN_MASK = 0x0000FF00;
+ const uint32_t ALPHA_MASK = 0xFF000000;
+
+ /* |diff| here is larger when the source image pixel is more
+ transparent. If both renderings are from the same source image
+ composited with OVER, then the color values on white will always be
+ greater than those on black, so |diff| would not overflow. However,
+ overflow may happen, for example, when a plugin plays a video and
+ the image is rapidly changing. If there is overflow, then behave as
+ if we limit to the difference to
+ >= 0, which will make the rendering opaque. (Without this overflow
+ will make the rendering transparent.) */
+ uint32_t diff = (white & GREEN_MASK) - (black & GREEN_MASK);
+ /* |diff| is 0xFFFFxx00 on overflow and 0x0000xx00 otherwise, so use
+ this to limit the transparency. */
+ uint32_t limit = diff & ALPHA_MASK;
+ /* The alpha bits of the result */
+ uint32_t alpha = (ALPHA_MASK - (diff << 16)) | limit;
+
+ return alpha | (black & ~ALPHA_MASK);
+ }
+};
+
+#endif /* _GFXALPHARECOVERY_H_ */