gfx/thebes/gfxAlphaRecovery.h

changeset 0
6474c204b198
     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_ */

mercurial