b=579676 detect overflow when black and white images differ r=roc

This commit is contained in:
Karl Tomlinson 2010-08-09 14:22:56 +12:00
Родитель 52babc3652
Коммит f21acbc8e6
1 изменённых файлов: 44 добавлений и 36 удалений

Просмотреть файл

@ -59,8 +59,29 @@
* bits are likely to be the most accurate. * bits are likely to be the most accurate.
*/ */
#define SET_ALPHA(v, a) (((v) & ~(0xFF << 24)) | ((a) << 24)) static inline PRUint32
#define GREEN_OF(v) (((v) >> 8) & 0xFF) RecoverPixel(PRUint32 black, PRUint32 white)
{
const PRUint32 GREEN_MASK = 0x0000FF00;
const PRUint32 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.) */
PRUint32 diff = (white & GREEN_MASK) - (black & GREEN_MASK);
/* |diff| is 0xFFFFxx00 on overflow and 0x0000xx00 otherwise, so use this
to limit the transparency. */
PRUint32 limit = diff & ALPHA_MASK;
/* The alpha bits of the result */
PRUint32 alpha = (ALPHA_MASK - (diff << 16)) | limit;
return alpha | (black & ~ALPHA_MASK);
}
/* static */ PRBool /* static */ PRBool
gfxAlphaRecovery::RecoverAlpha(gfxImageSurface* blackSurf, gfxAlphaRecovery::RecoverAlpha(gfxImageSurface* blackSurf,
@ -76,45 +97,32 @@ gfxAlphaRecovery::RecoverAlpha(gfxImageSurface* blackSurf,
whiteSurf->Format() != gfxASurface::ImageFormatRGB24)) whiteSurf->Format() != gfxASurface::ImageFormatRGB24))
return PR_FALSE; return PR_FALSE;
if (size.width == 0 || size.height == 0) {
if (analysis) {
analysis->uniformAlpha = PR_TRUE;
analysis->uniformColor = PR_TRUE;
/* whatever we put here will be true */
analysis->alpha = 1.0;
analysis->r = analysis->g = analysis->b = 0.0;
}
return PR_TRUE;
}
unsigned char* blackData = blackSurf->Data();
unsigned char* whiteData = whiteSurf->Data();
if (!blackData || !whiteData)
return PR_FALSE;
blackSurf->Flush(); blackSurf->Flush();
whiteSurf->Flush(); whiteSurf->Flush();
PRUint32 black = *reinterpret_cast<PRUint32*>(blackData); unsigned char* blackData = blackSurf->Data();
PRUint32 white = *reinterpret_cast<PRUint32*>(whiteData); unsigned char* whiteData = whiteSurf->Data();
unsigned char first_alpha =
255 - (GREEN_OF(white) - GREEN_OF(black)); /* Get the alpha value of 'first' */
/* set the alpha value of 'first' */ PRUint32 first;
PRUint32 first = SET_ALPHA(black, first_alpha); if (size.width == 0 || size.height == 0) {
first = 0;
} else {
if (!blackData || !whiteData)
return PR_FALSE;
first = RecoverPixel(*reinterpret_cast<PRUint32*>(blackData),
*reinterpret_cast<PRUint32*>(whiteData));
}
PRUint32 deltas = 0; PRUint32 deltas = 0;
for (PRInt32 i = 0; i < size.height; ++i) { for (PRInt32 i = 0; i < size.height; ++i) {
PRUint32* blackPixel = reinterpret_cast<PRUint32*>(blackData); PRUint32* blackPixel = reinterpret_cast<PRUint32*>(blackData);
const PRUint32* whitePixel = reinterpret_cast<PRUint32*>(whiteData); const PRUint32* whitePixel = reinterpret_cast<PRUint32*>(whiteData);
for (PRInt32 j = 0; j < size.width; ++j) { for (PRInt32 j = 0; j < size.width; ++j) {
black = blackPixel[j]; PRUint32 recovered = RecoverPixel(blackPixel[j], whitePixel[j]);
white = whitePixel[j]; blackPixel[j] = recovered;
unsigned char pixel_alpha = deltas |= (first ^ recovered);
255 - (GREEN_OF(white) - GREEN_OF(black));
black = SET_ALPHA(black, pixel_alpha);
blackPixel[j] = black;
deltas |= (first ^ black);
} }
blackData += blackSurf->Stride(); blackData += blackSurf->Stride();
whiteData += whiteSurf->Stride(); whiteData += whiteSurf->Stride();
@ -126,18 +134,18 @@ gfxAlphaRecovery::RecoverAlpha(gfxImageSurface* blackSurf,
analysis->uniformAlpha = (deltas >> 24) == 0; analysis->uniformAlpha = (deltas >> 24) == 0;
analysis->uniformColor = PR_FALSE; analysis->uniformColor = PR_FALSE;
if (analysis->uniformAlpha) { if (analysis->uniformAlpha) {
analysis->alpha = first_alpha/255.0; double d_first_alpha = first >> 24;
analysis->alpha = d_first_alpha/255.0;
/* we only set uniformColor when the alpha is already uniform. /* we only set uniformColor when the alpha is already uniform.
it's only useful in that case ... and if the alpha was nonuniform it's only useful in that case ... and if the alpha was nonuniform
then computing whether the color is uniform would require unpremultiplying then computing whether the color is uniform would require unpremultiplying
every pixel */ every pixel */
analysis->uniformColor = (deltas & ~(0xFF << 24)) == 0; analysis->uniformColor = deltas == 0;
if (analysis->uniformColor) { if (analysis->uniformColor) {
if (first_alpha == 0) { if (d_first_alpha == 0.0) {
/* can't unpremultiply, this is OK */ /* can't unpremultiply, this is OK */
analysis->r = analysis->g = analysis->b = 0.0; analysis->r = analysis->g = analysis->b = 0.0;
} else { } else {
double d_first_alpha = first_alpha;
analysis->r = (first & 0xFF)/d_first_alpha; analysis->r = (first & 0xFF)/d_first_alpha;
analysis->g = ((first >> 8) & 0xFF)/d_first_alpha; analysis->g = ((first >> 8) & 0xFF)/d_first_alpha;
analysis->b = ((first >> 16) & 0xFF)/d_first_alpha; analysis->b = ((first >> 16) & 0xFF)/d_first_alpha;