blob: dd71f65885e4032fd1ae06e83dea6550527a870b [file] [log] [blame]
// Copyright 2018 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/dom/screenshot_manager.h"
#include "base/time.h"
#include "cobalt/dom/screenshot.h"
#include "cobalt/render_tree/node.h"
#include "cobalt/script/array_buffer.h"
#include "cobalt/render_tree/resource_provider_stub.h"
namespace cobalt {
namespace dom {
ScreenshotManager::ScreenshotManager(
const ScreenshotManager::ProvideScreenshotFunctionCallback&
screenshot_function_callback)
: 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(scoped_array<uint8>, const math::Size&)> fill_screenshot =
base::Bind(&ScreenshotManager::FillScreenshot, base::Unretained(this),
next_ticket_id_, base::MessageLoopProxy::current(),
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, fill_screenshot);
}
void ScreenshotManager::SetEnvironmentSettings(
script::EnvironmentSettings* settings) {
environment_settings_ = settings;
}
void ScreenshotManager::FillScreenshot(
int64_t token, scoped_refptr<base::MessageLoopProxy> expected_message_loop,
loader::image::EncodedStaticImage::ImageFormat desired_format,
scoped_array<uint8> image_data, const math::Size& image_dimensions) {
if (base::MessageLoopProxy::current() != expected_message_loop) {
expected_message_loop->PostTask(
FROM_HERE,
base::Bind(&ScreenshotManager::FillScreenshot, base::Unretained(this),
token, expected_message_loop, desired_format,
base::Passed(&image_data), image_dimensions));
return;
}
DCHECK(thread_checker_.CalledOnValidThread());
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.";
DOMSettings* dom_settings =
base::polymorphic_downcast<dom::DOMSettings*>(environment_settings_);
script::Handle<script::ArrayBuffer> pixel_data =
script::ArrayBuffer::New(dom_settings->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