1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxAlphaRecovery.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,112 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef _GFXALPHARECOVERY_H_ 1.10 +#define _GFXALPHARECOVERY_H_ 1.11 + 1.12 +#include "mozilla/SSE.h" 1.13 +#include "gfxTypes.h" 1.14 +#include "nsRect.h" 1.15 + 1.16 +struct nsIntRect; 1.17 +class gfxImageSurface; 1.18 + 1.19 +class gfxAlphaRecovery { 1.20 +public: 1.21 + /** 1.22 + * Some SIMD fast-paths only can be taken if the relative 1.23 + * byte-alignment of images' pointers and strides meets certain 1.24 + * criteria. Aligning image pointers and strides by 1.25 + * |GoodAlignmentLog2()| below will ensure that fast-paths aren't 1.26 + * skipped because of misalignment. Fast-paths may still be taken 1.27 + * even if GoodAlignmentLog2() is not met, in some conditions. 1.28 + */ 1.29 + static uint32_t GoodAlignmentLog2() { return 4; /* for SSE2 */ } 1.30 + 1.31 + /* Given two surfaces of equal size with the same rendering, one onto a 1.32 + * black background and the other onto white, recovers alpha values from 1.33 + * the difference and sets the alpha values on the black surface. 1.34 + * The surfaces must have format RGB24 or ARGB32. 1.35 + * Returns true on success. 1.36 + */ 1.37 + static bool RecoverAlpha (gfxImageSurface *blackSurface, 1.38 + const gfxImageSurface *whiteSurface); 1.39 + 1.40 +#ifdef MOZILLA_MAY_SUPPORT_SSE2 1.41 + /* This does the same as the previous function, but uses SSE2 1.42 + * optimizations. Usually this should not be called directly. Be sure to 1.43 + * check mozilla::supports_sse2() before calling this function. 1.44 + */ 1.45 + static bool RecoverAlphaSSE2 (gfxImageSurface *blackSurface, 1.46 + const gfxImageSurface *whiteSurface); 1.47 + 1.48 + /** 1.49 + * A common use-case for alpha recovery is to paint into a 1.50 + * temporary "white image", then paint onto a subrect of the 1.51 + * surface, the "black image", into which alpha-recovered pixels 1.52 + * are eventually to be written. This function returns a rect 1.53 + * aligned so that recovering alpha for that rect will hit SIMD 1.54 + * fast-paths, if possible. It's not always possible to align 1.55 + * |aRect| so that fast-paths will be taken. 1.56 + * 1.57 + * The returned rect is always a superset of |aRect|. 1.58 + */ 1.59 + static nsIntRect AlignRectForSubimageRecovery(const nsIntRect& aRect, 1.60 + gfxImageSurface* aSurface); 1.61 +#else 1.62 + static nsIntRect AlignRectForSubimageRecovery(const nsIntRect& aRect, 1.63 + gfxImageSurface*) 1.64 + { return aRect; } 1.65 +#endif 1.66 + 1.67 + /** from cairo-xlib-utils.c, modified */ 1.68 + /** 1.69 + * Given the RGB data for two image surfaces, one a source image composited 1.70 + * with OVER onto a black background, and one a source image composited with 1.71 + * OVER onto a white background, reconstruct the original image data into 1.72 + * black_data. 1.73 + * 1.74 + * Consider a single color channel and a given pixel. Suppose the original 1.75 + * premultiplied color value was C and the alpha value was A. Let the final 1.76 + * on-black color be B and the final on-white color be W. All values range 1.77 + * over 0-255. 1.78 + * 1.79 + * Then B=C and W=(255*(255 - A) + C*255)/255. Solving for A, we get 1.80 + * A=255 - (W - C). Therefore it suffices to leave the black_data color 1.81 + * data alone and set the alpha values using that simple formula. It shouldn't 1.82 + * matter what color channel we pick for the alpha computation, but we'll 1.83 + * pick green because if we went through a color channel downsample the green 1.84 + * bits are likely to be the most accurate. 1.85 + * 1.86 + * This function needs to be in the header file since it's used by both 1.87 + * gfxRecoverAlpha.cpp and gfxRecoverAlphaSSE2.cpp. 1.88 + */ 1.89 + 1.90 + static inline uint32_t 1.91 + RecoverPixel(uint32_t black, uint32_t white) 1.92 + { 1.93 + const uint32_t GREEN_MASK = 0x0000FF00; 1.94 + const uint32_t ALPHA_MASK = 0xFF000000; 1.95 + 1.96 + /* |diff| here is larger when the source image pixel is more transparent. 1.97 + If both renderings are from the same source image composited with OVER, 1.98 + then the color values on white will always be greater than those on 1.99 + black, so |diff| would not overflow. However, overflow may happen, for 1.100 + example, when a plugin plays a video and the image is rapidly changing. 1.101 + If there is overflow, then behave as if we limit to the difference to 1.102 + >= 0, which will make the rendering opaque. (Without this overflow 1.103 + will make the rendering transparent.) */ 1.104 + uint32_t diff = (white & GREEN_MASK) - (black & GREEN_MASK); 1.105 + /* |diff| is 0xFFFFxx00 on overflow and 0x0000xx00 otherwise, so use this 1.106 + to limit the transparency. */ 1.107 + uint32_t limit = diff & ALPHA_MASK; 1.108 + /* The alpha bits of the result */ 1.109 + uint32_t alpha = (ALPHA_MASK - (diff << 16)) | limit; 1.110 + 1.111 + return alpha | (black & ~ALPHA_MASK); 1.112 + } 1.113 +}; 1.114 + 1.115 +#endif /* _GFXALPHARECOVERY_H_ */