blob: e4c26ac7b456b6f8a56ee53e26a3e718e22971ac [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/loader/image/threaded_image_decoder_proxy.h"
#include <string>
#include "base/bind.h"
#include "base/threading/thread.h"
#include "cobalt/loader/image/image_decoder.h"
namespace cobalt {
namespace loader {
namespace image {
namespace {
// Helper function that is run on the WebModule thread to run a Callback if
// and only if |threaded_image_decoder_proxy| is still alive.
template <typename Callback, typename Arg>
void MaybeRun(
base::WeakPtr<ThreadedImageDecoderProxy> threaded_image_decoder_proxy,
const Callback& callback, const Arg& arg) {
if (threaded_image_decoder_proxy) {
callback.Run(arg);
}
}
// Helper function to post a Callback back to the WebModule thread, that
// checks whether the ThreadedImageDecoderProxy it came from is alive or not
// before it runs.
template <typename Callback, typename Arg>
void PostToMessageLoopChecked(
base::WeakPtr<ThreadedImageDecoderProxy> threaded_image_decoder_proxy,
const Callback& callback, MessageLoop* message_loop, const Arg& arg) {
message_loop->PostTask(
FROM_HERE, base::Bind(&MaybeRun<Callback, Arg>,
threaded_image_decoder_proxy, callback, arg));
}
} // namespace
ThreadedImageDecoderProxy::ThreadedImageDecoderProxy(
render_tree::ResourceProvider* resource_provider,
const SuccessCallback& success_callback,
const ErrorCallback& error_callback, MessageLoop* load_message_loop)
: ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(
weak_this_(weak_ptr_factory_.GetWeakPtr())),
load_message_loop_(load_message_loop),
result_message_loop_(MessageLoop::current()),
image_decoder_(new ImageDecoder(
resource_provider,
base::Bind(
&PostToMessageLoopChecked<SuccessCallback, scoped_refptr<Image> >,
weak_this_, success_callback, result_message_loop_),
base::Bind(&PostToMessageLoopChecked<ErrorCallback, std::string>,
weak_this_, error_callback, result_message_loop_))) {
DCHECK(load_message_loop_);
DCHECK(result_message_loop_);
DCHECK(image_decoder_);
}
// We're dying, but |image_decoder_| might still be doing work on the load
// thread. Because of this, we transfer ownership of it into the load message
// loop, where it will be deleted after any pending tasks involving it are
// done.
ThreadedImageDecoderProxy::~ThreadedImageDecoderProxy() {
// Notify the ImageDecoder that there's a pending deletion to ensure that no
// additional work is done decoding the image.
image_decoder_->SetDeletionPending();
load_message_loop_->DeleteSoon(FROM_HERE, image_decoder_.release());
}
LoadResponseType ThreadedImageDecoderProxy::OnResponseStarted(
Fetcher* fetcher, const scoped_refptr<net::HttpResponseHeaders>& headers) {
UNREFERENCED_PARAMETER(fetcher);
return image_decoder_->OnResponseStarted(fetcher, headers);
}
void ThreadedImageDecoderProxy::DecodeChunk(const char* data, size_t size) {
scoped_ptr<std::string> scoped_data(new std::string(data, size));
load_message_loop_->PostTask(
FROM_HERE, base::Bind(&Decoder::DecodeChunkPassed,
base::Unretained(image_decoder_.get()),
base::Passed(&scoped_data)));
}
void ThreadedImageDecoderProxy::DecodeChunkPassed(
scoped_ptr<std::string> data) {
load_message_loop_->PostTask(
FROM_HERE,
base::Bind(&Decoder::DecodeChunkPassed,
base::Unretained(image_decoder_.get()), base::Passed(&data)));
}
void ThreadedImageDecoderProxy::Finish() {
load_message_loop_->PostTask(
FROM_HERE, base::Bind(&ImageDecoder::Finish,
base::Unretained(image_decoder_.get())));
}
bool ThreadedImageDecoderProxy::Suspend() {
load_message_loop_->PostTask(
FROM_HERE, base::Bind(base::IgnoreResult(&ImageDecoder::Suspend),
base::Unretained(image_decoder_.get())));
return true;
}
void ThreadedImageDecoderProxy::Resume(
render_tree::ResourceProvider* resource_provider) {
load_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ImageDecoder::Resume, base::Unretained(image_decoder_.get()),
resource_provider));
}
} // namespace image
} // namespace loader
} // namespace cobalt