blob: 9f7e33764a7ee744121cab964b927fdb05755d4f [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "screenshot.h"
#include <lib/zx/vmar.h>
#include <map>
#include <ostream>
#include <utility>
#include <vector>
#include "flutter/fml/logging.h"
namespace fuchsia_test_utils {
namespace {
constexpr uint64_t kBytesPerPixel = 4;
} // namespace
Screenshot::Screenshot(const zx::vmo& screenshot_vmo,
uint64_t width,
uint64_t height,
int rotation)
: width_(width), height_(height) {
FML_CHECK(rotation == 0 || rotation == 90 || rotation == 270);
if (rotation == 90 || rotation == 270) {
std::swap(width_, height_);
}
// Populate |screenshot_| from |screenshot_vmo|.
uint64_t vmo_size;
screenshot_vmo.get_prop_content_size(&vmo_size);
FML_CHECK(vmo_size == kBytesPerPixel * width_ * height_);
uint8_t* vmo_host = nullptr;
auto status = zx::vmar::root_self()->map(
ZX_VM_PERM_READ, /*vmar_offset*/ 0, screenshot_vmo,
/*vmo_offset*/ 0, vmo_size, reinterpret_cast<uintptr_t*>(&vmo_host));
FML_CHECK(status == ZX_OK);
ExtractScreenshotFromVMO(vmo_host);
// map the pointer.
uintptr_t address = reinterpret_cast<uintptr_t>(vmo_host);
status = zx::vmar::root_self()->unmap(address, vmo_size);
FML_CHECK(status == ZX_OK);
}
std::ostream& operator<<(std::ostream& stream, const Pixel& pixel) {
return stream << "{Pixel:" << " r:" << static_cast<unsigned int>(pixel.red)
<< " g:" << static_cast<unsigned int>(pixel.green)
<< " b:" << static_cast<unsigned int>(pixel.blue)
<< " a:" << static_cast<unsigned int>(pixel.alpha) << "}";
}
Pixel Screenshot::GetPixelAt(uint64_t x, uint64_t y) const {
FML_CHECK(x >= 0 && x < width_ && y >= 0 && y < height_)
<< "Index out of bounds";
return screenshot_[y][x];
}
std::map<Pixel, uint32_t> Screenshot::Histogram() const {
std::map<Pixel, uint32_t> histogram;
FML_CHECK(screenshot_.size() == height_ && screenshot_[0].size() == width_);
for (size_t i = 0; i < height_; i++) {
for (size_t j = 0; j < width_; j++) {
histogram[screenshot_[i][j]]++;
}
}
return histogram;
}
void Screenshot::ExtractScreenshotFromVMO(uint8_t* screenshot_vmo) {
FML_CHECK(screenshot_vmo);
for (size_t i = 0; i < height_; i++) {
// The head index of the ith row in the screenshot is |i* width_*
// KbytesPerPixel|.
screenshot_.push_back(GetPixelsInRow(screenshot_vmo, i));
}
}
std::vector<Pixel> Screenshot::GetPixelsInRow(uint8_t* screenshot_vmo,
size_t row_index) {
std::vector<Pixel> row;
for (size_t col_idx = 0;
col_idx < static_cast<size_t>(width_ * kBytesPerPixel);
col_idx += kBytesPerPixel) {
// Each row in the screenshot has |kBytesPerPixel * width_| elements.
// Therefore in order to reach the first pixel of the |row_index| row, we
// have to jump |row_index * width_ * kBytesPerPixel| positions.
auto pixel_start_index = row_index * width_ * kBytesPerPixel;
// Every |kBytesPerPixel| bytes represents the BGRA values of a pixel. Skip
// |kBytesPerPixel| bytes to get to the BGRA values of the next pixel. Each
// row in a screenshot has |kBytesPerPixel * width_| bytes of data.
// Example:-
// auto data = TakeScreenshot();
// data[0-3] -> RGBA of pixel 0.
// data[4-7] -> RGBA pf pixel 1.
row.emplace_back(screenshot_vmo[pixel_start_index + col_idx],
screenshot_vmo[pixel_start_index + col_idx + 1],
screenshot_vmo[pixel_start_index + col_idx + 2],
screenshot_vmo[pixel_start_index + col_idx + 3]);
}
return row;
}
} // namespace fuchsia_test_utils