| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/gpu/gpu_benchmarking_extension.h" | 5 #include "content/renderer/gpu/gpu_benchmarking_extension.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/memory/scoped_vector.h" | 12 #include "base/memory/scoped_vector.h" |
| 13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "cc/layers/layer.h" | 14 #include "cc/layers/layer.h" |
| 15 #include "content/common/input/synthetic_gesture_params.h" | 15 #include "content/common/input/synthetic_gesture_params.h" |
| 16 #include "content/common/input/synthetic_pinch_gesture_params.h" | 16 #include "content/common/input/synthetic_pinch_gesture_params.h" |
| 17 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" | 17 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" |
| 18 #include "content/common/input/synthetic_tap_gesture_params.h" | 18 #include "content/common/input/synthetic_tap_gesture_params.h" |
| 19 #include "content/public/renderer/render_thread.h" | 19 #include "content/public/renderer/render_thread.h" |
| 20 #include "content/public/renderer/v8_value_converter.h" | 20 #include "content/public/renderer/v8_value_converter.h" |
| 21 #include "content/renderer/chrome_object_extensions_utils.h" |
| 21 #include "content/renderer/gpu/render_widget_compositor.h" | 22 #include "content/renderer/gpu/render_widget_compositor.h" |
| 22 #include "content/renderer/render_thread_impl.h" | 23 #include "content/renderer/render_thread_impl.h" |
| 23 #include "content/renderer/render_view_impl.h" | 24 #include "content/renderer/render_view_impl.h" |
| 24 #include "content/renderer/skia_benchmarking_extension.h" | 25 #include "content/renderer/skia_benchmarking_extension.h" |
| 26 #include "gin/arguments.h" |
| 27 #include "gin/handle.h" |
| 28 #include "gin/object_template_builder.h" |
| 25 #include "third_party/WebKit/public/web/WebImageCache.h" | 29 #include "third_party/WebKit/public/web/WebImageCache.h" |
| 30 #include "third_party/WebKit/public/web/WebKit.h" |
| 26 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 31 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| 27 #include "third_party/WebKit/public/web/WebView.h" | 32 #include "third_party/WebKit/public/web/WebView.h" |
| 28 #include "third_party/skia/include/core/SkData.h" | 33 #include "third_party/skia/include/core/SkData.h" |
| 29 #include "third_party/skia/include/core/SkGraphics.h" | 34 #include "third_party/skia/include/core/SkGraphics.h" |
| 30 #include "third_party/skia/include/core/SkPicture.h" | 35 #include "third_party/skia/include/core/SkPicture.h" |
| 31 #include "third_party/skia/include/core/SkPixelRef.h" | 36 #include "third_party/skia/include/core/SkPixelRef.h" |
| 32 #include "third_party/skia/include/core/SkStream.h" | 37 #include "third_party/skia/include/core/SkStream.h" |
| 33 #include "ui/gfx/codec/png_codec.h" | 38 #include "ui/gfx/codec/png_codec.h" |
| 34 #include "v8/include/v8.h" | 39 #include "v8/include/v8.h" |
| 35 | 40 |
| 36 using blink::WebCanvas; | 41 using blink::WebCanvas; |
| 37 using blink::WebLocalFrame; | 42 using blink::WebLocalFrame; |
| 38 using blink::WebImageCache; | 43 using blink::WebImageCache; |
| 39 using blink::WebPrivatePtr; | 44 using blink::WebPrivatePtr; |
| 40 using blink::WebSize; | 45 using blink::WebSize; |
| 41 using blink::WebView; | 46 using blink::WebView; |
| 42 | 47 |
| 43 const char kGpuBenchmarkingExtensionName[] = "v8/GpuBenchmarking"; | 48 namespace content { |
| 49 |
| 50 namespace { |
| 44 | 51 |
| 45 // offset parameter is deprecated/ignored, and will be remove from the | 52 // offset parameter is deprecated/ignored, and will be remove from the |
| 46 // signature in a future skia release. <reed@google.com> | 53 // signature in a future skia release. <reed@google.com> |
| 47 static SkData* EncodeBitmapToData(size_t* offset, const SkBitmap& bm) { | 54 SkData* EncodeBitmapToData(size_t* offset, const SkBitmap& bm) { |
| 48 SkPixelRef* pr = bm.pixelRef(); | 55 SkPixelRef* pr = bm.pixelRef(); |
| 49 if (pr != NULL) { | 56 if (pr != NULL) { |
| 50 SkData* data = pr->refEncodedData(); | 57 SkData* data = pr->refEncodedData(); |
| 51 if (data != NULL) | 58 if (data != NULL) |
| 52 return data; | 59 return data; |
| 53 } | 60 } |
| 54 std::vector<unsigned char> vector; | 61 std::vector<unsigned char> vector; |
| 55 if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) { | 62 if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) { |
| 56 return SkData::NewWithCopy(&vector.front() , vector.size()); | 63 return SkData::NewWithCopy(&vector.front(), vector.size()); |
| 57 } | 64 } |
| 58 return NULL; | 65 return NULL; |
| 59 } | 66 } |
| 60 | 67 |
| 61 namespace { | |
| 62 | |
| 63 class SkPictureSerializer { | 68 class SkPictureSerializer { |
| 64 public: | 69 public: |
| 65 explicit SkPictureSerializer(const base::FilePath& dirpath) | 70 explicit SkPictureSerializer(const base::FilePath& dirpath) |
| 66 : dirpath_(dirpath), | 71 : dirpath_(dirpath), |
| 67 layer_id_(0) { | 72 layer_id_(0) { |
| 68 // Let skia register known effect subclasses. This basically enables | 73 // Let skia register known effect subclasses. This basically enables |
| 69 // reflection on those subclasses required for picture serialization. | 74 // reflection on those subclasses required for picture serialization. |
| 70 content::SkiaBenchmarking::Initialize(); | 75 SkiaBenchmarking::Initialize(); |
| 71 } | 76 } |
| 72 | 77 |
| 73 // Recursively serializes the layer tree. | 78 // Recursively serializes the layer tree. |
| 74 // Each layer in the tree is serialized into a separate skp file | 79 // Each layer in the tree is serialized into a separate skp file |
| 75 // in the given directory. | 80 // in the given directory. |
| 76 void Serialize(const cc::Layer* layer) { | 81 void Serialize(const cc::Layer* layer) { |
| 77 const cc::LayerList& children = layer->children(); | 82 const cc::LayerList& children = layer->children(); |
| 78 for (size_t i = 0; i < children.size(); ++i) { | 83 for (size_t i = 0; i < children.size(); ++i) { |
| 79 Serialize(children[i].get()); | 84 Serialize(children[i].get()); |
| 80 } | 85 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 93 SkFILEWStream file(filepath.c_str()); | 98 SkFILEWStream file(filepath.c_str()); |
| 94 DCHECK(file.isValid()); | 99 DCHECK(file.isValid()); |
| 95 picture->serialize(&file, &EncodeBitmapToData); | 100 picture->serialize(&file, &EncodeBitmapToData); |
| 96 } | 101 } |
| 97 | 102 |
| 98 private: | 103 private: |
| 99 base::FilePath dirpath_; | 104 base::FilePath dirpath_; |
| 100 int layer_id_; | 105 int layer_id_; |
| 101 }; | 106 }; |
| 102 | 107 |
| 103 } // namespace | 108 template <typename T> |
| 109 bool GetArg(gin::Arguments* args, T* value) { |
| 110 if (!args->GetNext(value)) { |
| 111 args->ThrowError(); |
| 112 return false; |
| 113 } |
| 114 return true; |
| 115 } |
| 104 | 116 |
| 105 namespace content { | 117 template <> |
| 118 bool GetArg(gin::Arguments* args, int* value) { |
| 119 float number; |
| 120 bool ret = GetArg(args, &number); |
| 121 *value = number; |
| 122 return ret; |
| 123 } |
| 106 | 124 |
| 107 namespace { | 125 template <typename T> |
| 126 bool GetOptionalArg(gin::Arguments* args, T* value) { |
| 127 if (args->PeekNext().IsEmpty()) |
| 128 return true; |
| 129 if (args->PeekNext()->IsUndefined()) { |
| 130 args->Skip(); |
| 131 return true; |
| 132 } |
| 133 return GetArg(args, value); |
| 134 } |
| 108 | 135 |
| 109 class CallbackAndContext : public base::RefCounted<CallbackAndContext> { | 136 class CallbackAndContext : public base::RefCounted<CallbackAndContext> { |
| 110 public: | 137 public: |
| 111 CallbackAndContext(v8::Isolate* isolate, | 138 CallbackAndContext(v8::Isolate* isolate, |
| 112 v8::Handle<v8::Function> callback, | 139 v8::Handle<v8::Function> callback, |
| 113 v8::Handle<v8::Context> context) | 140 v8::Handle<v8::Context> context) |
| 114 : isolate_(isolate) { | 141 : isolate_(isolate) { |
| 115 callback_.Reset(isolate_, callback); | 142 callback_.Reset(isolate_, callback); |
| 116 context_.Reset(isolate_, context); | 143 context_.Reset(isolate_, context); |
| 117 } | 144 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 | 228 |
| 202 private: | 229 private: |
| 203 WebLocalFrame* web_frame_; | 230 WebLocalFrame* web_frame_; |
| 204 WebView* web_view_; | 231 WebView* web_view_; |
| 205 RenderViewImpl* render_view_impl_; | 232 RenderViewImpl* render_view_impl_; |
| 206 RenderWidgetCompositor* compositor_; | 233 RenderWidgetCompositor* compositor_; |
| 207 | 234 |
| 208 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext); | 235 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext); |
| 209 }; | 236 }; |
| 210 | 237 |
| 211 } // namespace | 238 void OnMicroBenchmarkCompleted( |
| 212 | 239 CallbackAndContext* callback_and_context, |
| 213 class GpuBenchmarkingWrapper : public v8::Extension { | 240 scoped_ptr<base::Value> result) { |
| 214 public: | 241 v8::Isolate* isolate = callback_and_context->isolate(); |
| 215 GpuBenchmarkingWrapper() : | 242 v8::HandleScope scope(isolate); |
| 216 v8::Extension(kGpuBenchmarkingExtensionName, | 243 v8::Handle<v8::Context> context = callback_and_context->GetContext(); |
| 217 "if (typeof(chrome) == 'undefined') {" | 244 v8::Context::Scope context_scope(context); |
| 218 " chrome = {};" | 245 WebLocalFrame* frame = WebLocalFrame::frameForContext(context); |
| 219 "};" | 246 if (frame) { |
| 220 "if (typeof(chrome.gpuBenchmarking) == 'undefined') {" | |
| 221 " chrome.gpuBenchmarking = {};" | |
| 222 "};" | |
| 223 "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {" | |
| 224 " native function SetNeedsDisplayOnAllLayers();" | |
| 225 " return SetNeedsDisplayOnAllLayers();" | |
| 226 "};" | |
| 227 "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = " | |
| 228 "function() {" | |
| 229 " native function SetRasterizeOnlyVisibleContent();" | |
| 230 " return SetRasterizeOnlyVisibleContent();" | |
| 231 "};" | |
| 232 "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {" | |
| 233 " native function PrintToSkPicture();" | |
| 234 " return PrintToSkPicture(dirname);" | |
| 235 "};" | |
| 236 "chrome.gpuBenchmarking.DEFAULT_INPUT = 0;" | |
| 237 "chrome.gpuBenchmarking.TOUCH_INPUT = 1;" | |
| 238 "chrome.gpuBenchmarking.MOUSE_INPUT = 2;" | |
| 239 "chrome.gpuBenchmarking.gestureSourceTypeSupported = " | |
| 240 " function(gesture_source_type) {" | |
| 241 " native function GestureSourceTypeSupported();" | |
| 242 " return GestureSourceTypeSupported(gesture_source_type);" | |
| 243 "};" | |
| 244 "chrome.gpuBenchmarking.smoothScrollBy = " | |
| 245 " function(pixels_to_scroll, opt_callback, opt_start_x," | |
| 246 " opt_start_y, opt_gesture_source_type," | |
| 247 " opt_direction, opt_speed_in_pixels_s) {" | |
| 248 " pixels_to_scroll = pixels_to_scroll || 0;" | |
| 249 " callback = opt_callback || function() { };" | |
| 250 " gesture_source_type = opt_gesture_source_type ||" | |
| 251 " chrome.gpuBenchmarking.DEFAULT_INPUT;" | |
| 252 " direction = opt_direction || 'down';" | |
| 253 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" | |
| 254 " native function BeginSmoothScroll();" | |
| 255 " return BeginSmoothScroll(pixels_to_scroll, callback," | |
| 256 " gesture_source_type, direction," | |
| 257 " speed_in_pixels_s, true," | |
| 258 " opt_start_x, opt_start_y);" | |
| 259 "};" | |
| 260 "chrome.gpuBenchmarking.swipe = " | |
| 261 " function(direction, distance, opt_callback," | |
| 262 " opt_start_x, opt_start_y," | |
| 263 " opt_speed_in_pixels_s) {" | |
| 264 " direction = direction || 'up';" | |
| 265 " distance = distance || 0;" | |
| 266 " callback = opt_callback || function() { };" | |
| 267 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" | |
| 268 " native function BeginSmoothScroll();" | |
| 269 " return BeginSmoothScroll(-distance, callback," | |
| 270 " chrome.gpuBenchmarking.TOUCH_INPUT," | |
| 271 " direction, speed_in_pixels_s, false," | |
| 272 " opt_start_x, opt_start_y);" | |
| 273 "};" | |
| 274 "chrome.gpuBenchmarking.scrollBounce = " | |
| 275 " function(direction, distance, overscroll, opt_repeat_count," | |
| 276 " opt_callback, opt_start_x, opt_start_y," | |
| 277 " opt_speed_in_pixels_s) {" | |
| 278 " direction = direction || 'down';" | |
| 279 " distance = distance || 0;" | |
| 280 " overscroll = overscroll || 0;" | |
| 281 " repeat_count = opt_repeat_count || 1;" | |
| 282 " callback = opt_callback || function() { };" | |
| 283 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;" | |
| 284 " native function BeginScrollBounce();" | |
| 285 " return BeginScrollBounce(direction, distance, overscroll," | |
| 286 " repeat_count, callback," | |
| 287 " speed_in_pixels_s," | |
| 288 " opt_start_x, opt_start_y);" | |
| 289 "};" | |
| 290 // TODO(dominikg): Remove once JS interface changes have rolled into | |
| 291 // stable. | |
| 292 "chrome.gpuBenchmarking.newPinchInterface = true;" | |
| 293 "chrome.gpuBenchmarking.pinchBy = " | |
| 294 " function(scale_factor, anchor_x, anchor_y," | |
| 295 " opt_callback, " | |
| 296 "opt_relative_pointer_speed_in_pixels_s) {" | |
| 297 " callback = opt_callback || function() { };" | |
| 298 " relative_pointer_speed_in_pixels_s =" | |
| 299 " opt_relative_pointer_speed_in_pixels_s || 800;" | |
| 300 " native function BeginPinch();" | |
| 301 " return BeginPinch(scale_factor, anchor_x, anchor_y, callback," | |
| 302 " relative_pointer_speed_in_pixels_s);" | |
| 303 "};" | |
| 304 "chrome.gpuBenchmarking.tap = " | |
| 305 " function(position_x, position_y, opt_callback, " | |
| 306 "opt_duration_ms," | |
| 307 " opt_gesture_source_type) {" | |
| 308 " callback = opt_callback || function() { };" | |
| 309 " duration_ms = opt_duration_ms || 50;" | |
| 310 " gesture_source_type = opt_gesture_source_type ||" | |
| 311 " chrome.gpuBenchmarking.DEFAULT_INPUT;" | |
| 312 " native function BeginTap();" | |
| 313 " return BeginTap(position_x, position_y, callback, duration_ms," | |
| 314 " gesture_source_type);" | |
| 315 "};" | |
| 316 "chrome.gpuBenchmarking.beginWindowSnapshotPNG = " | |
| 317 "function(callback) {" | |
| 318 " native function BeginWindowSnapshotPNG();" | |
| 319 " BeginWindowSnapshotPNG(callback);" | |
| 320 "};" | |
| 321 "chrome.gpuBenchmarking.clearImageCache = function() {" | |
| 322 " native function ClearImageCache();" | |
| 323 " ClearImageCache();" | |
| 324 "};" | |
| 325 "chrome.gpuBenchmarking.runMicroBenchmark =" | |
| 326 " function(name, callback, opt_arguments) {" | |
| 327 " arguments = opt_arguments || {};" | |
| 328 " native function RunMicroBenchmark();" | |
| 329 " return RunMicroBenchmark(name, callback, arguments);" | |
| 330 "};" | |
| 331 "chrome.gpuBenchmarking.sendMessageToMicroBenchmark =" | |
| 332 " function(id, arguments) {" | |
| 333 " native function SendMessageToMicroBenchmark();" | |
| 334 " return SendMessageToMicroBenchmark(id, arguments);" | |
| 335 "};" | |
| 336 "chrome.gpuBenchmarking.hasGpuProcess = function() {" | |
| 337 " native function HasGpuProcess();" | |
| 338 " return HasGpuProcess();" | |
| 339 "};") {} | |
| 340 | |
| 341 v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( | |
| 342 v8::Isolate* isolate, | |
| 343 v8::Handle<v8::String> name) override { | |
| 344 if (name->Equals( | |
| 345 v8::String::NewFromUtf8(isolate, "SetNeedsDisplayOnAllLayers"))) | |
| 346 return v8::FunctionTemplate::New(isolate, SetNeedsDisplayOnAllLayers); | |
| 347 if (name->Equals( | |
| 348 v8::String::NewFromUtf8(isolate, "SetRasterizeOnlyVisibleContent"))) | |
| 349 return v8::FunctionTemplate::New(isolate, SetRasterizeOnlyVisibleContent); | |
| 350 if (name->Equals(v8::String::NewFromUtf8(isolate, "PrintToSkPicture"))) | |
| 351 return v8::FunctionTemplate::New(isolate, PrintToSkPicture); | |
| 352 if (name->Equals( | |
| 353 v8::String::NewFromUtf8(isolate, "GestureSourceTypeSupported"))) | |
| 354 return v8::FunctionTemplate::New(isolate, GestureSourceTypeSupported); | |
| 355 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginSmoothScroll"))) | |
| 356 return v8::FunctionTemplate::New(isolate, BeginSmoothScroll); | |
| 357 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginScrollBounce"))) | |
| 358 return v8::FunctionTemplate::New(isolate, BeginScrollBounce); | |
| 359 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginPinch"))) | |
| 360 return v8::FunctionTemplate::New(isolate, BeginPinch); | |
| 361 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginTap"))) | |
| 362 return v8::FunctionTemplate::New(isolate, BeginTap); | |
| 363 if (name->Equals( | |
| 364 v8::String::NewFromUtf8(isolate, "BeginWindowSnapshotPNG"))) | |
| 365 return v8::FunctionTemplate::New(isolate, BeginWindowSnapshotPNG); | |
| 366 if (name->Equals(v8::String::NewFromUtf8(isolate, "ClearImageCache"))) | |
| 367 return v8::FunctionTemplate::New(isolate, ClearImageCache); | |
| 368 if (name->Equals(v8::String::NewFromUtf8(isolate, "RunMicroBenchmark"))) | |
| 369 return v8::FunctionTemplate::New(isolate, RunMicroBenchmark); | |
| 370 if (name->Equals( | |
| 371 v8::String::NewFromUtf8(isolate, "SendMessageToMicroBenchmark"))) | |
| 372 return v8::FunctionTemplate::New(isolate, SendMessageToMicroBenchmark); | |
| 373 if (name->Equals(v8::String::NewFromUtf8(isolate, "HasGpuProcess"))) | |
| 374 return v8::FunctionTemplate::New(isolate, HasGpuProcess); | |
| 375 | |
| 376 return v8::Handle<v8::FunctionTemplate>(); | |
| 377 } | |
| 378 | |
| 379 static void SetNeedsDisplayOnAllLayers( | |
| 380 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 381 GpuBenchmarkingContext context; | |
| 382 if (!context.Init(true)) | |
| 383 return; | |
| 384 | |
| 385 context.compositor()->SetNeedsDisplayOnAllLayers(); | |
| 386 } | |
| 387 | |
| 388 static void SetRasterizeOnlyVisibleContent( | |
| 389 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 390 GpuBenchmarkingContext context; | |
| 391 if (!context.Init(true)) | |
| 392 return; | |
| 393 | |
| 394 context.compositor()->SetRasterizeOnlyVisibleContent(); | |
| 395 } | |
| 396 | |
| 397 static void PrintToSkPicture( | |
| 398 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 399 if (args.Length() != 1) | |
| 400 return; | |
| 401 | |
| 402 v8::String::Utf8Value dirname(args[0]); | |
| 403 if (dirname.length() == 0) | |
| 404 return; | |
| 405 | |
| 406 GpuBenchmarkingContext context; | |
| 407 if (!context.Init(true)) | |
| 408 return; | |
| 409 | |
| 410 const cc::Layer* root_layer = context.compositor()->GetRootLayer(); | |
| 411 if (!root_layer) | |
| 412 return; | |
| 413 | |
| 414 base::FilePath dirpath( | |
| 415 base::FilePath::StringType(*dirname, *dirname + dirname.length())); | |
| 416 if (!base::CreateDirectory(dirpath) || | |
| 417 !base::PathIsWritable(dirpath)) { | |
| 418 std::string msg("Path is not writable: "); | |
| 419 msg.append(dirpath.MaybeAsASCII()); | |
| 420 v8::Isolate* isolate = args.GetIsolate(); | |
| 421 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | |
| 422 isolate, msg.c_str(), v8::String::kNormalString, msg.length()))); | |
| 423 return; | |
| 424 } | |
| 425 | |
| 426 SkPictureSerializer serializer(dirpath); | |
| 427 serializer.Serialize(root_layer); | |
| 428 } | |
| 429 | |
| 430 static void OnSyntheticGestureCompleted( | |
| 431 CallbackAndContext* callback_and_context) { | |
| 432 v8::Isolate* isolate = callback_and_context->isolate(); | |
| 433 v8::HandleScope scope(isolate); | |
| 434 v8::Handle<v8::Context> context = callback_and_context->GetContext(); | |
| 435 v8::Context::Scope context_scope(context); | |
| 436 WebLocalFrame* frame = WebLocalFrame::frameForContext(context); | |
| 437 if (frame) { | |
| 438 frame->callFunctionEvenIfScriptDisabled( | |
| 439 callback_and_context->GetCallback(), | |
| 440 v8::Object::New(isolate), | |
| 441 0, | |
| 442 NULL); | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 static void GestureSourceTypeSupported( | |
| 447 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 448 if (args.Length() != 1 || !args[0]->IsNumber()) { | |
| 449 args.GetReturnValue().Set(false); | |
| 450 return; | |
| 451 } | |
| 452 | |
| 453 int gesture_source_type = args[0]->IntegerValue(); | |
| 454 if (gesture_source_type < 0 || | |
| 455 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) { | |
| 456 args.GetReturnValue().Set(false); | |
| 457 return; | |
| 458 } | |
| 459 | |
| 460 bool is_supported = SyntheticGestureParams::IsGestureSourceTypeSupported( | |
| 461 static_cast<SyntheticGestureParams::GestureSourceType>( | |
| 462 gesture_source_type)); | |
| 463 args.GetReturnValue().Set(is_supported); | |
| 464 } | |
| 465 | |
| 466 static void BeginSmoothScroll( | |
| 467 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 468 GpuBenchmarkingContext context; | |
| 469 if (!context.Init(false)) | |
| 470 return; | |
| 471 | |
| 472 // The last two arguments can be undefined. We check their validity later. | |
| 473 int arglen = args.Length(); | |
| 474 if (arglen < 8 || | |
| 475 !args[0]->IsNumber() || | |
| 476 !args[1]->IsFunction() || | |
| 477 !args[2]->IsNumber() || | |
| 478 !args[3]->IsString() || | |
| 479 !args[4]->IsNumber() || | |
| 480 !args[5]->IsBoolean()) { | |
| 481 args.GetReturnValue().Set(false); | |
| 482 return; | |
| 483 } | |
| 484 | |
| 485 v8::Local<v8::Function> callback_local = | |
| 486 v8::Local<v8::Function>::Cast(args[1]); | |
| 487 | |
| 488 scoped_refptr<CallbackAndContext> callback_and_context = | |
| 489 new CallbackAndContext(args.GetIsolate(), | |
| 490 callback_local, | |
| 491 context.web_frame()->mainWorldScriptContext()); | |
| 492 | |
| 493 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params( | |
| 494 new SyntheticSmoothScrollGestureParams); | |
| 495 | |
| 496 // Convert coordinates from CSS pixels to density independent pixels (DIPs). | |
| 497 float page_scale_factor = context.web_view()->pageScaleFactor(); | |
| 498 | |
| 499 int gesture_source_type = args[2]->IntegerValue(); | |
| 500 if (gesture_source_type < 0 || | |
| 501 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) { | |
| 502 args.GetReturnValue().Set(false); | |
| 503 return; | |
| 504 } | |
| 505 gesture_params->gesture_source_type = | |
| 506 static_cast<SyntheticGestureParams::GestureSourceType>( | |
| 507 gesture_source_type); | |
| 508 | |
| 509 gesture_params->speed_in_pixels_s = args[4]->IntegerValue(); | |
| 510 gesture_params->prevent_fling = args[5]->BooleanValue(); | |
| 511 | |
| 512 // Account for the 2 optional arguments, start_x and start_y. | |
| 513 gfx::Point anchor; | |
| 514 if (args[6]->IsUndefined() || args[7]->IsUndefined()) { | |
| 515 blink::WebRect rect = context.render_view_impl()->windowRect(); | |
| 516 anchor.SetPoint(rect.width / 2, rect.height / 2); | |
| 517 } else if (args[6]->IsNumber() && args[7]->IsNumber()) { | |
| 518 anchor.SetPoint(args[6]->IntegerValue() * page_scale_factor, | |
| 519 args[7]->IntegerValue() * page_scale_factor); | |
| 520 } else { | |
| 521 args.GetReturnValue().Set(false); | |
| 522 return; | |
| 523 } | |
| 524 gesture_params->anchor = anchor; | |
| 525 | |
| 526 int distance_length = args[0]->IntegerValue() * page_scale_factor; | |
| 527 gfx::Vector2d distance; | |
| 528 v8::String::Utf8Value direction(args[3]); | |
| 529 DCHECK(*direction); | |
| 530 std::string direction_str(*direction); | |
| 531 if (direction_str == "down") | |
| 532 distance.set_y(-distance_length); | |
| 533 else if (direction_str == "up") | |
| 534 distance.set_y(distance_length); | |
| 535 else if (direction_str == "right") | |
| 536 distance.set_x(-distance_length); | |
| 537 else if (direction_str == "left") | |
| 538 distance.set_x(distance_length); | |
| 539 else { | |
| 540 args.GetReturnValue().Set(false); | |
| 541 return; | |
| 542 } | |
| 543 gesture_params->distances.push_back(distance); | |
| 544 | |
| 545 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in | |
| 546 // progress, we will leak the callback and context. This needs to be fixed, | |
| 547 // somehow. | |
| 548 context.render_view_impl()->QueueSyntheticGesture( | |
| 549 gesture_params.Pass(), | |
| 550 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); | |
| 551 | |
| 552 args.GetReturnValue().Set(true); | |
| 553 } | |
| 554 | |
| 555 static void BeginScrollBounce( | |
| 556 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 557 GpuBenchmarkingContext context; | |
| 558 if (!context.Init(false)) | |
| 559 return; | |
| 560 | |
| 561 // The last two arguments can be undefined. We check their validity later. | |
| 562 int arglen = args.Length(); | |
| 563 if (arglen < 8 || | |
| 564 !args[0]->IsString() || | |
| 565 !args[1]->IsNumber() || | |
| 566 !args[2]->IsNumber() || | |
| 567 !args[3]->IsNumber() || | |
| 568 !args[4]->IsFunction() || | |
| 569 !args[5]->IsNumber()) { | |
| 570 args.GetReturnValue().Set(false); | |
| 571 return; | |
| 572 } | |
| 573 | |
| 574 v8::Local<v8::Function> callback_local = | |
| 575 v8::Local<v8::Function>::Cast(args[4]); | |
| 576 | |
| 577 scoped_refptr<CallbackAndContext> callback_and_context = | |
| 578 new CallbackAndContext(args.GetIsolate(), | |
| 579 callback_local, | |
| 580 context.web_frame()->mainWorldScriptContext()); | |
| 581 | |
| 582 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params( | |
| 583 new SyntheticSmoothScrollGestureParams); | |
| 584 | |
| 585 // Convert coordinates from CSS pixels to density independent pixels (DIPs). | |
| 586 float page_scale_factor = context.web_view()->pageScaleFactor(); | |
| 587 | |
| 588 gesture_params->speed_in_pixels_s = args[5]->IntegerValue(); | |
| 589 | |
| 590 // Account for the 2 optional arguments, start_x and start_y. | |
| 591 gfx::Point start; | |
| 592 if (args[6]->IsUndefined() || args[7]->IsUndefined()) { | |
| 593 blink::WebRect rect = context.render_view_impl()->windowRect(); | |
| 594 start.SetPoint(rect.width / 2, rect.height / 2); | |
| 595 } else if (args[6]->IsNumber() && args[7]->IsNumber()) { | |
| 596 start.SetPoint(args[6]->IntegerValue() * page_scale_factor, | |
| 597 args[7]->IntegerValue() * page_scale_factor); | |
| 598 } else { | |
| 599 args.GetReturnValue().Set(false); | |
| 600 return; | |
| 601 } | |
| 602 | |
| 603 int distance_length = args[1]->IntegerValue() * page_scale_factor; | |
| 604 int overscroll_length = args[2]->IntegerValue() * page_scale_factor; | |
| 605 gfx::Vector2d distance; | |
| 606 gfx::Vector2d overscroll; | |
| 607 v8::String::Utf8Value direction(args[0]); | |
| 608 DCHECK(*direction); | |
| 609 std::string direction_str(*direction); | |
| 610 if (direction_str == "down") { | |
| 611 distance.set_y(-distance_length); | |
| 612 overscroll.set_y(overscroll_length); | |
| 613 } | |
| 614 else if (direction_str == "up") { | |
| 615 distance.set_y(distance_length); | |
| 616 overscroll.set_y(-overscroll_length); | |
| 617 } | |
| 618 else if (direction_str == "right") { | |
| 619 distance.set_x(-distance_length); | |
| 620 overscroll.set_x(overscroll_length); | |
| 621 } | |
| 622 else if (direction_str == "left") { | |
| 623 distance.set_x(distance_length); | |
| 624 overscroll.set_x(-overscroll_length); | |
| 625 } | |
| 626 else { | |
| 627 args.GetReturnValue().Set(false); | |
| 628 return; | |
| 629 } | |
| 630 | |
| 631 int repeat_count = args[3]->IntegerValue(); | |
| 632 gesture_params->anchor = start; | |
| 633 for (int i = 0; i < repeat_count; i++) { | |
| 634 gesture_params->distances.push_back(distance); | |
| 635 gesture_params->distances.push_back(-distance + overscroll); | |
| 636 } | |
| 637 | |
| 638 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in | |
| 639 // progress, we will leak the callback and context. This needs to be fixed, | |
| 640 // somehow. | |
| 641 context.render_view_impl()->QueueSyntheticGesture( | |
| 642 gesture_params.Pass(), | |
| 643 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); | |
| 644 | |
| 645 args.GetReturnValue().Set(true); | |
| 646 } | |
| 647 | |
| 648 static void BeginPinch( | |
| 649 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 650 GpuBenchmarkingContext context; | |
| 651 if (!context.Init(false)) | |
| 652 return; | |
| 653 | |
| 654 int arglen = args.Length(); | |
| 655 if (arglen < 5 || | |
| 656 !args[0]->IsNumber() || | |
| 657 !args[1]->IsNumber() || | |
| 658 !args[2]->IsNumber() || | |
| 659 !args[3]->IsFunction() || | |
| 660 !args[4]->IsNumber()) { | |
| 661 args.GetReturnValue().Set(false); | |
| 662 return; | |
| 663 } | |
| 664 | |
| 665 scoped_ptr<SyntheticPinchGestureParams> gesture_params( | |
| 666 new SyntheticPinchGestureParams); | |
| 667 | |
| 668 // Convert coordinates from CSS pixels to density independent pixels (DIPs). | |
| 669 float page_scale_factor = context.web_view()->pageScaleFactor(); | |
| 670 | |
| 671 gesture_params->scale_factor = args[0]->NumberValue(); | |
| 672 gesture_params->anchor.SetPoint( | |
| 673 args[1]->IntegerValue() * page_scale_factor, | |
| 674 args[2]->IntegerValue() * page_scale_factor); | |
| 675 gesture_params->relative_pointer_speed_in_pixels_s = | |
| 676 args[4]->IntegerValue(); | |
| 677 | |
| 678 v8::Local<v8::Function> callback_local = | |
| 679 v8::Local<v8::Function>::Cast(args[3]); | |
| 680 | |
| 681 scoped_refptr<CallbackAndContext> callback_and_context = | |
| 682 new CallbackAndContext(args.GetIsolate(), | |
| 683 callback_local, | |
| 684 context.web_frame()->mainWorldScriptContext()); | |
| 685 | |
| 686 | |
| 687 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in | |
| 688 // progress, we will leak the callback and context. This needs to be fixed, | |
| 689 // somehow. | |
| 690 context.render_view_impl()->QueueSyntheticGesture( | |
| 691 gesture_params.Pass(), | |
| 692 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); | |
| 693 | |
| 694 args.GetReturnValue().Set(true); | |
| 695 } | |
| 696 | |
| 697 static void BeginTap( | |
| 698 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 699 GpuBenchmarkingContext context; | |
| 700 if (!context.Init(false)) | |
| 701 return; | |
| 702 | |
| 703 int arglen = args.Length(); | |
| 704 if (arglen < 5 || | |
| 705 !args[0]->IsNumber() || | |
| 706 !args[1]->IsNumber() || | |
| 707 !args[2]->IsFunction() || | |
| 708 !args[3]->IsNumber() || | |
| 709 !args[4]->IsNumber()) { | |
| 710 args.GetReturnValue().Set(false); | |
| 711 return; | |
| 712 } | |
| 713 | |
| 714 scoped_ptr<SyntheticTapGestureParams> gesture_params( | |
| 715 new SyntheticTapGestureParams); | |
| 716 | |
| 717 // Convert coordinates from CSS pixels to density independent pixels (DIPs). | |
| 718 float page_scale_factor = context.web_view()->pageScaleFactor(); | |
| 719 | |
| 720 gesture_params->position.SetPoint( | |
| 721 args[0]->IntegerValue() * page_scale_factor, | |
| 722 args[1]->IntegerValue() * page_scale_factor); | |
| 723 gesture_params->duration_ms = args[3]->IntegerValue(); | |
| 724 | |
| 725 int gesture_source_type = args[4]->IntegerValue(); | |
| 726 if (gesture_source_type < 0 || | |
| 727 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) { | |
| 728 args.GetReturnValue().Set(false); | |
| 729 return; | |
| 730 } | |
| 731 gesture_params->gesture_source_type = | |
| 732 static_cast<SyntheticGestureParams::GestureSourceType>( | |
| 733 gesture_source_type); | |
| 734 | |
| 735 v8::Local<v8::Function> callback_local = | |
| 736 v8::Local<v8::Function>::Cast(args[2]); | |
| 737 | |
| 738 scoped_refptr<CallbackAndContext> callback_and_context = | |
| 739 new CallbackAndContext(args.GetIsolate(), | |
| 740 callback_local, | |
| 741 context.web_frame()->mainWorldScriptContext()); | |
| 742 | |
| 743 | |
| 744 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in | |
| 745 // progress, we will leak the callback and context. This needs to be fixed, | |
| 746 // somehow. | |
| 747 context.render_view_impl()->QueueSyntheticGesture( | |
| 748 gesture_params.Pass(), | |
| 749 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); | |
| 750 | |
| 751 args.GetReturnValue().Set(true); | |
| 752 } | |
| 753 | |
| 754 static void OnSnapshotCompleted(CallbackAndContext* callback_and_context, | |
| 755 const gfx::Size& size, | |
| 756 const std::vector<unsigned char>& png) { | |
| 757 v8::Isolate* isolate = callback_and_context->isolate(); | |
| 758 v8::HandleScope scope(isolate); | |
| 759 v8::Handle<v8::Context> context = callback_and_context->GetContext(); | |
| 760 v8::Context::Scope context_scope(context); | |
| 761 WebLocalFrame* frame = WebLocalFrame::frameForContext(context); | |
| 762 if (frame) { | |
| 763 | |
| 764 v8::Handle<v8::Value> result; | |
| 765 | |
| 766 if(!size.IsEmpty()) { | |
| 767 v8::Handle<v8::Object> result_object; | |
| 768 result_object = v8::Object::New(isolate); | |
| 769 | |
| 770 result_object->Set(v8::String::NewFromUtf8(isolate, "width"), | |
| 771 v8::Number::New(isolate, size.width())); | |
| 772 result_object->Set(v8::String::NewFromUtf8(isolate, "height"), | |
| 773 v8::Number::New(isolate, size.height())); | |
| 774 | |
| 775 std::string base64_png; | |
| 776 base::Base64Encode(base::StringPiece( | |
| 777 reinterpret_cast<const char*>(&*png.begin()), png.size()), | |
| 778 &base64_png); | |
| 779 | |
| 780 result_object->Set(v8::String::NewFromUtf8(isolate, "data"), | |
| 781 v8::String::NewFromUtf8(isolate, | |
| 782 base64_png.c_str(), | |
| 783 v8::String::kNormalString, | |
| 784 base64_png.size())); | |
| 785 | |
| 786 result = result_object; | |
| 787 } else { | |
| 788 result = v8::Null(isolate); | |
| 789 } | |
| 790 | |
| 791 v8::Handle<v8::Value> argv[] = { result }; | |
| 792 | |
| 793 frame->callFunctionEvenIfScriptDisabled( | |
| 794 callback_and_context->GetCallback(), | |
| 795 v8::Object::New(isolate), | |
| 796 1, | |
| 797 argv); | |
| 798 } | |
| 799 } | |
| 800 | |
| 801 static void BeginWindowSnapshotPNG( | |
| 802 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 803 GpuBenchmarkingContext context; | |
| 804 if (!context.Init(false)) | |
| 805 return; | |
| 806 | |
| 807 if (!args[0]->IsFunction()) | |
| 808 return; | |
| 809 | |
| 810 v8::Local<v8::Function> callback_local = | |
| 811 v8::Local<v8::Function>::Cast(args[0]); | |
| 812 | |
| 813 scoped_refptr<CallbackAndContext> callback_and_context = | |
| 814 new CallbackAndContext(args.GetIsolate(), | |
| 815 callback_local, | |
| 816 context.web_frame()->mainWorldScriptContext()); | |
| 817 | |
| 818 context.render_view_impl()->GetWindowSnapshot( | |
| 819 base::Bind(&OnSnapshotCompleted, callback_and_context)); | |
| 820 } | |
| 821 | |
| 822 static void ClearImageCache( | |
| 823 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 824 WebImageCache::clear(); | |
| 825 } | |
| 826 | |
| 827 static void OnMicroBenchmarkCompleted( | |
| 828 CallbackAndContext* callback_and_context, | |
| 829 scoped_ptr<base::Value> result) { | |
| 830 v8::Isolate* isolate = callback_and_context->isolate(); | |
| 831 v8::HandleScope scope(isolate); | |
| 832 v8::Handle<v8::Context> context = callback_and_context->GetContext(); | |
| 833 v8::Context::Scope context_scope(context); | |
| 834 WebLocalFrame* frame = WebLocalFrame::frameForContext(context); | |
| 835 if (frame) { | |
| 836 scoped_ptr<V8ValueConverter> converter = | |
| 837 make_scoped_ptr(V8ValueConverter::create()); | |
| 838 v8::Handle<v8::Value> value = converter->ToV8Value(result.get(), context); | |
| 839 v8::Handle<v8::Value> argv[] = { value }; | |
| 840 | |
| 841 frame->callFunctionEvenIfScriptDisabled( | |
| 842 callback_and_context->GetCallback(), | |
| 843 v8::Object::New(isolate), | |
| 844 1, | |
| 845 argv); | |
| 846 } | |
| 847 } | |
| 848 | |
| 849 static void RunMicroBenchmark( | |
| 850 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 851 GpuBenchmarkingContext context; | |
| 852 if (!context.Init(true)) { | |
| 853 args.GetReturnValue().Set(0); | |
| 854 return; | |
| 855 } | |
| 856 | |
| 857 if (args.Length() != 3 || | |
| 858 !args[0]->IsString() || | |
| 859 !args[1]->IsFunction() || | |
| 860 !args[2]->IsObject()) { | |
| 861 args.GetReturnValue().Set(0); | |
| 862 return; | |
| 863 } | |
| 864 | |
| 865 v8::Local<v8::Function> callback_local = | |
| 866 v8::Local<v8::Function>::Cast(args[1]); | |
| 867 | |
| 868 scoped_refptr<CallbackAndContext> callback_and_context = | |
| 869 new CallbackAndContext(args.GetIsolate(), | |
| 870 callback_local, | |
| 871 context.web_frame()->mainWorldScriptContext()); | |
| 872 | |
| 873 scoped_ptr<V8ValueConverter> converter = | 247 scoped_ptr<V8ValueConverter> converter = |
| 874 make_scoped_ptr(V8ValueConverter::create()); | 248 make_scoped_ptr(V8ValueConverter::create()); |
| 875 v8::Handle<v8::Context> v8_context = callback_and_context->GetContext(); | 249 v8::Handle<v8::Value> value = converter->ToV8Value(result.get(), context); |
| 876 scoped_ptr<base::Value> value = | 250 v8::Handle<v8::Value> argv[] = { value }; |
| 877 make_scoped_ptr(converter->FromV8Value(args[2], v8_context)); | 251 |
| 878 | 252 frame->callFunctionEvenIfScriptDisabled( |
| 879 v8::String::Utf8Value benchmark(args[0]); | 253 callback_and_context->GetCallback(), |
| 880 DCHECK(*benchmark); | 254 v8::Object::New(isolate), |
| 881 args.GetReturnValue().Set(context.compositor()->ScheduleMicroBenchmark( | 255 1, |
| 882 std::string(*benchmark), | 256 argv); |
| 883 value.Pass(), | 257 } |
| 884 base::Bind(&OnMicroBenchmarkCompleted, callback_and_context))); | 258 } |
| 885 } | 259 |
| 886 | 260 void OnSnapshotCompleted(CallbackAndContext* callback_and_context, |
| 887 static void SendMessageToMicroBenchmark( | 261 const gfx::Size& size, |
| 888 const v8::FunctionCallbackInfo<v8::Value>& args) { | 262 const std::vector<unsigned char>& png) { |
| 889 GpuBenchmarkingContext context; | 263 v8::Isolate* isolate = callback_and_context->isolate(); |
| 890 if (!context.Init(true)) { | 264 v8::HandleScope scope(isolate); |
| 891 args.GetReturnValue().Set(0); | 265 v8::Handle<v8::Context> context = callback_and_context->GetContext(); |
| 892 return; | 266 v8::Context::Scope context_scope(context); |
| 267 WebLocalFrame* frame = WebLocalFrame::frameForContext(context); |
| 268 if (frame) { |
| 269 v8::Handle<v8::Value> result; |
| 270 |
| 271 if (!size.IsEmpty()) { |
| 272 v8::Handle<v8::Object> result_object; |
| 273 result_object = v8::Object::New(isolate); |
| 274 |
| 275 result_object->Set(v8::String::NewFromUtf8(isolate, "width"), |
| 276 v8::Number::New(isolate, size.width())); |
| 277 result_object->Set(v8::String::NewFromUtf8(isolate, "height"), |
| 278 v8::Number::New(isolate, size.height())); |
| 279 |
| 280 std::string base64_png; |
| 281 base::Base64Encode( |
| 282 base::StringPiece(reinterpret_cast<const char*>(&*png.begin()), |
| 283 png.size()), |
| 284 &base64_png); |
| 285 |
| 286 result_object->Set(v8::String::NewFromUtf8(isolate, "data"), |
| 287 v8::String::NewFromUtf8(isolate, |
| 288 base64_png.c_str(), |
| 289 v8::String::kNormalString, |
| 290 base64_png.size())); |
| 291 |
| 292 result = result_object; |
| 293 } else { |
| 294 result = v8::Null(isolate); |
| 893 } | 295 } |
| 894 | 296 |
| 895 if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsObject()) { | 297 v8::Handle<v8::Value> argv[] = {result}; |
| 896 args.GetReturnValue().Set(0); | 298 |
| 897 return; | 299 frame->callFunctionEvenIfScriptDisabled( |
| 898 } | 300 callback_and_context->GetCallback(), v8::Object::New(isolate), 1, argv); |
| 899 | 301 } |
| 900 scoped_ptr<V8ValueConverter> converter = | 302 } |
| 901 make_scoped_ptr(V8ValueConverter::create()); | 303 |
| 902 v8::Handle<v8::Context> v8_context = | 304 void OnSyntheticGestureCompleted(CallbackAndContext* callback_and_context) { |
| 903 context.web_frame()->mainWorldScriptContext(); | 305 v8::Isolate* isolate = callback_and_context->isolate(); |
| 904 scoped_ptr<base::Value> value = | 306 v8::HandleScope scope(isolate); |
| 905 make_scoped_ptr(converter->FromV8Value(args[1], v8_context)); | 307 v8::Handle<v8::Context> context = callback_and_context->GetContext(); |
| 906 | 308 v8::Context::Scope context_scope(context); |
| 907 int id = 0; | 309 WebLocalFrame* frame = WebLocalFrame::frameForContext(context); |
| 908 converter->FromV8Value(args[0], v8_context)->GetAsInteger(&id); | 310 if (frame) { |
| 909 args.GetReturnValue().Set( | 311 frame->callFunctionEvenIfScriptDisabled( |
| 910 context.compositor()->SendMessageToMicroBenchmark(id, value.Pass())); | 312 callback_and_context->GetCallback(), v8::Object::New(isolate), 0, NULL); |
| 911 } | 313 } |
| 912 | 314 } |
| 913 static void HasGpuProcess(const v8::FunctionCallbackInfo<v8::Value>& args) { | 315 |
| 316 bool BeginSmoothScroll(v8::Isolate* isolate, |
| 317 int pixels_to_scroll, |
| 318 v8::Handle<v8::Function> callback, |
| 319 int gesture_source_type, |
| 320 const std::string& direction, |
| 321 int speed_in_pixels_s, |
| 322 bool prevent_fling, |
| 323 int start_x, |
| 324 int start_y) { |
| 325 GpuBenchmarkingContext context; |
| 326 if (!context.Init(false)) |
| 327 return false; |
| 328 |
| 329 scoped_refptr<CallbackAndContext> callback_and_context = |
| 330 new CallbackAndContext( |
| 331 isolate, callback, context.web_frame()->mainWorldScriptContext()); |
| 332 |
| 333 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params( |
| 334 new SyntheticSmoothScrollGestureParams); |
| 335 |
| 336 // Convert coordinates from CSS pixels to density independent pixels (DIPs). |
| 337 float page_scale_factor = context.web_view()->pageScaleFactor(); |
| 338 |
| 339 if (gesture_source_type < 0 || |
| 340 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) { |
| 341 return false; |
| 342 } |
| 343 gesture_params->gesture_source_type = |
| 344 static_cast<SyntheticGestureParams::GestureSourceType>( |
| 345 gesture_source_type); |
| 346 |
| 347 gesture_params->speed_in_pixels_s = speed_in_pixels_s; |
| 348 gesture_params->prevent_fling = prevent_fling; |
| 349 |
| 350 gesture_params->anchor.SetPoint(start_x * page_scale_factor, |
| 351 start_y * page_scale_factor); |
| 352 |
| 353 int distance_length = pixels_to_scroll * page_scale_factor; |
| 354 gfx::Vector2d distance; |
| 355 if (direction == "down") |
| 356 distance.set_y(-distance_length); |
| 357 else if (direction == "up") |
| 358 distance.set_y(distance_length); |
| 359 else if (direction == "right") |
| 360 distance.set_x(-distance_length); |
| 361 else if (direction == "left") |
| 362 distance.set_x(distance_length); |
| 363 else { |
| 364 return false; |
| 365 } |
| 366 gesture_params->distances.push_back(distance); |
| 367 |
| 368 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in |
| 369 // progress, we will leak the callback and context. This needs to be fixed, |
| 370 // somehow. |
| 371 context.render_view_impl()->QueueSyntheticGesture( |
| 372 gesture_params.Pass(), |
| 373 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); |
| 374 |
| 375 return true; |
| 376 } |
| 377 |
| 378 } // namespace |
| 379 |
| 380 gin::WrapperInfo GpuBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin}; |
| 381 |
| 382 // static |
| 383 void GpuBenchmarking::Install(blink::WebFrame* frame) { |
| 384 v8::Isolate* isolate = blink::mainThreadIsolate(); |
| 385 v8::HandleScope handle_scope(isolate); |
| 386 v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); |
| 387 if (context.IsEmpty()) |
| 388 return; |
| 389 |
| 390 v8::Context::Scope context_scope(context); |
| 391 |
| 392 gin::Handle<GpuBenchmarking> controller = |
| 393 gin::CreateHandle(isolate, new GpuBenchmarking()); |
| 394 if (controller.IsEmpty()) |
| 395 return; |
| 396 |
| 397 v8::Handle<v8::Object> chrome = GetOrCreateChromeObject(isolate, |
| 398 context->Global()); |
| 399 chrome->Set(gin::StringToV8(isolate, "gpuBenchmarking"), controller.ToV8()); |
| 400 } |
| 401 |
| 402 GpuBenchmarking::GpuBenchmarking() { |
| 403 } |
| 404 |
| 405 GpuBenchmarking::~GpuBenchmarking() { |
| 406 } |
| 407 |
| 408 gin::ObjectTemplateBuilder GpuBenchmarking::GetObjectTemplateBuilder( |
| 409 v8::Isolate* isolate) { |
| 410 return gin::Wrappable<GpuBenchmarking>::GetObjectTemplateBuilder(isolate) |
| 411 .SetMethod("setNeedsDisplayOnAllLayers", |
| 412 &GpuBenchmarking::SetNeedsDisplayOnAllLayers) |
| 413 .SetMethod("setRasterizeOnlyVisibleContent", |
| 414 &GpuBenchmarking::SetRasterizeOnlyVisibleContent) |
| 415 .SetMethod("printToSkPicture", &GpuBenchmarking::PrintToSkPicture) |
| 416 .SetValue("DEFAULT_INPUT", 0) |
| 417 .SetValue("TOUCH_INPUT", 1) |
| 418 .SetValue("MOUSE_INPUT", 2) |
| 419 .SetMethod("gestureSourceTypeSupported", |
| 420 &GpuBenchmarking::GestureSourceTypeSupported) |
| 421 .SetMethod("smoothScrollBy", &GpuBenchmarking::SmoothScrollBy) |
| 422 .SetMethod("swipe", &GpuBenchmarking::Swipe) |
| 423 .SetMethod("scrollBounce", &GpuBenchmarking::ScrollBounce) |
| 424 // TODO(dominikg): Remove once JS interface changes have rolled into |
| 425 // stable. |
| 426 .SetValue("newPinchInterface", true) |
| 427 .SetMethod("pinchBy", &GpuBenchmarking::PinchBy) |
| 428 .SetMethod("tap", &GpuBenchmarking::Tap) |
| 429 .SetMethod("beginWindowSnapshotPNG", |
| 430 &GpuBenchmarking::BeginWindowSnapshotPNG) |
| 431 .SetMethod("clearImageCache", &GpuBenchmarking::ClearImageCache) |
| 432 .SetMethod("runMicroBenchmark", &GpuBenchmarking::RunMicroBenchmark) |
| 433 .SetMethod("sendMessageToMicroBenchmark", |
| 434 &GpuBenchmarking::SendMessageToMicroBenchmark) |
| 435 .SetMethod("hasGpuProcess", &GpuBenchmarking::HasGpuProcess); |
| 436 } |
| 437 |
| 438 void GpuBenchmarking::SetNeedsDisplayOnAllLayers() { |
| 439 GpuBenchmarkingContext context; |
| 440 if (!context.Init(true)) |
| 441 return; |
| 442 |
| 443 context.compositor()->SetNeedsDisplayOnAllLayers(); |
| 444 } |
| 445 |
| 446 void GpuBenchmarking::SetRasterizeOnlyVisibleContent() { |
| 447 GpuBenchmarkingContext context; |
| 448 if (!context.Init(true)) |
| 449 return; |
| 450 |
| 451 context.compositor()->SetRasterizeOnlyVisibleContent(); |
| 452 } |
| 453 |
| 454 void GpuBenchmarking::PrintToSkPicture(v8::Isolate* isolate, |
| 455 const std::string& dirname) { |
| 456 GpuBenchmarkingContext context; |
| 457 if (!context.Init(true)) |
| 458 return; |
| 459 |
| 460 const cc::Layer* root_layer = context.compositor()->GetRootLayer(); |
| 461 if (!root_layer) |
| 462 return; |
| 463 |
| 464 base::FilePath dirpath = base::FilePath::FromUTF8Unsafe(dirname); |
| 465 if (!base::CreateDirectory(dirpath) || |
| 466 !base::PathIsWritable(dirpath)) { |
| 467 std::string msg("Path is not writable: "); |
| 468 msg.append(dirpath.MaybeAsASCII()); |
| 469 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( |
| 470 isolate, msg.c_str(), v8::String::kNormalString, msg.length()))); |
| 471 return; |
| 472 } |
| 473 |
| 474 SkPictureSerializer serializer(dirpath); |
| 475 serializer.Serialize(root_layer); |
| 476 } |
| 477 |
| 478 bool GpuBenchmarking::GestureSourceTypeSupported(int gesture_source_type) { |
| 479 if (gesture_source_type < 0 || |
| 480 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) { |
| 481 return false; |
| 482 } |
| 483 |
| 484 return SyntheticGestureParams::IsGestureSourceTypeSupported( |
| 485 static_cast<SyntheticGestureParams::GestureSourceType>( |
| 486 gesture_source_type)); |
| 487 } |
| 488 |
| 489 bool GpuBenchmarking::SmoothScrollBy(gin::Arguments* args) { |
| 490 GpuBenchmarkingContext context; |
| 491 if (!context.Init(true)) |
| 492 return false; |
| 493 |
| 494 float page_scale_factor = context.web_view()->pageScaleFactor(); |
| 495 blink::WebRect rect = context.render_view_impl()->windowRect(); |
| 496 |
| 497 int pixels_to_scroll = 0; |
| 498 v8::Handle<v8::Function> callback; |
| 499 int start_x = rect.width / (page_scale_factor * 2); |
| 500 int start_y = rect.height / (page_scale_factor * 2); |
| 501 int gesture_source_type = 0; // DEFAULT_INPUT |
| 502 std::string direction = "down"; |
| 503 int speed_in_pixels_s = 800; |
| 504 |
| 505 if (!GetOptionalArg(args, &pixels_to_scroll) || |
| 506 !GetOptionalArg(args, &callback) || |
| 507 !GetOptionalArg(args, &start_x) || |
| 508 !GetOptionalArg(args, &start_y) || |
| 509 !GetOptionalArg(args, &gesture_source_type) || |
| 510 !GetOptionalArg(args, &direction) || |
| 511 !GetOptionalArg(args, &speed_in_pixels_s)) { |
| 512 return false; |
| 513 } |
| 514 |
| 515 return BeginSmoothScroll(args->isolate(), |
| 516 pixels_to_scroll, |
| 517 callback, |
| 518 gesture_source_type, |
| 519 direction, |
| 520 speed_in_pixels_s, |
| 521 true, |
| 522 start_x, |
| 523 start_y); |
| 524 } |
| 525 |
| 526 bool GpuBenchmarking::Swipe(gin::Arguments* args) { |
| 527 GpuBenchmarkingContext context; |
| 528 if (!context.Init(true)) |
| 529 return false; |
| 530 |
| 531 float page_scale_factor = context.web_view()->pageScaleFactor(); |
| 532 blink::WebRect rect = context.render_view_impl()->windowRect(); |
| 533 |
| 534 std::string direction = "up"; |
| 535 int pixels_to_scroll = 0; |
| 536 v8::Handle<v8::Function> callback; |
| 537 int start_x = rect.width / (page_scale_factor * 2); |
| 538 int start_y = rect.height / (page_scale_factor * 2); |
| 539 int speed_in_pixels_s = 800; |
| 540 |
| 541 if (!GetOptionalArg(args, &direction) || |
| 542 !GetOptionalArg(args, &pixels_to_scroll) || |
| 543 !GetOptionalArg(args, &callback) || |
| 544 !GetOptionalArg(args, &start_x) || |
| 545 !GetOptionalArg(args, &start_y) || |
| 546 !GetOptionalArg(args, &speed_in_pixels_s)) { |
| 547 return false; |
| 548 } |
| 549 |
| 550 return BeginSmoothScroll(args->isolate(), |
| 551 -pixels_to_scroll, |
| 552 callback, |
| 553 1, // TOUCH_INPUT |
| 554 direction, |
| 555 speed_in_pixels_s, |
| 556 false, |
| 557 start_x, |
| 558 start_y); |
| 559 } |
| 560 |
| 561 bool GpuBenchmarking::ScrollBounce(gin::Arguments* args) { |
| 562 GpuBenchmarkingContext context; |
| 563 if (!context.Init(false)) |
| 564 return false; |
| 565 |
| 566 float page_scale_factor = context.web_view()->pageScaleFactor(); |
| 567 blink::WebRect rect = context.render_view_impl()->windowRect(); |
| 568 |
| 569 std::string direction = "down"; |
| 570 int distance_length = 0; |
| 571 int overscroll_length = 0; |
| 572 int repeat_count = 1; |
| 573 v8::Handle<v8::Function> callback; |
| 574 int start_x = rect.width / (page_scale_factor * 2); |
| 575 int start_y = rect.height / (page_scale_factor * 2); |
| 576 int speed_in_pixels_s = 800; |
| 577 |
| 578 if (!GetOptionalArg(args, &direction) || |
| 579 !GetOptionalArg(args, &distance_length) || |
| 580 !GetOptionalArg(args, &overscroll_length) || |
| 581 !GetOptionalArg(args, &repeat_count) || |
| 582 !GetOptionalArg(args, &callback) || |
| 583 !GetOptionalArg(args, &start_x) || |
| 584 !GetOptionalArg(args, &start_y) || |
| 585 !GetOptionalArg(args, &speed_in_pixels_s)) { |
| 586 return false; |
| 587 } |
| 588 |
| 589 scoped_refptr<CallbackAndContext> callback_and_context = |
| 590 new CallbackAndContext(args->isolate(), |
| 591 callback, |
| 592 context.web_frame()->mainWorldScriptContext()); |
| 593 |
| 594 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params( |
| 595 new SyntheticSmoothScrollGestureParams); |
| 596 |
| 597 gesture_params->speed_in_pixels_s = speed_in_pixels_s; |
| 598 |
| 599 gesture_params->anchor.SetPoint(start_x * page_scale_factor, |
| 600 start_y * page_scale_factor); |
| 601 |
| 602 distance_length *= page_scale_factor; |
| 603 overscroll_length *= page_scale_factor; |
| 604 gfx::Vector2d distance; |
| 605 gfx::Vector2d overscroll; |
| 606 if (direction == "down") { |
| 607 distance.set_y(-distance_length); |
| 608 overscroll.set_y(overscroll_length); |
| 609 } else if (direction == "up") { |
| 610 distance.set_y(distance_length); |
| 611 overscroll.set_y(-overscroll_length); |
| 612 } else if (direction == "right") { |
| 613 distance.set_x(-distance_length); |
| 614 overscroll.set_x(overscroll_length); |
| 615 } else if (direction == "left") { |
| 616 distance.set_x(distance_length); |
| 617 overscroll.set_x(-overscroll_length); |
| 618 } else { |
| 619 return false; |
| 620 } |
| 621 |
| 622 for (int i = 0; i < repeat_count; i++) { |
| 623 gesture_params->distances.push_back(distance); |
| 624 gesture_params->distances.push_back(-distance + overscroll); |
| 625 } |
| 626 |
| 627 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in |
| 628 // progress, we will leak the callback and context. This needs to be fixed, |
| 629 // somehow. |
| 630 context.render_view_impl()->QueueSyntheticGesture( |
| 631 gesture_params.Pass(), |
| 632 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); |
| 633 |
| 634 return true; |
| 635 } |
| 636 |
| 637 bool GpuBenchmarking::PinchBy(gin::Arguments* args) { |
| 638 GpuBenchmarkingContext context; |
| 639 if (!context.Init(false)) |
| 640 return false; |
| 641 |
| 642 float scale_factor; |
| 643 int anchor_x; |
| 644 int anchor_y; |
| 645 v8::Handle<v8::Function> callback; |
| 646 int relative_pointer_speed_in_pixels_s = 800; |
| 647 |
| 648 |
| 649 if (!GetArg(args, &scale_factor) || |
| 650 !GetArg(args, &anchor_x) || |
| 651 !GetArg(args, &anchor_y) || |
| 652 !GetOptionalArg(args, &callback) || |
| 653 !GetOptionalArg(args, &relative_pointer_speed_in_pixels_s)) { |
| 654 return false; |
| 655 } |
| 656 |
| 657 scoped_ptr<SyntheticPinchGestureParams> gesture_params( |
| 658 new SyntheticPinchGestureParams); |
| 659 |
| 660 // Convert coordinates from CSS pixels to density independent pixels (DIPs). |
| 661 float page_scale_factor = context.web_view()->pageScaleFactor(); |
| 662 |
| 663 gesture_params->scale_factor = scale_factor; |
| 664 gesture_params->anchor.SetPoint(anchor_x * page_scale_factor, |
| 665 anchor_y * page_scale_factor); |
| 666 gesture_params->relative_pointer_speed_in_pixels_s = |
| 667 relative_pointer_speed_in_pixels_s; |
| 668 |
| 669 scoped_refptr<CallbackAndContext> callback_and_context = |
| 670 new CallbackAndContext(args->isolate(), |
| 671 callback, |
| 672 context.web_frame()->mainWorldScriptContext()); |
| 673 |
| 674 |
| 675 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in |
| 676 // progress, we will leak the callback and context. This needs to be fixed, |
| 677 // somehow. |
| 678 context.render_view_impl()->QueueSyntheticGesture( |
| 679 gesture_params.Pass(), |
| 680 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); |
| 681 |
| 682 return true; |
| 683 } |
| 684 |
| 685 bool GpuBenchmarking::Tap(gin::Arguments* args) { |
| 686 GpuBenchmarkingContext context; |
| 687 if (!context.Init(false)) |
| 688 return false; |
| 689 |
| 690 int position_x; |
| 691 int position_y; |
| 692 v8::Handle<v8::Function> callback; |
| 693 int duration_ms = 50; |
| 694 int gesture_source_type = 0; // DEFAULT_INPUT |
| 695 |
| 696 if (!GetArg(args, &position_x) || |
| 697 !GetArg(args, &position_y) || |
| 698 !GetOptionalArg(args, &callback) || |
| 699 !GetOptionalArg(args, &duration_ms) || |
| 700 !GetOptionalArg(args, &gesture_source_type)) { |
| 701 return false; |
| 702 } |
| 703 |
| 704 scoped_ptr<SyntheticTapGestureParams> gesture_params( |
| 705 new SyntheticTapGestureParams); |
| 706 |
| 707 // Convert coordinates from CSS pixels to density independent pixels (DIPs). |
| 708 float page_scale_factor = context.web_view()->pageScaleFactor(); |
| 709 |
| 710 gesture_params->position.SetPoint(position_x * page_scale_factor, |
| 711 position_y * page_scale_factor); |
| 712 gesture_params->duration_ms = duration_ms; |
| 713 |
| 714 if (gesture_source_type < 0 || |
| 715 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) { |
| 716 return false; |
| 717 } |
| 718 gesture_params->gesture_source_type = |
| 719 static_cast<SyntheticGestureParams::GestureSourceType>( |
| 720 gesture_source_type); |
| 721 |
| 722 scoped_refptr<CallbackAndContext> callback_and_context = |
| 723 new CallbackAndContext(args->isolate(), |
| 724 callback, |
| 725 context.web_frame()->mainWorldScriptContext()); |
| 726 |
| 727 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in |
| 728 // progress, we will leak the callback and context. This needs to be fixed, |
| 729 // somehow. |
| 730 context.render_view_impl()->QueueSyntheticGesture( |
| 731 gesture_params.Pass(), |
| 732 base::Bind(&OnSyntheticGestureCompleted, callback_and_context)); |
| 733 |
| 734 return true; |
| 735 } |
| 736 |
| 737 void GpuBenchmarking::BeginWindowSnapshotPNG( |
| 738 v8::Isolate* isolate, |
| 739 v8::Handle<v8::Function> callback) { |
| 740 GpuBenchmarkingContext context; |
| 741 if (!context.Init(false)) |
| 742 return; |
| 743 |
| 744 scoped_refptr<CallbackAndContext> callback_and_context = |
| 745 new CallbackAndContext(isolate, |
| 746 callback, |
| 747 context.web_frame()->mainWorldScriptContext()); |
| 748 |
| 749 context.render_view_impl()->GetWindowSnapshot( |
| 750 base::Bind(&OnSnapshotCompleted, callback_and_context)); |
| 751 } |
| 752 |
| 753 void GpuBenchmarking::ClearImageCache() { |
| 754 WebImageCache::clear(); |
| 755 } |
| 756 |
| 757 int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) { |
| 758 GpuBenchmarkingContext context; |
| 759 if (!context.Init(true)) |
| 760 return 0; |
| 761 |
| 762 std::string name; |
| 763 v8::Handle<v8::Function> callback; |
| 764 v8::Handle<v8::Object> arguments; |
| 765 |
| 766 if (!GetArg(args, &name) || !GetArg(args, &callback) || |
| 767 !GetOptionalArg(args, &arguments)) { |
| 768 return 0; |
| 769 } |
| 770 |
| 771 scoped_refptr<CallbackAndContext> callback_and_context = |
| 772 new CallbackAndContext(args->isolate(), |
| 773 callback, |
| 774 context.web_frame()->mainWorldScriptContext()); |
| 775 |
| 776 scoped_ptr<V8ValueConverter> converter = |
| 777 make_scoped_ptr(V8ValueConverter::create()); |
| 778 v8::Handle<v8::Context> v8_context = callback_and_context->GetContext(); |
| 779 scoped_ptr<base::Value> value = |
| 780 make_scoped_ptr(converter->FromV8Value(arguments, v8_context)); |
| 781 |
| 782 return context.compositor()->ScheduleMicroBenchmark( |
| 783 name, |
| 784 value.Pass(), |
| 785 base::Bind(&OnMicroBenchmarkCompleted, callback_and_context)); |
| 786 } |
| 787 |
| 788 bool GpuBenchmarking::SendMessageToMicroBenchmark( |
| 789 int id, |
| 790 v8::Handle<v8::Object> message) { |
| 791 GpuBenchmarkingContext context; |
| 792 if (!context.Init(true)) |
| 793 return false; |
| 794 |
| 795 scoped_ptr<V8ValueConverter> converter = |
| 796 make_scoped_ptr(V8ValueConverter::create()); |
| 797 v8::Handle<v8::Context> v8_context = |
| 798 context.web_frame()->mainWorldScriptContext(); |
| 799 scoped_ptr<base::Value> value = |
| 800 make_scoped_ptr(converter->FromV8Value(message, v8_context)); |
| 801 |
| 802 return context.compositor()->SendMessageToMicroBenchmark(id, value.Pass()); |
| 803 } |
| 804 |
| 805 bool GpuBenchmarking::HasGpuProcess() { |
| 914 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel(); | 806 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel(); |
| 915 args.GetReturnValue().Set(!!gpu_channel); | 807 return !!gpu_channel; |
| 916 } | |
| 917 }; | |
| 918 | |
| 919 v8::Extension* GpuBenchmarkingExtension::Get() { | |
| 920 return new GpuBenchmarkingWrapper(); | |
| 921 } | 808 } |
| 922 | 809 |
| 923 } // namespace content | 810 } // namespace content |
| OLD | NEW |