OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ui/views/corewm/cursor_height_provider_win.h" |
| 6 |
| 7 #include <windows.h> |
| 8 |
| 9 #include "base/basictypes.h" |
| 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/win/scoped_hdc.h" |
| 12 |
| 13 namespace { |
| 14 const uint32 bits_per_uint32 = 32; |
| 15 // All bits are 1 for transparent portion of monochromatic mask. |
| 16 const uint32 transparent_mask = 0xffffffff; |
| 17 // This is height of default pointer arrow in Windows 7. |
| 18 const int default_height = 20; |
| 19 |
| 20 /** |
| 21 * Gets the vertical offset between specified cursor's hotpoint and it's bottom. |
| 22 * |
| 23 * Gets the cursor image data and extract cursor's visible height. |
| 24 * Based on that get's what should be the vertical offset between cursor's |
| 25 * hot point and the tooltip. |
| 26 */ |
| 27 class CursorVisibleHeightCalculator { |
| 28 public: |
| 29 explicit CursorVisibleHeightCalculator(HCURSOR cursor_handle); |
| 30 int visible_height() const { return visible_height_; } |
| 31 |
| 32 private: |
| 33 /** |
| 34 * Extracts the cursor data and calculates the visible height. |
| 35 */ |
| 36 void Init(HCURSOR cursor_handle); |
| 37 |
| 38 /** |
| 39 * Fills the BITMAPINFO structure for specified bitmap @p handle. |
| 40 * @param handle Handle to bitmap that's being examined. |
| 41 * @param info Pointer to BITMAPINFO structure that'll receive the output. |
| 42 * @return true if no error occured. |
| 43 */ |
| 44 bool GetBitmapInfo(HBITMAP handle, BITMAPINFO* info); |
| 45 |
| 46 /** |
| 47 * Fills the bitmap_data_ member with pixel data for bitmap |
| 48 * specified by @p handle in format described through @p info. |
| 49 * @param handle Handle to bitmap that's being examined. |
| 50 * @param info BITMAPINFO structure that describes the output format. |
| 51 * @return true if no error occured. |
| 52 */ |
| 53 bool GetBitmapData(HBITMAP handle, const BITMAPINFO& info); |
| 54 |
| 55 /** |
| 56 * Checks if the row on specified index is fully transparent. |
| 57 * @param y row index. |
| 58 * @return true if the row is considered transparent. |
| 59 */ |
| 60 bool IsRowTransparent(uint32 y) const; |
| 61 |
| 62 base::win::ScopedGetDC hdc_; |
| 63 // Row size in DWORDs. |
| 64 uint32 row_size_; |
| 65 // Since bitmap is padded to full DWORD OR it with this bitmask |
| 66 // to remove the padding noise. |
| 67 uint32 last_byte_mask_; |
| 68 // Pointer that receives memory block containing bitmap pixel data. |
| 69 scoped_ptr<uint32> bitmap_data_; |
| 70 int visible_height_; |
| 71 }; |
| 72 |
| 73 CursorVisibleHeightCalculator::CursorVisibleHeightCalculator( |
| 74 HCURSOR cursor_handle) |
| 75 : hdc_(NULL), |
| 76 row_size_(0), |
| 77 last_byte_mask_(0), |
| 78 visible_height_(default_height) { |
| 79 Init(cursor_handle); |
| 80 } |
| 81 |
| 82 void CursorVisibleHeightCalculator::Init(HCURSOR cursor_handle) { |
| 83 ICONINFO icon = {0}; |
| 84 GetIconInfo(cursor_handle, &icon); |
| 85 |
| 86 BITMAPINFO info = {0}; |
| 87 if (!GetBitmapInfo(icon.hbmMask, &info)) |
| 88 return; |
| 89 |
| 90 // Rows are padded to full DWORDs. OR with this mask will set them to 1 |
| 91 // to simplify matching with |transparent_mask|. |
| 92 last_byte_mask_ = ~0; |
| 93 last_byte_mask_ = last_byte_mask_ |
| 94 << (sizeof(last_byte_mask_) * 8 - |
| 95 (info.bmiHeader.biWidth % bits_per_uint32)); |
| 96 |
| 97 row_size_ = (info.bmiHeader.biWidth + bits_per_uint32 - 1) / bits_per_uint32; |
| 98 if (!GetBitmapData(icon.hbmMask, info)) |
| 99 return; |
| 100 const int cursor_height = GetSystemMetrics(SM_CYCURSOR); |
| 101 int i = info.bmiHeader.biHeight - cursor_height; |
| 102 for (; i < info.bmiHeader.biHeight; ++i) { |
| 103 if (!IsRowTransparent(i)) { |
| 104 i--; |
| 105 break; |
| 106 } |
| 107 } |
| 108 bitmap_data_.reset(); |
| 109 visible_height_ = info.bmiHeader.biHeight - i - icon.yHotspot; |
| 110 } |
| 111 |
| 112 bool CursorVisibleHeightCalculator::GetBitmapInfo(HBITMAP handle, |
| 113 BITMAPINFO* info) { |
| 114 info->bmiHeader.biSize = sizeof(info->bmiHeader); |
| 115 info->bmiHeader.biBitCount = 0; |
| 116 |
| 117 int result = GetDIBits(hdc_, handle, 0, 0, NULL, info, DIB_RGB_COLORS); |
| 118 return result != 0; |
| 119 } |
| 120 |
| 121 bool CursorVisibleHeightCalculator::GetBitmapData(HBITMAP handle, |
| 122 const BITMAPINFO& info) { |
| 123 // Masks are monochromatic. |
| 124 DCHECK_EQ(info.bmiHeader.biBitCount, 1); |
| 125 if (info.bmiHeader.biBitCount != 1) |
| 126 return false; |
| 127 |
| 128 const size_t number_of_colors = 2; |
| 129 |
| 130 const size_t header_and_palette = |
| 131 sizeof(info.bmiHeader) + number_of_colors * sizeof(RGBQUAD); |
| 132 // When getting pixel data palette is appended to memory pointed by |
| 133 // BITMAPINFO passed so allocate additional memory to store additional data. |
| 134 scoped_ptr<BITMAPINFO> header( |
| 135 reinterpret_cast<BITMAPINFO*>(new char[header_and_palette])); |
| 136 if (header == nullptr) |
| 137 return false; |
| 138 memcpy(header.get(), &(info.bmiHeader), sizeof(info.bmiHeader)); |
| 139 |
| 140 bitmap_data_ = scoped_ptr<uint32>( |
| 141 new uint32[info.bmiHeader.biSizeImage / sizeof(uint32)]); |
| 142 if (bitmap_data_ == nullptr) |
| 143 return false; |
| 144 |
| 145 int result = GetDIBits(hdc_, |
| 146 handle, |
| 147 0, |
| 148 info.bmiHeader.biHeight, |
| 149 bitmap_data_.get(), |
| 150 header.get(), |
| 151 DIB_RGB_COLORS); |
| 152 |
| 153 return result != 0; |
| 154 } |
| 155 |
| 156 bool CursorVisibleHeightCalculator::IsRowTransparent(uint32 y) const { |
| 157 // Set the padding bits to 1 to make mask matching easier. |
| 158 *(bitmap_data_.get() + (y + 1)* row_size_ - 1) |= last_byte_mask_; |
| 159 for (uint32 i = y * row_size_; i < (y + 1) * row_size_; ++i) { |
| 160 if (*(bitmap_data_.get() + i) != transparent_mask) |
| 161 return false; |
| 162 } |
| 163 return true; |
| 164 } |
| 165 |
| 166 } // namespace |
| 167 |
| 168 namespace views { |
| 169 namespace corewm { |
| 170 |
| 171 int CursorHeightProvider::GetCursorHeight() { |
| 172 CURSORINFO cursor = {0}; |
| 173 cursor.cbSize = sizeof(cursor); |
| 174 GetCursorInfo(&cursor); |
| 175 |
| 176 HeightStorage::const_iterator cached_height = |
| 177 cached_heights_.find(cursor.hCursor); |
| 178 if (cached_height != cached_heights_.end()) |
| 179 return cached_height->second; |
| 180 |
| 181 CursorVisibleHeightCalculator cursor_data(cursor.hCursor); |
| 182 cached_heights_[cursor.hCursor] = cursor_data.visible_height(); |
| 183 |
| 184 return cursor_data.visible_height(); |
| 185 } |
| 186 |
| 187 } // namespace corewm |
| 188 } // namespace views |
OLD | NEW |