Index: ui/base/clipboard/clipboard_win.cc |
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc |
index cec06012fbf50e9540fe27d69155a15eba6122e2..a736f638feeb37b53440f69c03fc0a1991e49354 100644 |
--- a/ui/base/clipboard/clipboard_win.cc |
+++ b/ui/base/clipboard/clipboard_win.cc |
@@ -476,18 +476,38 @@ SkBitmap Clipboard::ReadImage(Buffer buffer) const { |
bitmap->bmiHeader.biHeight, bitmap_bits, bitmap, |
DIB_RGB_COLORS); |
} |
- // SetDIBitsToDevice doesn't properly set alpha values for bitmaps with |
- // depth < 32bpp so manually fix it up. |
- if (bitmap->bmiHeader.biBitCount < 32) { |
- const SkBitmap& device_bitmap = canvas.getDevice()->accessBitmap(true); |
+ // Windows doesn't really handle alpha channels well in many situations. We |
+ // attempt to manually fix the alpha channel here. 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 junk and reset the alpha value for all pixels to 255. This |
+ // heuristic will fail on a transparent bitmap containing only black pixels... |
+ const SkBitmap& device_bitmap = canvas.getDevice()->accessBitmap(true); |
+ { |
SkAutoLockPixels lock(device_bitmap); |
+ bool has_invalid_alpha_channel = false; |
for (int x = 0; x < device_bitmap.width(); ++x) { |
for (int y = 0; y < device_bitmap.height(); ++y) { |
- *device_bitmap.getAddr32(x, y) = |
- SkColorSetA(*device_bitmap.getAddr32(x, y), 0xFF); |
+ uint32_t pixel = *device_bitmap.getAddr32(x, y); |
+ if (SkColorGetR(pixel) > SkColorGetA(pixel) || |
+ SkColorGetG(pixel) > SkColorGetA(pixel) || |
+ SkColorGetB(pixel) > SkColorGetA(pixel)) { |
+ has_invalid_alpha_channel = true; |
+ break; |
tony
2011/09/20 23:26:54
This only breaks out of the inner for loop. You p
dcheng
2011/09/20 23:56:33
Done. Thanks for the catch.
|
+ } |
+ } |
+ } |
+ |
+ if (has_invalid_alpha_channel) { |
+ for (int x = 0; x < device_bitmap.width(); ++x) { |
+ for (int y = 0; y < device_bitmap.height(); ++y) { |
+ *device_bitmap.getAddr32(x, y) = |
+ SkColorSetA(*device_bitmap.getAddr32(x, y), 0xFF); |
+ } |
} |
} |
} |
+ |
return canvas.ExtractBitmap(); |
} |