| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..742f1cd2dd110840a7939e7744e316a714b4b80a
|
| --- /dev/null
|
| +++ b/ui/views/corewm/cursor_height_provider_win.cc
|
| @@ -0,0 +1,188 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ui/views/corewm/cursor_height_provider_win.h"
|
| +
|
| +#include <windows.h>
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/win/scoped_hdc.h"
|
| +
|
| +namespace {
|
| +const uint32 bits_per_uint32 = 32;
|
| +// All bits are 1 for transparent portion of monochromatic mask.
|
| +const uint32 transparent_mask = 0xffffffff;
|
| +// This is height of default pointer arrow in Windows 7.
|
| +const int default_height = 20;
|
| +
|
| +/**
|
| + * Gets the vertical offset between specified cursor's hotpoint and it's bottom.
|
| + *
|
| + * Gets the cursor image data and extract cursor's visible height.
|
| + * Based on that get's what should be the vertical offset between cursor's
|
| + * hot point and the tooltip.
|
| + */
|
| +class CursorVisibleHeightCalculator {
|
| + public:
|
| + explicit CursorVisibleHeightCalculator(HCURSOR cursor_handle);
|
| + int visible_height() const { return visible_height_; }
|
| +
|
| + private:
|
| + /**
|
| + * Extracts the cursor data and calculates the visible height.
|
| + */
|
| + void Init(HCURSOR cursor_handle);
|
| +
|
| + /**
|
| + * Fills the BITMAPINFO structure for specified bitmap @p handle.
|
| + * @param handle Handle to bitmap that's being examined.
|
| + * @param info Pointer to BITMAPINFO structure that'll receive the output.
|
| + * @return true if no error occured.
|
| + */
|
| + bool GetBitmapInfo(HBITMAP handle, BITMAPINFO* info);
|
| +
|
| + /**
|
| + * Fills the bitmap_data_ member with pixel data for bitmap
|
| + * specified by @p handle in format described through @p info.
|
| + * @param handle Handle to bitmap that's being examined.
|
| + * @param info BITMAPINFO structure that describes the output format.
|
| + * @return true if no error occured.
|
| + */
|
| + bool GetBitmapData(HBITMAP handle, const BITMAPINFO& info);
|
| +
|
| + /**
|
| + * Checks if the row on specified index is fully transparent.
|
| + * @param y row index.
|
| + * @return true if the row is considered transparent.
|
| + */
|
| + bool IsRowTransparent(uint32 y) const;
|
| +
|
| + base::win::ScopedGetDC hdc_;
|
| + // Row size in DWORDs.
|
| + uint32 row_size_;
|
| + // Since bitmap is padded to full DWORD OR it with this bitmask
|
| + // to remove the padding noise.
|
| + uint32 last_byte_mask_;
|
| + // Pointer that receives memory block containing bitmap pixel data.
|
| + scoped_ptr<uint32> bitmap_data_;
|
| + int visible_height_;
|
| +};
|
| +
|
| +CursorVisibleHeightCalculator::CursorVisibleHeightCalculator(
|
| + HCURSOR cursor_handle)
|
| + : hdc_(NULL),
|
| + row_size_(0),
|
| + last_byte_mask_(0),
|
| + visible_height_(default_height) {
|
| + Init(cursor_handle);
|
| +}
|
| +
|
| +void CursorVisibleHeightCalculator::Init(HCURSOR cursor_handle) {
|
| + ICONINFO icon = {0};
|
| + GetIconInfo(cursor_handle, &icon);
|
| +
|
| + BITMAPINFO info = {0};
|
| + if (!GetBitmapInfo(icon.hbmMask, &info))
|
| + return;
|
| +
|
| + // Rows are padded to full DWORDs. OR with this mask will set them to 1
|
| + // to simplify matching with |transparent_mask|.
|
| + last_byte_mask_ = ~0;
|
| + last_byte_mask_ = last_byte_mask_
|
| + << (sizeof(last_byte_mask_) * 8 -
|
| + (info.bmiHeader.biWidth % bits_per_uint32));
|
| +
|
| + row_size_ = (info.bmiHeader.biWidth + bits_per_uint32 - 1) / bits_per_uint32;
|
| + if (!GetBitmapData(icon.hbmMask, info))
|
| + return;
|
| + const int cursor_height = GetSystemMetrics(SM_CYCURSOR);
|
| + int i = info.bmiHeader.biHeight - cursor_height;
|
| + for (; i < info.bmiHeader.biHeight; ++i) {
|
| + if (!IsRowTransparent(i)) {
|
| + i--;
|
| + break;
|
| + }
|
| + }
|
| + bitmap_data_.reset();
|
| + visible_height_ = info.bmiHeader.biHeight - i - icon.yHotspot;
|
| +}
|
| +
|
| +bool CursorVisibleHeightCalculator::GetBitmapInfo(HBITMAP handle,
|
| + BITMAPINFO* info) {
|
| + info->bmiHeader.biSize = sizeof(info->bmiHeader);
|
| + info->bmiHeader.biBitCount = 0;
|
| +
|
| + int result = GetDIBits(hdc_, handle, 0, 0, NULL, info, DIB_RGB_COLORS);
|
| + return result != 0;
|
| +}
|
| +
|
| +bool CursorVisibleHeightCalculator::GetBitmapData(HBITMAP handle,
|
| + const BITMAPINFO& info) {
|
| + // Masks are monochromatic.
|
| + DCHECK_EQ(info.bmiHeader.biBitCount, 1);
|
| + if (info.bmiHeader.biBitCount != 1)
|
| + return false;
|
| +
|
| + const size_t number_of_colors = 2;
|
| +
|
| + const size_t header_and_palette =
|
| + sizeof(info.bmiHeader) + number_of_colors * sizeof(RGBQUAD);
|
| + // When getting pixel data palette is appended to memory pointed by
|
| + // BITMAPINFO passed so allocate additional memory to store additional data.
|
| + scoped_ptr<BITMAPINFO> header(
|
| + reinterpret_cast<BITMAPINFO*>(new char[header_and_palette]));
|
| + if (header == nullptr)
|
| + return false;
|
| + memcpy(header.get(), &(info.bmiHeader), sizeof(info.bmiHeader));
|
| +
|
| + bitmap_data_ = scoped_ptr<uint32>(
|
| + new uint32[info.bmiHeader.biSizeImage / sizeof(uint32)]);
|
| + if (bitmap_data_ == nullptr)
|
| + return false;
|
| +
|
| + int result = GetDIBits(hdc_,
|
| + handle,
|
| + 0,
|
| + info.bmiHeader.biHeight,
|
| + bitmap_data_.get(),
|
| + header.get(),
|
| + DIB_RGB_COLORS);
|
| +
|
| + return result != 0;
|
| +}
|
| +
|
| +bool CursorVisibleHeightCalculator::IsRowTransparent(uint32 y) const {
|
| + // Set the padding bits to 1 to make mask matching easier.
|
| + *(bitmap_data_.get() + (y + 1)* row_size_ - 1) |= last_byte_mask_;
|
| + for (uint32 i = y * row_size_; i < (y + 1) * row_size_; ++i) {
|
| + if (*(bitmap_data_.get() + i) != transparent_mask)
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace views {
|
| +namespace corewm {
|
| +
|
| +int CursorHeightProvider::GetCursorHeight() {
|
| + CURSORINFO cursor = {0};
|
| + cursor.cbSize = sizeof(cursor);
|
| + GetCursorInfo(&cursor);
|
| +
|
| + HeightStorage::const_iterator cached_height =
|
| + cached_heights_.find(cursor.hCursor);
|
| + if (cached_height != cached_heights_.end())
|
| + return cached_height->second;
|
| +
|
| + CursorVisibleHeightCalculator cursor_data(cursor.hCursor);
|
| + cached_heights_[cursor.hCursor] = cursor_data.visible_height();
|
| +
|
| + return cursor_data.visible_height();
|
| +}
|
| +
|
| +} // namespace corewm
|
| +} // namespace views
|
|
|