Commit 5be15927 authored by dcheng@chromium.org's avatar dcheng@chromium.org

Add heuristic for fixing the alpha channel when reading clipboard images on Windows

The code attempts to detect an image with a garbage in the alpha channel and reset the alpha channel to a sane state in that case.

BUG=97160
TEST=Paste an image into a page using event.ClipboardData with the Windows Basic theme active.

Review URL: http://codereview.chromium.org/7967007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102317 0039d316-1c4b-4281-b951-d872f2087c98
parent 907ffbc4
...@@ -134,6 +134,27 @@ HGLOBAL CreateGlobalData(const std::basic_string<charT>& str) { ...@@ -134,6 +134,27 @@ HGLOBAL CreateGlobalData(const std::basic_string<charT>& str) {
return data; return data;
}; };
bool BitmapHasInvalidPremultipliedColors(const SkBitmap& bitmap) {
for (int x = 0; x < bitmap.width(); ++x) {
for (int y = 0; y < bitmap.height(); ++y) {
uint32_t pixel = *bitmap.getAddr32(x, y);
if (SkColorGetR(pixel) > SkColorGetA(pixel) ||
SkColorGetG(pixel) > SkColorGetA(pixel) ||
SkColorGetB(pixel) > SkColorGetA(pixel))
return true;
}
}
return false;
}
void MakeBitmapOpaque(const SkBitmap& bitmap) {
for (int x = 0; x < bitmap.width(); ++x) {
for (int y = 0; y < bitmap.height(); ++y) {
*bitmap.getAddr32(x, y) = SkColorSetA(*bitmap.getAddr32(x, y), 0xFF);
}
}
}
} // namespace } // namespace
Clipboard::Clipboard() : create_window_(false) { Clipboard::Clipboard() : create_window_(false) {
...@@ -476,18 +497,24 @@ SkBitmap Clipboard::ReadImage(Buffer buffer) const { ...@@ -476,18 +497,24 @@ SkBitmap Clipboard::ReadImage(Buffer buffer) const {
bitmap->bmiHeader.biHeight, bitmap_bits, bitmap, bitmap->bmiHeader.biHeight, bitmap_bits, bitmap,
DIB_RGB_COLORS); DIB_RGB_COLORS);
} }
// SetDIBitsToDevice doesn't properly set alpha values for bitmaps with // Windows doesn't really handle alpha channels well in many situations. When
// depth < 32bpp so manually fix it up. // the source image is < 32 bpp, we force the bitmap to be opaque. When the
if (bitmap->bmiHeader.biBitCount < 32) { // source image is 32 bpp, the alpha channel might still contain garbage data.
const SkBitmap& device_bitmap = canvas.getDevice()->accessBitmap(true); // Since Windows uses premultiplied alpha, we scan for instances where
// (R, G, B) > A. If there are any invalid premultiplied colors in the image,
// we assume the alpha channel contains garbage and force the bitmap to be
// opaque as well. Note that this heuristic will fail on a transparent bitmap
// containing only black pixels...
const SkBitmap& device_bitmap = canvas.getDevice()->accessBitmap(true);
{
SkAutoLockPixels lock(device_bitmap); SkAutoLockPixels lock(device_bitmap);
for (int x = 0; x < device_bitmap.width(); ++x) { bool has_invalid_alpha_channel = bitmap->bmiHeader.biBitCount < 32 ||
for (int y = 0; y < device_bitmap.height(); ++y) { BitmapHasInvalidPremultipliedColors(device_bitmap);
*device_bitmap.getAddr32(x, y) = if (has_invalid_alpha_channel) {
SkColorSetA(*device_bitmap.getAddr32(x, y), 0xFF); MakeBitmapOpaque(device_bitmap);
}
} }
} }
return canvas.ExtractBitmap(); return canvas.ExtractBitmap();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment