blob: b996c0b0737a1fd15e13abf9b45f6c26800cebd3 [file] [log] [blame]
// 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 "chrome/browser/ui/views/elevation_icon_setter.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/task/post_task.h"
#include "build/build_config.h"
#include "ui/views/controls/button/label_button.h"
#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#include "base/task_runner_util.h"
#include "base/win/win_util.h"
#include "ui/display/win/dpi.h"
#include "ui/gfx/icon_util.h"
#endif
// Helpers --------------------------------------------------------------------
namespace {
#if defined(OS_WIN)
SkBitmap GetElevationIcon() {
if (!base::win::UserAccountControlIsEnabled())
return SkBitmap();
SHSTOCKICONINFO icon_info = { sizeof(SHSTOCKICONINFO) };
typedef HRESULT (STDAPICALLTYPE *GetStockIconInfo)(SHSTOCKICONID,
UINT,
SHSTOCKICONINFO*);
// Even with the runtime guard above, we have to use GetProcAddress()
// here, because otherwise the loader will try to resolve the function
// address on startup, which will break on XP.
GetStockIconInfo func = reinterpret_cast<GetStockIconInfo>(
GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHGetStockIconInfo"));
// TODO(pkasting): Run on a background thread since this call spins a nested
// message loop.
if (FAILED((*func)(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &icon_info)))
return SkBitmap();
SkBitmap icon = IconUtil::CreateSkBitmapFromHICON(
icon_info.hIcon,
gfx::Size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)));
DestroyIcon(icon_info.hIcon);
return icon;
}
#endif
} // namespace
// ElevationIconSetter --------------------------------------------------------
ElevationIconSetter::ElevationIconSetter(views::LabelButton* button,
base::OnceClosure callback)
: button_(button), weak_factory_(this) {
#if defined(OS_WIN)
base::PostTaskAndReplyWithResult(
base::CreateCOMSTATaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::USER_BLOCKING})
.get(),
FROM_HERE, base::BindOnce(&GetElevationIcon),
base::BindOnce(&ElevationIconSetter::SetButtonIcon,
weak_factory_.GetWeakPtr(), std::move(callback)));
#endif
}
ElevationIconSetter::~ElevationIconSetter() {
}
void ElevationIconSetter::SetButtonIcon(base::OnceClosure callback,
const SkBitmap& icon) {
if (!icon.isNull()) {
float device_scale_factor = 1.0f;
#if defined(OS_WIN)
// Windows gives us back a correctly-scaled image for the current DPI, so
// mark this image as having been scaled for the current DPI already.
device_scale_factor = display::win::GetDPIScale();
#endif
button_->SetImage(
views::Button::STATE_NORMAL,
gfx::ImageSkia(gfx::ImageSkiaRep(icon, device_scale_factor)));
button_->SizeToPreferredSize();
if (button_->parent())
button_->parent()->Layout();
if (!callback.is_null())
std::move(callback).Run();
}
}