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