From fd9f15be2e290d54095d1b3c6b2285d89447e984 Mon Sep 17 00:00:00 2001 From: kylechar Date: Mon, 21 Dec 2015 10:43:01 -0800 Subject: Fix bug where custom cursors would disappear when screen was rotated for ozone based platforms. This was caused by commit cd0a8ae72380dc461eea58084325d9d981942192. The change modified the cursor SkBitmap to always be in unpremultiplied alpha format. However, the SkCanvas::drawBitmap() operation fails silently if the SkBitmap is in unpremultiplied format and the ui::ScaleAndRotateCursorBitmapAndHotpoint() function relies on SkCanvas::drawBitmap() to rotate the cursor. This fails and the cursor disappears. This fix temporarily converts the cursor bitmap back to premultiplied alpha before rotating. It also adds a DCHECK to SkBitmapOperations::Rotate() to document the alpha type requirement. BUG=533748 Review URL: https://codereview.chromium.org/1514723003 Cr-Commit-Position: refs/heads/master@{#366423} --- ui/base/cursor/cursor_util.cc | 37 +++++++++++++++++++++++++++++++++++++ ui/gfx/skbitmap_operations.cc | 3 +++ 2 files changed, 40 insertions(+) diff --git a/ui/base/cursor/cursor_util.cc b/ui/base/cursor/cursor_util.cc index 193ab73..0e1d36e 100644 --- a/ui/base/cursor/cursor_util.cc +++ b/ui/base/cursor/cursor_util.cc @@ -15,10 +15,43 @@ namespace ui { +namespace { + +// Converts the SkBitmap to use a different alpha type. Returns true if bitmap +// was modified, otherwise returns false. +bool ConvertSkBitmapAlphaType(SkBitmap* bitmap, SkAlphaType alpha_type) { + if (bitmap->info().alphaType() == alpha_type) { + return false; + } + + // Copy the bitmap into a temporary buffer. This will convert alpha type. + SkImageInfo image_info = + SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), alpha_type); + std::vector buffer(bitmap->getSize()); + bitmap->readPixels(image_info, &buffer[0], image_info.minRowBytes(), 0, 0); + // Read the temporary buffer back into the original bitmap. + bitmap->reset(); + bitmap->allocPixels(image_info); + memcpy(bitmap->getPixels(), &buffer[0], buffer.size()); + + return true; +} + +} // namespace + void ScaleAndRotateCursorBitmapAndHotpoint(float scale, gfx::Display::Rotation rotation, SkBitmap* bitmap, gfx::Point* hotpoint) { + // SkBitmapOperations::Rotate() needs the bitmap to have premultiplied alpha, + // so convert bitmap alpha type if we are going to rotate. + bool was_converted = false; + if (rotation != gfx::Display::ROTATE_0 && + bitmap->info().alphaType() == kUnpremul_SkAlphaType) { + ConvertSkBitmapAlphaType(bitmap, kPremul_SkAlphaType); + was_converted = true; + } + switch (rotation) { case gfx::Display::ROTATE_0: break; @@ -40,6 +73,10 @@ void ScaleAndRotateCursorBitmapAndHotpoint(float scale, break; } + if (was_converted) { + ConvertSkBitmapAlphaType(bitmap, kUnpremul_SkAlphaType); + } + if (scale < FLT_EPSILON) { NOTREACHED() << "Scale must be larger than 0."; scale = 1.0f; diff --git a/ui/gfx/skbitmap_operations.cc b/ui/gfx/skbitmap_operations.cc index a12ef83..7d16bff 100644 --- a/ui/gfx/skbitmap_operations.cc +++ b/ui/gfx/skbitmap_operations.cc @@ -757,6 +757,9 @@ SkBitmap SkBitmapOperations::CreateDropShadow( // static SkBitmap SkBitmapOperations::Rotate(const SkBitmap& source, RotationAmount rotation) { + // SkCanvas::drawBitmap() fails silently with unpremultiplied SkBitmap. + DCHECK_NE(source.info().alphaType(), kUnpremul_SkAlphaType); + SkBitmap result; SkScalar angle = SkFloatToScalar(0.0f); -- cgit v1.1