chromium/chrome/services/util_win/util_read_icon.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/services/util_win/util_read_icon.h"

#include <windows.h>

#include <string.h>

#include <utility>

#include "base/files/file.h"
#include "base/files/memory_mapped_file.h"
#include "base/win/scoped_gdi_object.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/image/image_skia.h"

using chrome::mojom::IconSize;

namespace {

gfx::ImageSkia LoadIcon(base::File file, int size, float scale) {
  base::MemoryMappedFile map;
  if (!map.Initialize(std::move(file),
                      base::MemoryMappedFile::READ_CODE_IMAGE)) {
    return gfx::ImageSkia();
  }

  HMODULE library = reinterpret_cast<HMODULE>(map.data());
  // Find the first icon referenced in the file.  This matches Explorer.
  LPWSTR id = nullptr;
  // Because the lambda below returns FALSE, EnumResourceNames() itself will
  // return FALSE even when it "succeeds", so ignore its return value.
  ::EnumResourceNames(
      library, RT_GROUP_ICON,
      [](HMODULE, LPCWSTR, LPWSTR name, LONG_PTR param) {
        *reinterpret_cast<LPWSTR*>(param) =
            IS_INTRESOURCE(name) ? name : _wcsdup(name);
        return FALSE;
      },
      reinterpret_cast<LONG_PTR>(&id));

  base::win::ScopedHICON icon(static_cast<HICON>(
      ::LoadImage(library, id, IMAGE_ICON, size, size, LR_DEFAULTCOLOR)));
  if (!IS_INTRESOURCE(id))
    free(id);
  if (!icon.is_valid())
    return gfx::ImageSkia();

  const SkBitmap bitmap = IconUtil::CreateSkBitmapFromHICON(icon.get());
  if (bitmap.isNull())
    return gfx::ImageSkia();

  gfx::ImageSkia image_skia(gfx::ImageSkiaRep(bitmap, scale));
  image_skia.MakeThreadSafe();
  return image_skia;
}

}  // namespace

UtilReadIcon::UtilReadIcon(
    mojo::PendingReceiver<chrome::mojom::UtilReadIcon> receiver)
    : receiver_(this, std::move(receiver)) {}

UtilReadIcon::~UtilReadIcon() = default;

// This is exposed to the browser process only. |file| is a handle to
// a downloaded file, such as an |.exe|.
void UtilReadIcon::ReadIcon(base::File file,
                            IconSize icon_size,
                            float scale,
                            ReadIconCallback callback) {
  int size = 0;
  // See IconLoader::IconSize.
  switch (icon_size) {
    case IconSize::kSmall:
      size = 16;
      break;
    case IconSize::kNormal:
      size = 32;
      break;
    case IconSize::kLarge:
      size = 48;
      break;
    default:
      NOTREACHED_IN_MIGRATION();
  }
  std::move(callback).Run(LoadIcon(std::move(file), size * scale, scale));
}