// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.h"

#include <array>

#include "base/compiler_specific.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace blink {

class WebGLImageConversionTest : public testing::Test {
 protected:
  void UnpackPixels(const uint16_t* source_data,
                    WebGLImageConversion::DataFormat source_data_format,
                    unsigned pixels_per_row,
                    uint8_t* destination_data) {
    WebGLImageConversion::UnpackPixels(source_data, source_data_format,
                                       pixels_per_row, destination_data);
  }
  void PackPixels(const uint8_t* source_data,
                  WebGLImageConversion::DataFormat source_data_format,
                  unsigned pixels_per_row,
                  uint8_t* destination_data) {
    WebGLImageConversion::PackPixels(source_data, source_data_format,
                                     pixels_per_row, destination_data);
  }
};

TEST_F(WebGLImageConversionTest, ConvertRGBA4444toRGBA8) {
  constexpr std::array<uint16_t, 9> source_data = {
      0x1234, 0x3456, 0x1234, 0x3456, 0x1234, 0x3456, 0x1234, 0x3456, 0x1234};
  constexpr std::array<uint8_t, 36> expected_data = {
      0x11, 0x22, 0x33, 0x44, 0x33, 0x44, 0x55, 0x66, 0x11, 0x22, 0x33, 0x44,
      0x33, 0x44, 0x55, 0x66, 0x11, 0x22, 0x33, 0x44, 0x33, 0x44, 0x55, 0x66,
      0x11, 0x22, 0x33, 0x44, 0x33, 0x44, 0x55, 0x66, 0x11, 0x22, 0x33, 0x44};
  std::array<uint8_t, 36> destination_data;
  UnpackPixels(source_data.data(), WebGLImageConversion::kDataFormatRGBA4444, 9,
               destination_data.data());
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, ConvertRGBA5551toRGBA8) {
  constexpr std::array<uint16_t, 9> source_data = {
      0x1234, 0x3456, 0x1234, 0x3456, 0x1234, 0x3456, 0x1234, 0x3456, 0x1234};
  constexpr std::array<uint8_t, 36> expected_data = {
      0x12, 0x40, 0xd2, 0x0, 0x36, 0x89, 0x5b, 0x0, 0x12, 0x40, 0xd2, 0x0,
      0x36, 0x89, 0x5b, 0x0, 0x12, 0x40, 0xd2, 0x0, 0x36, 0x89, 0x5b, 0x0,
      0x12, 0x40, 0xd2, 0x0, 0x36, 0x89, 0x5b, 0x0, 0x12, 0x40, 0xd2, 0x0};
  std::array<uint8_t, 36> destination_data;
  UnpackPixels(source_data.data(), WebGLImageConversion::kDataFormatRGBA5551, 9,
               destination_data.data());
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, ConvertRGBA8toRA8) {
  constexpr std::array<uint8_t, 40> source_data = {
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56};
  constexpr std::array<uint8_t, 20> expected_data = {
      0x9a, 0x56, 0x9a, 0x56, 0x9a, 0x56, 0x9a, 0x56, 0x9a, 0x56,
      0x9a, 0x56, 0x9a, 0x56, 0x9a, 0x56, 0x9a, 0x56, 0x9a, 0x56};
  std::array<uint8_t, 20> destination_data;
  PackPixels(source_data.data(), WebGLImageConversion::kDataFormatRA8, 10,
             destination_data.data());
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, convertBGRA8toRGBA8) {
  constexpr std::array<uint32_t, 9> source_data = {
      0x12345678, 0x34567888, 0x12345678, 0x34567888, 0x12345678,
      0x34567888, 0x12345678, 0x34567888, 0x12345678};
#if defined(ARCH_CPU_BIG_ENDIAN)
  constexpr std::array<uint32_t, 9> expected_data = {
      0x56341278, 0x78563488, 0x56341278, 0x78563488, 0x56341278,
      0x78563488, 0x56341278, 0x78563488, 0x56341278};
#else
  constexpr std::array<uint32_t, 9> expected_data = {
      0x12785634, 0x34887856, 0x12785634, 0x34887856, 0x12785634,
      0x34887856, 0x12785634, 0x34887856, 0x12785634};
#endif
  std::array<uint32_t, 9> destination_data;
  UnpackPixels(reinterpret_cast<const uint16_t*>(source_data.data()),
               WebGLImageConversion::kDataFormatBGRA8, 9,
               reinterpret_cast<uint8_t*>(destination_data.data()));
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, ConvertRGBA8toR8) {
  constexpr std::array<uint8_t, 40> source_data = {
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56};
  constexpr std::array<uint8_t, 10> expected_data = {
      0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a};
  std::array<uint8_t, 10> destination_data;
  PackPixels(source_data.data(), WebGLImageConversion::kDataFormatR8, 10,
             destination_data.data());
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, ConvertRGBA8toRGBA8) {
  constexpr std::array<uint8_t, 40> source_data = {
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56};
  constexpr std::array<uint8_t, 40> expected_data = {
      0x9a, 0xff, 0x9a, 0x56, 0x9a, 0xff, 0x9a, 0x56, 0x9a, 0xff,
      0x9a, 0x56, 0x9a, 0xff, 0x9a, 0x56, 0x9a, 0xff, 0x9a, 0x56,
      0x9a, 0xff, 0x9a, 0x56, 0x9a, 0xff, 0x9a, 0x56, 0x9a, 0xff,
      0x9a, 0x56, 0x9a, 0xff, 0x9a, 0x56, 0x9a, 0xff, 0x9a, 0x56};
  std::array<uint8_t, 40> destination_data;
  PackPixels(source_data.data(), WebGLImageConversion::kDataFormatRGBA8, 10,
             destination_data.data());
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, ConvertRGBA8ToUnsignedShort4444) {
  constexpr std::array<uint8_t, 40> source_data = {
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56};
  constexpr std::array<uint16_t, 10> expected_data = {
      0x3535, 0x3535, 0x3535, 0x3535, 0x3535,
      0x3535, 0x3535, 0x3535, 0x3535, 0x3535};
  std::array<uint16_t, 10> destination_data;
  PackPixels(source_data.data(), WebGLImageConversion::kDataFormatRGBA4444, 10,
             reinterpret_cast<uint8_t*>(destination_data.data()));
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, ConvertRGBA8ToRGBA5551) {
  constexpr std::array<uint8_t, 40> source_data = {
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56};
  constexpr std::array<uint16_t, 10> expected_data = {
      0x328c, 0x328c, 0x328c, 0x328c, 0x328c,
      0x328c, 0x328c, 0x328c, 0x328c, 0x328c};
  std::array<uint16_t, 10> destination_data;
  PackPixels(source_data.data(), WebGLImageConversion::kDataFormatRGBA5551, 10,
             reinterpret_cast<uint8_t*>(destination_data.data()));
  EXPECT_EQ(expected_data, destination_data);
}

TEST_F(WebGLImageConversionTest, ConvertRGBA8ToRGB565) {
  constexpr std::array<uint8_t, 40> source_data = {
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56,
      0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56};
  constexpr std::array<uint16_t, 10> expected_data = {
      0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6,
      0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6};
  std::array<uint16_t, 10> destination_data;
  PackPixels(source_data.data(), WebGLImageConversion::kDataFormatRGB565, 10,
             reinterpret_cast<uint8_t*>(destination_data.data()));
  EXPECT_EQ(expected_data, destination_data);
}

}  // namespace blink
