1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/image_fetcher/core/image_fetcher_impl.h"
#include <string>
#include "base/functional/bind.h"
#include "base/task/single_thread_task_runner.h"
#include "net/base/load_flags.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "ui/gfx/image/image.h"
namespace image_fetcher {
ImageFetcherImpl::ImageFetcherImpl(
std::unique_ptr<ImageDecoder> image_decoder,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: url_loader_factory_(url_loader_factory),
image_decoder_(std::move(image_decoder)),
image_data_fetcher_(new ImageDataFetcher(url_loader_factory)) {}
ImageFetcherImpl::~ImageFetcherImpl() = default;
ImageFetcherImpl::ImageRequest::ImageRequest() = default;
ImageFetcherImpl::ImageRequest::ImageRequest(ImageRequest&& other) = default;
ImageFetcherImpl::ImageRequest::~ImageRequest() = default;
void ImageFetcherImpl::FetchImageAndData(
const GURL& image_url,
ImageDataFetcherCallback image_data_callback,
ImageFetcherCallback image_callback,
ImageFetcherParams params) {
// Before starting to fetch the image. Look for a request in progress for
// `image_url`, and queue if appropriate.
auto it = pending_net_requests_.find(image_url);
if (it == pending_net_requests_.end()) {
ImageRequest request;
request.id = image_url.spec();
if (image_callback) {
request.image_callbacks.push_back(std::move(image_callback));
}
if (image_data_callback) {
request.image_data_callbacks.push_back(std::move(image_data_callback));
}
pending_net_requests_.emplace(image_url, std::move(request));
image_data_fetcher_->SetImageDownloadLimit(params.max_download_size());
image_data_fetcher_->FetchImageData(
image_url,
base::BindOnce(&ImageFetcherImpl::OnImageURLFetched,
base::Unretained(this), image_url, params),
params);
} else {
ImageRequest* request = &it->second;
// Request in progress. Register as an interested callback.
// TODO(treib,markusheintz): We're not guaranteed that the ID also matches.
// We probably have to store them all.
if (image_callback) {
request->image_callbacks.push_back(std::move(image_callback));
}
// Call callback if data is already fetched, otherwise register it for
// later.
if (image_data_callback) {
if (!request->image_data.empty()) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ImageFetcherImpl::RunImageDataCallback,
weak_ptr_factory_.GetWeakPtr(),
std::move(image_data_callback), request->image_data,
request->request_metadata));
} else {
request->image_data_callbacks.push_back(std::move(image_data_callback));
}
}
}
}
void ImageFetcherImpl::OnImageURLFetched(const GURL& image_url,
ImageFetcherParams params,
const std::string& image_data,
const RequestMetadata& metadata) {
auto it = pending_net_requests_.find(image_url);
CHECK(it != pending_net_requests_.end());
ImageRequest* request = &it->second;
DCHECK(request->image_data.empty());
DCHECK_EQ(RequestMetadata::RESPONSE_CODE_INVALID,
request->request_metadata.http_response_code);
for (auto& callback : request->image_data_callbacks) {
std::move(callback).Run(image_data, metadata);
}
request->image_data_callbacks.clear();
if (image_data.empty() || request->image_callbacks.empty()) {
for (auto& callback : request->image_callbacks) {
std::move(callback).Run(gfx::Image(), metadata);
}
pending_net_requests_.erase(it);
return;
}
request->image_data = image_data;
request->request_metadata = metadata;
image_decoder_->DecodeImage(
image_data, params.frame_size(), params.data_decoder(),
base::BindOnce(&ImageFetcherImpl::OnImageDecoded,
weak_ptr_factory_.GetWeakPtr(), image_url, metadata));
}
void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
const RequestMetadata& metadata,
const gfx::Image& image) {
// Get request for the given image_url from the request queue.
auto image_iter = pending_net_requests_.find(image_url);
CHECK(image_iter != pending_net_requests_.end());
ImageRequest* request = &image_iter->second;
// Run all image callbacks.
for (auto& callback : request->image_callbacks) {
std::move(callback).Run(image, metadata);
}
// Erase the completed ImageRequest.
DCHECK(request->image_data_callbacks.empty());
pending_net_requests_.erase(image_iter);
}
void ImageFetcherImpl::RunImageDataCallback(
ImageDataFetcherCallback image_data_callback,
std::string image_data,
RequestMetadata request_metadata) {
std::move(image_data_callback)
.Run(std::move(image_data), std::move(request_metadata));
}
ImageDecoder* ImageFetcherImpl::GetImageDecoder() {
return image_decoder_.get();
}
} // namespace image_fetcher
|