blob: e534c768e207d54e1666e6b7cf9bb76d54a4701a [file] [log] [blame]
// Copyright 2015 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/browser/screen_shot_writer.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "cobalt/renderer/test/png_utils/png_encode.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"
using cobalt::renderer::test::png_utils::EncodeRGBAToBuffer;
namespace cobalt {
namespace browser {
namespace {
scoped_array<uint8> WriteRGBAPixelsToPNG(scoped_array<uint8> pixel_data,
const math::Size& dimensions,
size_t* out_num_bytes) {
// Given a chunk of memory formatted as RGBA8 with pitch = width * 4, this
// function will wrap that memory in a SkBitmap that does *not* own the
// pixels and return that.
const int kRGBABytesPerPixel = 4;
SkBitmap bitmap;
bitmap.installPixels(
SkImageInfo::Make(dimensions.width(), dimensions.height(),
kRGBA_8888_SkColorType, kUnpremul_SkAlphaType),
const_cast<uint8_t*>(pixel_data.get()),
dimensions.width() * kRGBABytesPerPixel);
// No conversion needed here, simply write out the pixels as is.
return EncodeRGBAToBuffer(static_cast<uint8_t*>(bitmap.pixelRef()->pixels()),
bitmap.width(), bitmap.height(),
static_cast<int>(bitmap.rowBytes()), out_num_bytes);
}
} // namespace
ScreenShotWriter::ScreenShotWriter(renderer::Pipeline* pipeline)
: pipeline_(pipeline),
screenshot_thread_("Screenshot IO thread") {
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
screenshot_thread_.StartWithOptions(options);
}
void ScreenShotWriter::RequestScreenshot(const FilePath& output_path,
const base::Closure& complete) {
RequestScreenshotToMemory(base::Bind(&ScreenShotWriter::EncodingComplete,
base::Unretained(this), output_path,
complete));
}
void ScreenShotWriter::RequestScreenshotToMemory(
const PNGEncodeCompleteCallback& callback) {
DCHECK(!callback.is_null());
DCHECK(last_submission_);
renderer::Submission submission(last_submission_.value());
submission.time_offset +=
base::TimeTicks::HighResNow() - last_submission_time_;
pipeline_->RasterizeToRGBAPixels(
submission, base::Bind(&ScreenShotWriter::RasterizationComplete,
base::Unretained(this), callback));
}
void ScreenShotWriter::SetLastPipelineSubmission(
const renderer::Submission& submission) {
DCHECK(submission.render_tree.get());
last_submission_ = submission;
last_submission_time_ = base::TimeTicks::HighResNow();
}
void ScreenShotWriter::ClearLastPipelineSubmission() {
last_submission_ = base::nullopt;
}
void ScreenShotWriter::RasterizationComplete(
const PNGEncodeCompleteCallback& encode_complete_callback,
scoped_array<uint8> pixel_data, const math::Size& dimensions) {
if (MessageLoop::current() != screenshot_thread_.message_loop()) {
screenshot_thread_.message_loop()->PostTask(
FROM_HERE, base::Bind(&ScreenShotWriter::RasterizationComplete,
base::Unretained(this), encode_complete_callback,
base::Passed(&pixel_data), dimensions));
return;
}
size_t num_bytes;
scoped_array<uint8> png_data =
WriteRGBAPixelsToPNG(pixel_data.Pass(), dimensions, &num_bytes);
encode_complete_callback.Run(png_data.Pass(), num_bytes);
}
void ScreenShotWriter::EncodingComplete(const FilePath& output_path,
const base::Closure& complete_callback,
scoped_array<uint8> png_data,
size_t num_bytes) {
DCHECK_EQ(MessageLoop::current(), screenshot_thread_.message_loop());
// Blocking write to output_path.
int bytes_written =
file_util::WriteFile(output_path, reinterpret_cast<char*>(png_data.get()),
static_cast<int>(num_bytes));
DLOG_IF(ERROR, bytes_written != num_bytes) << "Error writing PNG to file.";
// Notify the caller that the screenshot is complete.
if (!complete_callback.is_null()) {
complete_callback.Run();
}
}
} // namespace browser
} // namespace cobalt