blob: e5bab9cc5cf10d2fd6cab0b155a53f6816ba8bdd [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_
#define CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_
#include <map>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "ui/gfx/geometry/size.h"
namespace data_decoder {
class DataDecoder;
} // namespace data_decoder
namespace gfx {
class Size;
} // namespace gfx
class SkBitmap;
// This is a helper class for decoding images safely in a sandboxed service. To
// use this, call ImageDecoder::Start(...) or
// ImageDecoder::StartWithOptions(...) on any thread.
//
// ImageRequest::OnImageDecoded or ImageRequest::OnDecodeImageFailed is posted
// back to the |task_runner_| associated with the ImageRequest.
//
// The Cancel() method runs on whichever thread called it.
//
// TODO(rockot): Use of this class should be replaced with direct image_decoder
// client library usage.
class ImageDecoder {
public:
// ImageRequest objects needs to be created and destroyed on the same
// SequencedTaskRunner.
class ImageRequest {
public:
// Called when image is decoded.
virtual void OnImageDecoded(const SkBitmap& decoded_image) = 0;
// Called when decoding image failed. ImageRequest can do some cleanup in
// this handler.
virtual void OnDecodeImageFailed() {}
base::SequencedTaskRunner* task_runner() const {
return task_runner_.get();
}
data_decoder::DataDecoder* data_decoder() { return data_decoder_; }
protected:
// Creates an ImageRequest that runs on the thread which created it.
ImageRequest();
// Explicitly pass in |task_runner| if the current thread is part of a
// thread pool.
explicit ImageRequest(
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
// Explicitly pass in |data_decoder| if there's a specific decoder that
// should be used; otherwise, an isolated decoder will created and used.
explicit ImageRequest(data_decoder::DataDecoder* data_decoder);
virtual ~ImageRequest();
private:
// The thread to post OnImageDecoded() or OnDecodeImageFailed() once the
// the image has been decoded.
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
// If null, will use a new decoder via DecodeImageIsolated() instead.
const raw_ptr<data_decoder::DataDecoder> data_decoder_ = nullptr;
SEQUENCE_CHECKER(sequence_checker_);
};
enum ImageCodec {
DEFAULT_CODEC = 0, // Uses WebKit image decoding (via WebImage).
#if BUILDFLAG(IS_CHROMEOS)
PNG_CODEC, // Restrict decoding to libpng.
#endif
};
static ImageDecoder* GetInstance();
ImageDecoder(const ImageDecoder&) = delete;
ImageDecoder& operator=(const ImageDecoder&) = delete;
// Calls StartWithOptions() with default options.
// ImageDataType can be std::vector<uint8_t> or std::string.
template <typename ImageDataType>
static void Start(ImageRequest* image_request, ImageDataType image_data);
// Starts asynchronous image decoding. Once finished, the callback will be
// posted back to image_request's |task_runner_|.
// For images with multiple frames (e.g. ico files), a frame with a size as
// close as possible to |desired_image_frame_size| is chosen (tries to take
// one in larger size if there's no precise match). Passing gfx::Size() as
// |desired_image_frame_size| is also supported and will result in chosing the
// smallest available size.
template <typename ImageDataType>
static void StartWithOptions(
ImageRequest* image_request,
ImageDataType image_data,
ImageCodec image_codec = DEFAULT_CODEC,
bool shrink_to_fit = false,
const gfx::Size& desired_image_frame_size = gfx::Size());
// Removes all instances of |image_request| from |image_request_id_map_|,
// ensuring callbacks are not made to the image_request after it is destroyed.
static void Cancel(ImageRequest* image_request);
private:
friend base::NoDestructor<ImageDecoder>;
using RequestMap = std::map<int, raw_ptr<ImageRequest, CtnExperimental>>;
ImageDecoder();
~ImageDecoder() = delete;
template <typename ImageDataType>
void StartWithOptionsImpl(ImageRequest* image_request,
ImageDataType image_data,
ImageCodec image_codec,
bool shrink_to_fit,
const gfx::Size& desired_image_frame_size);
void CancelImpl(ImageRequest* image_request);
// IPC message handlers.
void OnDecodeImageSucceeded(const SkBitmap& decoded_image, int request_id);
void OnDecodeImageFailed(int request_id);
// id to use for the next Start() request that comes in.
int image_request_id_counter_;
// Map of request id's to ImageRequests.
RequestMap image_request_id_map_;
// Protects |image_request_id_map_| and |image_request_id_counter_|.
base::Lock map_lock_;
};
#endif // CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_