1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/native_client/tests/ppapi_test_lib/test_interface.h"
6
7#include <string.h>
8#include <map>
9#include <new>
10
11#include "native_client/src/include/nacl_macros.h"
12#include "native_client/src/shared/platform/nacl_check.h"
13
14#include "ppapi/c/pp_instance.h"
15#include "ppapi/c/pp_module.h"
16#include "ppapi/c/pp_size.h"
17#include "ppapi/c/pp_rect.h"
18#include "ppapi/c/pp_var.h"
19#include "ppapi/c/ppb_core.h"
20#include "ppapi/c/ppb_graphics_2d.h"
21#include "ppapi/c/ppb_image_data.h"
22#include "ppapi/c/ppb_instance.h"
23#include "ppapi/c/ppb_messaging.h"
24#include "ppapi/c/ppb_var.h"
25#include "ppapi/c/private/ppb_testing_private.h"
26
27#include "ppapi/native_client/tests/ppapi_test_lib/get_browser_interface.h"
28#include "ppapi/native_client/tests/ppapi_test_lib/internal_utils.h"
29
30void PostTestMessage(nacl::string test_name, nacl::string message) {
31  nacl::string test_message = test_name;
32  test_message += ":";
33  test_message += message;
34  PP_Var post_var = PPBVar()->VarFromUtf8(test_message.c_str(),
35                                          test_message.size());
36  PPBMessaging()->PostMessage(pp_instance(), post_var);
37  PPBVar()->Release(post_var);
38}
39
40PP_Var PP_MakeString(const char* s) {
41  return PPBVar()->VarFromUtf8(s, strlen(s));
42}
43
44nacl::string StringifyVar(const PP_Var& var) {
45  uint32_t dummy_size;
46  switch (var.type) {
47    default:
48     return "<UNKNOWN>" +  toString(var.type);
49    case  PP_VARTYPE_NULL:
50      return "<NULL>";
51    case  PP_VARTYPE_BOOL:
52     return "<BOOL>" + toString(var.value.as_bool);
53    case  PP_VARTYPE_INT32:
54     return "<INT32>" + toString(var.value.as_int);
55    case  PP_VARTYPE_DOUBLE:
56     return "<DOUBLE>" + toString(var.value.as_double);
57    case PP_VARTYPE_STRING:
58     return "<STRING>" + nacl::string(PPBVar()->VarToUtf8(var, &dummy_size));
59  }
60}
61
62////////////////////////////////////////////////////////////////////////////////
63// Test registration
64////////////////////////////////////////////////////////////////////////////////
65
66namespace {
67
68class TestTable {
69 public:
70  // Return singleton intsance.
71  static TestTable* Get() {
72    static TestTable table;
73    return &table;
74  }
75
76  void AddTest(nacl::string test_name, TestFunction test_function) {
77    test_map_[test_name] = test_function;
78  }
79  void RunTest(nacl::string test_name);
80
81 private:
82  NACL_DISALLOW_COPY_AND_ASSIGN(TestTable);
83
84  TestTable() {}
85
86  typedef std::map<nacl::string, TestFunction> TestMap;
87  TestMap test_map_;
88};
89
90void TestTable::RunTest(nacl::string test_name) {
91  TestMap::iterator it = test_map_.find(test_name);
92  if (it == test_map_.end()) {
93    PostTestMessage(test_name, "NOTFOUND");
94    return;
95  }
96  CHECK(it->second != NULL);
97  TestFunction test_function = it->second;
98  return test_function();
99}
100
101}  // namespace
102
103void RegisterTest(nacl::string test_name, TestFunction test_func) {
104  TestTable::Get()->AddTest(test_name, test_func);
105}
106
107void RunTest(nacl::string test_name) {
108  TestTable::Get()->RunTest(test_name);
109}
110
111////////////////////////////////////////////////////////////////////////////////
112// Testable callback support
113////////////////////////////////////////////////////////////////////////////////
114
115namespace {
116
117struct CallbackInfo {
118  nacl::string callback_name;
119  PP_CompletionCallback user_callback;
120};
121
122void ReportCallbackInvocationToJS(const char* callback_name) {
123  PP_Var callback_var = PPBVar()->VarFromUtf8(callback_name,
124                                              strlen(callback_name));
125  // Report using postmessage for async tests.
126  PPBMessaging()->PostMessage(pp_instance(), callback_var);
127  PPBVar()->Release(callback_var);
128}
129
130void CallbackWrapper(void* user_data, int32_t result) {
131  CallbackInfo* callback_info = reinterpret_cast<CallbackInfo*>(user_data);
132  PP_RunCompletionCallback(&callback_info->user_callback, result);
133  ReportCallbackInvocationToJS(callback_info->callback_name.c_str());
134  delete callback_info;
135}
136
137}  // namespace
138
139PP_CompletionCallback MakeTestableCompletionCallback(
140    const char* callback_name,  // Tested for by JS harness.
141    PP_CompletionCallback_Func func,
142    void* user_data) {
143  CHECK(callback_name != NULL && strlen(callback_name) > 0);
144  CHECK(func != NULL);
145
146  CallbackInfo* callback_info = new(std::nothrow) CallbackInfo;
147  CHECK(callback_info != NULL);
148  callback_info->callback_name = callback_name;
149  callback_info->user_callback =
150    PP_MakeOptionalCompletionCallback(func, user_data);
151
152  return PP_MakeOptionalCompletionCallback(CallbackWrapper, callback_info);
153}
154
155PP_CompletionCallback MakeTestableCompletionCallback(
156    const char* callback_name,  // Tested for by JS harness.
157    PP_CompletionCallback_Func func) {
158  return MakeTestableCompletionCallback(callback_name, func, NULL);
159}
160
161
162////////////////////////////////////////////////////////////////////////////////
163// PPAPI Helpers
164////////////////////////////////////////////////////////////////////////////////
165
166bool IsSizeInRange(PP_Size size, PP_Size min_size, PP_Size max_size) {
167  return (min_size.width <= size.width && size.width <= max_size.width &&
168          min_size.height <= size.height && size.height <= max_size.height);
169}
170
171bool IsSizeEqual(PP_Size size, PP_Size expected) {
172  return (size.width == expected.width && size.height == expected.height);
173}
174
175bool IsRectEqual(PP_Rect position, PP_Rect expected) {
176  return (position.point.x == expected.point.x &&
177          position.point.y == expected.point.y &&
178          IsSizeEqual(position.size, expected.size));
179}
180
181uint32_t FormatColor(PP_ImageDataFormat format, ColorPremul color) {
182  if (format == PP_IMAGEDATAFORMAT_BGRA_PREMUL)
183    return (color.A << 24) | (color.R << 16) | (color.G << 8) | (color.B);
184  else if (format == PP_IMAGEDATAFORMAT_RGBA_PREMUL)
185    return (color.A << 24) | (color.B << 16) | (color.G << 8) | (color.R);
186  else
187    NACL_NOTREACHED();
188}
189
190PP_Resource CreateImageData(PP_Size size, ColorPremul pixel_color, void** bmp) {
191  PP_ImageDataFormat image_format = PPBImageData()->GetNativeImageDataFormat();
192  uint32_t formatted_pixel_color = FormatColor(image_format, pixel_color);
193  PP_Resource image_data = PPBImageData()->Create(
194      pp_instance(), image_format, &size, PP_TRUE /*init_to_zero*/);
195  CHECK(image_data != kInvalidResource);
196  PP_ImageDataDesc image_desc;
197  CHECK(PPBImageData()->Describe(image_data, &image_desc) == PP_TRUE);
198  *bmp = NULL;
199  *bmp = PPBImageData()->Map(image_data);
200  CHECK(*bmp != NULL);
201  uint32_t* bmp_words = static_cast<uint32_t*>(*bmp);
202  int num_pixels = image_desc.stride / kBytesPerPixel * image_desc.size.height;
203  for (int i = 0; i < num_pixels; i++)
204    bmp_words[i] = formatted_pixel_color;
205  return image_data;
206}
207
208bool IsImageRectOnScreen(PP_Resource graphics2d,
209                         PP_Point origin,
210                         PP_Size size,
211                         ColorPremul color) {
212  PP_Size size2d;
213  PP_Bool dummy;
214  CHECK(PP_TRUE == PPBGraphics2D()->Describe(graphics2d, &size2d, &dummy));
215
216  void* bitmap = NULL;
217  PP_Resource image = CreateImageData(size2d, kOpaqueBlack, &bitmap);
218
219  PP_ImageDataDesc image_desc;
220  CHECK(PP_TRUE == PPBImageData()->Describe(image, &image_desc));
221  int32_t stride = image_desc.stride / kBytesPerPixel;  // width + padding.
222  uint32_t expected_color = FormatColor(image_desc.format, color);
223  CHECK(origin.x >= 0 && origin.y >= 0 &&
224        (origin.x + size.width) <= stride &&
225        (origin.y + size.height) <= image_desc.size.height);
226
227  CHECK(PP_TRUE == PPBTestingPrivate()->ReadImageData(
228      graphics2d, image, &kOrigin));
229  bool found_error = false;
230  for (int y = origin.y; y < origin.y + size.height && !found_error; y++) {
231    for (int x = origin.x; x < origin.x + size.width && !found_error; x++) {
232      uint32_t pixel_color = static_cast<uint32_t*>(bitmap)[stride * y + x];
233      found_error = (pixel_color != expected_color);
234    }
235  }
236
237  PPBCore()->ReleaseResource(image);
238  return !found_error;
239}
240