Index: ui/views/corewm/cursor_height_provider_win.cc |
diff --git a/ui/views/corewm/cursor_height_provider_win.cc b/ui/views/corewm/cursor_height_provider_win.cc |
index 0d28d3801aa8ce2d24f89339f054eaddb073de17..d3945034809d41f3bc015e018a87dfd8479fcfa5 100644 |
--- a/ui/views/corewm/cursor_height_provider_win.cc |
+++ b/ui/views/corewm/cursor_height_provider_win.cc |
@@ -105,17 +105,48 @@ int CalculateCursorHeight(HCURSOR cursor_handle) { |
if (data == NULL) |
return kDefaultHeight; |
- const int cursor_height = GetSystemMetrics(SM_CYCURSOR); |
- // Crash data seems to indicate cursor_height may be bigger than the bitmap. |
- int i = std::max(0, static_cast<int>(bitmap_info.bmiHeader.biHeight) - |
- cursor_height); |
- for (; i < bitmap_info.bmiHeader.biHeight; ++i) { |
- if (!IsRowTransparent(data, row_size, last_byte_mask, i)) { |
- i--; |
+ // There are 2 types of cursors: Ones that cover the area underneath |
+ // completely (i.e. hand cursor) and ones that partially cover |
+ // and partially blend with background (i. e. I-beam cursor). |
+ // These will have either 1 square mask or 2 masks stacked on top |
+ // of each other (xor mask and and mask). |
+ const bool has_xor_mask = |
+ bitmap_info.bmiHeader.biHeight == 2 * bitmap_info.bmiHeader.biWidth; |
+ const int cursor_height = |
+ has_xor_mask ? static_cast<int>(bitmap_info.bmiHeader.biHeight / 2) |
+ : static_cast<int>(bitmap_info.bmiHeader.biHeight); |
+ int xor_offset; |
+ if (has_xor_mask) { |
+ for (xor_offset = 0; xor_offset < cursor_height; ++xor_offset) { |
+ const uint32_t row_start = row_size * xor_offset; |
+ const uint32_t row_boundary = row_start + row_size; |
+ for (uint32_t i = row_start; i < row_boundary; ++i) |
+ data.get()[i] = ~(data.get()[i]); |
+ if (!IsRowTransparent(data, row_size, last_byte_mask, xor_offset)) { |
+ break; |
+ } |
+ } |
+ } else { |
+ xor_offset = cursor_height; |
+ } |
+ |
+ int and_offset; |
+ |
+ for (and_offset = has_xor_mask ? cursor_height : 0; |
+ and_offset < bitmap_info.bmiHeader.biHeight; ++and_offset) { |
+ if (!IsRowTransparent(data, row_size, last_byte_mask, and_offset)) { |
break; |
} |
} |
- return bitmap_info.bmiHeader.biHeight - i - icon.yHotspot; |
+ if (has_xor_mask) { |
+ and_offset -= cursor_height; |
+ } |
+ const int offset = std::min(xor_offset, and_offset); |
+ |
+ DeleteObject(icon.hbmColor); |
+ DeleteObject(icon.hbmMask); |
+ |
+ return cursor_height - offset - icon.yHotspot + 1; |
} |
} // namespace |