blob: b8f3eeb1290e6b9102b2d63049a84c19cde3bdc2 [file] [log] [blame]
// Copyright 2018 The Cobalt Authors. 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/dom/screenshot_manager.h"
#include <memory>
#include <utility>
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "cobalt/dom/screenshot.h"
#include "cobalt/render_tree/node.h"
#include "cobalt/render_tree/resource_provider_stub.h"
#include "cobalt/script/array_buffer.h"
#include "cobalt/web/context.h"
#include "cobalt/web/environment_settings.h"
namespace cobalt {
namespace dom {
ScreenshotManager::ScreenshotManager(
script::EnvironmentSettings* settings,
const ScreenshotManager::ProvideScreenshotFunctionCallback&
screenshot_function_callback)
: environment_settings_(settings),
screenshot_function_callback_(screenshot_function_callback) {}
void ScreenshotManager::Screenshot(
loader::image::EncodedStaticImage::ImageFormat desired_format,
const scoped_refptr<render_tree::Node>& render_tree_root,
std::unique_ptr<ScreenshotManager::InterfacePromiseValue::Reference>
promise_reference) {
DLOG(INFO) << "Will take a screenshot asynchronously";
DCHECK(!screenshot_function_callback_.is_null());
// We want to ScreenshotManager::FillScreenshot, on this thread.
base::Callback<void(std::unique_ptr<uint8[]>, const math::Size&)>
fill_screenshot = base::Bind(
&ScreenshotManager::FillScreenshot, base::Unretained(this),
next_ticket_id_, base::ThreadTaskRunnerHandle::Get(), desired_format);
bool was_emplaced =
ticket_to_screenshot_promise_map_
.emplace(next_ticket_id_, std::move(promise_reference))
.second;
DCHECK(was_emplaced);
++next_ticket_id_;
screenshot_function_callback_.Run(
render_tree_root, /*clip_rect=*/base::nullopt, fill_screenshot);
}
void ScreenshotManager::FillScreenshot(
int64_t token,
scoped_refptr<base::SingleThreadTaskRunner> expected_task_runner,
loader::image::EncodedStaticImage::ImageFormat desired_format,
std::unique_ptr<uint8[]> image_data, const math::Size& image_dimensions) {
if (expected_task_runner && !expected_task_runner->BelongsToCurrentThread()) {
expected_task_runner->PostTask(
FROM_HERE,
base::Bind(&ScreenshotManager::FillScreenshot, base::Unretained(this),
token, expected_task_runner, desired_format,
base::Passed(&image_data), image_dimensions));
return;
}
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(environment_settings_);
auto iterator = ticket_to_screenshot_promise_map_.find(token);
DCHECK(iterator != ticket_to_screenshot_promise_map_.end());
const script::Promise<scoped_refptr<script::Wrappable>>& promise =
iterator->second->value();
do {
if (!image_data) {
// There was no data for the screenshot.
LOG(WARNING) << "There was no data for the screenshot.";
promise.Reject();
break;
}
scoped_refptr<loader::image::EncodedStaticImage> encoded_image_data =
CompressRGBAImage(desired_format, image_data.get(), image_dimensions);
size_t encoded_size = encoded_image_data->GetEstimatedSizeInBytes();
if (encoded_image_data->GetEstimatedSizeInBytes() > kint32max) {
NOTREACHED();
promise.Reject();
break;
}
DLOG(INFO) << "Filling data in for the screenshot.";
script::Handle<script::ArrayBuffer> pixel_data = script::ArrayBuffer::New(
base::polymorphic_downcast<web::EnvironmentSettings*>(
environment_settings_)
->context()
->global_environment(),
encoded_image_data->GetMemory(), encoded_size);
scoped_refptr<script::Wrappable> promise_result =
new dom::Screenshot(pixel_data);
promise.Resolve(promise_result);
} while (0);
DCHECK(promise.State() != script::PromiseState::kPending);
// Drop the reference to the promise since it will not be used.
ticket_to_screenshot_promise_map_.erase(iterator);
}
} // namespace dom
} // namespace cobalt