| // Copyright 2024 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/browser/ui/ash/picker/picker_thumbnail_loader.h" |
| |
| #include <optional> |
| |
| #include "base/files/file_path.h" |
| #include "chrome/browser/ash/drive/drive_integration_service.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "ipc/ipc_channel.h" |
| #include "services/data_decoder/public/cpp/decode_image.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace { |
| |
| constexpr int64_t kMaxImageSizeInBytes = |
| static_cast<int64_t>(IPC::Channel::kMaximumMessageSize); |
| |
| std::optional<base::FilePath> MaybeGetDriveFileRelativePath( |
| drive::DriveIntegrationService& drive_integration, |
| const base::FilePath& path) { |
| base::FilePath relative_path; |
| if (!drive_integration.GetRelativeDrivePath(path, &relative_path)) { |
| return std::nullopt; |
| } |
| return relative_path; |
| } |
| |
| } // namespace |
| |
| PickerThumbnailLoader::PickerThumbnailLoader(Profile* profile) |
| : profile_(profile), thumbnail_loader_(profile) {} |
| |
| PickerThumbnailLoader::~PickerThumbnailLoader() = default; |
| |
| void PickerThumbnailLoader::Load(const base::FilePath& path, |
| const gfx::Size& size, |
| LoadCallback callback) { |
| // If the file is a drive file, use DriveFS to get the thumbnail. |
| if (drive::DriveIntegrationService* drive_integration = |
| drive::DriveIntegrationServiceFactory::FindForProfile(profile_)) { |
| if (std::optional<base::FilePath> relative_path = |
| MaybeGetDriveFileRelativePath(*drive_integration, path); |
| relative_path.has_value()) { |
| drive_integration->GetThumbnail( |
| *relative_path, /*crop_to_square=*/true, |
| base::BindOnce(&PickerThumbnailLoader::DecodeDriveThumbnail, |
| weak_factory_.GetWeakPtr(), std::move(callback), |
| size)); |
| return; |
| } |
| } |
| |
| // Fallback to the thumbnail loader extension. |
| thumbnail_loader_.Load({path, size}, std::move(callback)); |
| } |
| |
| void PickerThumbnailLoader::DecodeDriveThumbnail( |
| LoadCallback callback, |
| const gfx::Size& size, |
| const std::optional<std::vector<uint8_t>>& bytes) { |
| if (!bytes.has_value()) { |
| std::move(callback).Run(nullptr, base::File::Error::FILE_ERROR_FAILED); |
| return; |
| } |
| |
| data_decoder::DecodeImageIsolated( |
| *bytes, data_decoder::mojom::ImageCodec::kPng, |
| /*shrink_to_fit=*/true, kMaxImageSizeInBytes, size, |
| base::BindOnce(&PickerThumbnailLoader::OnDriveThumbnailDecoded, |
| weak_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| |
| void PickerThumbnailLoader::OnDriveThumbnailDecoded(LoadCallback callback, |
| const SkBitmap& image) { |
| if (image.empty()) { |
| std::move(callback).Run(nullptr, base::File::Error::FILE_ERROR_FAILED); |
| return; |
| } |
| std::move(callback).Run(&image, base::File::Error::FILE_OK); |
| } |