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 |