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
3 // found in the LICENSE file.
5 #include "content/renderer/gpu/gpu_benchmarking_extension.h"
9 #include "base/base64.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "cc/layers/layer.h"
15 #include "content/common/input/synthetic_gesture_params.h"
16 #include "content/common/input/synthetic_pinch_gesture_params.h"
17 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
18 #include "content/common/input/synthetic_tap_gesture_params.h"
19 #include "content/public/renderer/render_thread.h"
20 #include "content/public/renderer/v8_value_converter.h"
21 #include "content/renderer/gpu/render_widget_compositor.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "content/renderer/render_view_impl.h"
24 #include "content/renderer/skia_benchmarking_extension.h"
25 #include "third_party/WebKit/public/web/WebImageCache.h"
26 #include "third_party/WebKit/public/web/WebLocalFrame.h"
27 #include "third_party/WebKit/public/web/WebView.h"
28 #include "third_party/skia/include/core/SkData.h"
29 #include "third_party/skia/include/core/SkGraphics.h"
30 #include "third_party/skia/include/core/SkPicture.h"
31 #include "third_party/skia/include/core/SkPixelRef.h"
32 #include "third_party/skia/include/core/SkStream.h"
33 #include "ui/gfx/codec/png_codec.h"
34 #include "v8/include/v8.h"
36 using blink::WebCanvas
;
37 using blink::WebLocalFrame
;
38 using blink::WebImageCache
;
39 using blink::WebPrivatePtr
;
43 const char kGpuBenchmarkingExtensionName
[] = "v8/GpuBenchmarking";
45 // offset parameter is deprecated/ignored, and will be remove from the
46 // signature in a future skia release. <reed@google.com>
47 static SkData
* EncodeBitmapToData(size_t* offset
, const SkBitmap
& bm
) {
48 SkPixelRef
* pr
= bm
.pixelRef();
50 SkData
* data
= pr
->refEncodedData();
54 std::vector
<unsigned char> vector
;
55 if (gfx::PNGCodec::EncodeBGRASkBitmap(bm
, false, &vector
)) {
56 return SkData::NewWithCopy(&vector
.front() , vector
.size());
63 class SkPictureSerializer
{
65 explicit SkPictureSerializer(const base::FilePath
& dirpath
)
68 // Let skia register known effect subclasses. This basically enables
69 // reflection on those subclasses required for picture serialization.
70 content::SkiaBenchmarking::Initialize();
73 // Recursively serializes the layer tree.
74 // Each layer in the tree is serialized into a separate skp file
75 // in the given directory.
76 void Serialize(const cc::Layer
* layer
) {
77 const cc::LayerList
& children
= layer
->children();
78 for (size_t i
= 0; i
< children
.size(); ++i
) {
79 Serialize(children
[i
].get());
82 skia::RefPtr
<SkPicture
> picture
= layer
->GetPicture();
86 // Serialize picture to file.
87 // TODO(alokp): Note that for this to work Chrome needs to be launched with
88 // --no-sandbox command-line flag. Get rid of this limitation.
90 std::string filename
= "layer_" + base::IntToString(layer_id_
++) + ".skp";
91 std::string filepath
= dirpath_
.AppendASCII(filename
).MaybeAsASCII();
92 DCHECK(!filepath
.empty());
93 SkFILEWStream
file(filepath
.c_str());
94 DCHECK(file
.isValid());
95 picture
->serialize(&file
, &EncodeBitmapToData
);
99 base::FilePath dirpath_
;
109 class CallbackAndContext
: public base::RefCounted
<CallbackAndContext
> {
111 CallbackAndContext(v8::Isolate
* isolate
,
112 v8::Handle
<v8::Function
> callback
,
113 v8::Handle
<v8::Context
> context
)
114 : isolate_(isolate
) {
115 callback_
.Reset(isolate_
, callback
);
116 context_
.Reset(isolate_
, context
);
119 v8::Isolate
* isolate() {
123 v8::Handle
<v8::Function
> GetCallback() {
124 return v8::Local
<v8::Function
>::New(isolate_
, callback_
);
127 v8::Handle
<v8::Context
> GetContext() {
128 return v8::Local
<v8::Context
>::New(isolate_
, context_
);
132 friend class base::RefCounted
<CallbackAndContext
>;
134 virtual ~CallbackAndContext() {
139 v8::Isolate
* isolate_
;
140 v8::Persistent
<v8::Function
> callback_
;
141 v8::Persistent
<v8::Context
> context_
;
142 DISALLOW_COPY_AND_ASSIGN(CallbackAndContext
);
145 class GpuBenchmarkingContext
{
147 GpuBenchmarkingContext()
150 render_view_impl_(NULL
),
153 bool Init(bool init_compositor
) {
154 web_frame_
= WebLocalFrame::frameForCurrentContext();
158 web_view_
= web_frame_
->view();
164 render_view_impl_
= RenderViewImpl::FromWebView(web_view_
);
165 if (!render_view_impl_
) {
171 if (!init_compositor
)
174 compositor_
= render_view_impl_
->compositor();
178 render_view_impl_
= NULL
;
185 WebLocalFrame
* web_frame() const {
186 DCHECK(web_frame_
!= NULL
);
189 WebView
* web_view() const {
190 DCHECK(web_view_
!= NULL
);
193 RenderViewImpl
* render_view_impl() const {
194 DCHECK(render_view_impl_
!= NULL
);
195 return render_view_impl_
;
197 RenderWidgetCompositor
* compositor() const {
198 DCHECK(compositor_
!= NULL
);
203 WebLocalFrame
* web_frame_
;
205 RenderViewImpl
* render_view_impl_
;
206 RenderWidgetCompositor
* compositor_
;
208 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext
);
213 class GpuBenchmarkingWrapper
: public v8::Extension
{
215 GpuBenchmarkingWrapper() :
216 v8::Extension(kGpuBenchmarkingExtensionName
,
217 "if (typeof(chrome) == 'undefined') {"
220 "if (typeof(chrome.gpuBenchmarking) == 'undefined') {"
221 " chrome.gpuBenchmarking = {};"
223 "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {"
224 " native function SetNeedsDisplayOnAllLayers();"
225 " return SetNeedsDisplayOnAllLayers();"
227 "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = "
229 " native function SetRasterizeOnlyVisibleContent();"
230 " return SetRasterizeOnlyVisibleContent();"
232 "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {"
233 " native function PrintToSkPicture();"
234 " return PrintToSkPicture(dirname);"
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);"
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);"
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);"
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);"
290 // TODO(dominikg): Remove once JS interface changes have rolled into
292 "chrome.gpuBenchmarking.newPinchInterface = true;"
293 "chrome.gpuBenchmarking.pinchBy = "
294 " function(scale_factor, anchor_x, anchor_y,"
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);"
304 "chrome.gpuBenchmarking.tap = "
305 " function(position_x, position_y, opt_callback, "
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);"
316 "chrome.gpuBenchmarking.beginWindowSnapshotPNG = "
317 "function(callback) {"
318 " native function BeginWindowSnapshotPNG();"
319 " BeginWindowSnapshotPNG(callback);"
321 "chrome.gpuBenchmarking.clearImageCache = function() {"
322 " native function ClearImageCache();"
323 " ClearImageCache();"
325 "chrome.gpuBenchmarking.runMicroBenchmark ="
326 " function(name, callback, opt_arguments) {"
327 " arguments = opt_arguments || {};"
328 " native function RunMicroBenchmark();"
329 " return RunMicroBenchmark(name, callback, arguments);"
331 "chrome.gpuBenchmarking.sendMessageToMicroBenchmark ="
332 " function(id, arguments) {"
333 " native function SendMessageToMicroBenchmark();"
334 " return SendMessageToMicroBenchmark(id, arguments);"
336 "chrome.gpuBenchmarking.hasGpuProcess = function() {"
337 " native function HasGpuProcess();"
338 " return HasGpuProcess();"
341 virtual v8::Handle
<v8::FunctionTemplate
> GetNativeFunctionTemplate(
342 v8::Isolate
* isolate
,
343 v8::Handle
<v8::String
> name
) override
{
345 v8::String::NewFromUtf8(isolate
, "SetNeedsDisplayOnAllLayers")))
346 return v8::FunctionTemplate::New(isolate
, SetNeedsDisplayOnAllLayers
);
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
);
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
);
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
);
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
);
376 return v8::Handle
<v8::FunctionTemplate
>();
379 static void SetNeedsDisplayOnAllLayers(
380 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
381 GpuBenchmarkingContext context
;
382 if (!context
.Init(true))
385 context
.compositor()->SetNeedsDisplayOnAllLayers();
388 static void SetRasterizeOnlyVisibleContent(
389 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
390 GpuBenchmarkingContext context
;
391 if (!context
.Init(true))
394 context
.compositor()->SetRasterizeOnlyVisibleContent();
397 static void PrintToSkPicture(
398 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
399 if (args
.Length() != 1)
402 v8::String::Utf8Value
dirname(args
[0]);
403 if (dirname
.length() == 0)
406 GpuBenchmarkingContext context
;
407 if (!context
.Init(true))
410 const cc::Layer
* root_layer
= context
.compositor()->GetRootLayer();
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())));
426 SkPictureSerializer
serializer(dirpath
);
427 serializer
.Serialize(root_layer
);
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
);
438 frame
->callFunctionEvenIfScriptDisabled(
439 callback_and_context
->GetCallback(),
440 v8::Object::New(isolate
),
446 static void GestureSourceTypeSupported(
447 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
448 if (args
.Length() != 1 || !args
[0]->IsNumber()) {
449 args
.GetReturnValue().Set(false);
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);
460 bool is_supported
= SyntheticGestureParams::IsGestureSourceTypeSupported(
461 static_cast<SyntheticGestureParams::GestureSourceType
>(
462 gesture_source_type
));
463 args
.GetReturnValue().Set(is_supported
);
466 static void BeginSmoothScroll(
467 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
468 GpuBenchmarkingContext context
;
469 if (!context
.Init(false))
472 // The last two arguments can be undefined. We check their validity later.
473 int arglen
= args
.Length();
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);
485 v8::Local
<v8::Function
> callback_local
=
486 v8::Local
<v8::Function
>::Cast(args
[1]);
488 scoped_refptr
<CallbackAndContext
> callback_and_context
=
489 new CallbackAndContext(args
.GetIsolate(),
491 context
.web_frame()->mainWorldScriptContext());
493 scoped_ptr
<SyntheticSmoothScrollGestureParams
> gesture_params(
494 new SyntheticSmoothScrollGestureParams
);
496 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
497 float page_scale_factor
= context
.web_view()->pageScaleFactor();
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);
505 gesture_params
->gesture_source_type
=
506 static_cast<SyntheticGestureParams::GestureSourceType
>(
507 gesture_source_type
);
509 gesture_params
->speed_in_pixels_s
= args
[4]->IntegerValue();
510 gesture_params
->prevent_fling
= args
[5]->BooleanValue();
512 // Account for the 2 optional arguments, start_x and start_y.
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
);
521 args
.GetReturnValue().Set(false);
524 gesture_params
->anchor
= anchor
;
526 int distance_length
= args
[0]->IntegerValue() * page_scale_factor
;
527 gfx::Vector2d distance
;
528 v8::String::Utf8Value
direction(args
[3]);
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
);
540 args
.GetReturnValue().Set(false);
543 gesture_params
->distances
.push_back(distance
);
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,
548 context
.render_view_impl()->QueueSyntheticGesture(
549 gesture_params
.PassAs
<SyntheticGestureParams
>(),
550 base::Bind(&OnSyntheticGestureCompleted
,
551 callback_and_context
));
553 args
.GetReturnValue().Set(true);
556 static void BeginScrollBounce(
557 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
558 GpuBenchmarkingContext context
;
559 if (!context
.Init(false))
562 // The last two arguments can be undefined. We check their validity later.
563 int arglen
= args
.Length();
565 !args
[0]->IsString() ||
566 !args
[1]->IsNumber() ||
567 !args
[2]->IsNumber() ||
568 !args
[3]->IsNumber() ||
569 !args
[4]->IsFunction() ||
570 !args
[5]->IsNumber()) {
571 args
.GetReturnValue().Set(false);
575 v8::Local
<v8::Function
> callback_local
=
576 v8::Local
<v8::Function
>::Cast(args
[4]);
578 scoped_refptr
<CallbackAndContext
> callback_and_context
=
579 new CallbackAndContext(args
.GetIsolate(),
581 context
.web_frame()->mainWorldScriptContext());
583 scoped_ptr
<SyntheticSmoothScrollGestureParams
> gesture_params(
584 new SyntheticSmoothScrollGestureParams
);
586 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
587 float page_scale_factor
= context
.web_view()->pageScaleFactor();
589 gesture_params
->speed_in_pixels_s
= args
[5]->IntegerValue();
591 // Account for the 2 optional arguments, start_x and start_y.
593 if (args
[6]->IsUndefined() || args
[7]->IsUndefined()) {
594 blink::WebRect rect
= context
.render_view_impl()->windowRect();
595 start
.SetPoint(rect
.width
/ 2, rect
.height
/ 2);
596 } else if (args
[6]->IsNumber() && args
[7]->IsNumber()) {
597 start
.SetPoint(args
[6]->IntegerValue() * page_scale_factor
,
598 args
[7]->IntegerValue() * page_scale_factor
);
600 args
.GetReturnValue().Set(false);
604 int distance_length
= args
[1]->IntegerValue() * page_scale_factor
;
605 int overscroll_length
= args
[2]->IntegerValue() * page_scale_factor
;
606 gfx::Vector2d distance
;
607 gfx::Vector2d overscroll
;
608 v8::String::Utf8Value
direction(args
[0]);
610 std::string
direction_str(*direction
);
611 if (direction_str
== "down") {
612 distance
.set_y(-distance_length
);
613 overscroll
.set_y(overscroll_length
);
615 else if (direction_str
== "up") {
616 distance
.set_y(distance_length
);
617 overscroll
.set_y(-overscroll_length
);
619 else if (direction_str
== "right") {
620 distance
.set_x(-distance_length
);
621 overscroll
.set_x(overscroll_length
);
623 else if (direction_str
== "left") {
624 distance
.set_x(distance_length
);
625 overscroll
.set_x(-overscroll_length
);
628 args
.GetReturnValue().Set(false);
632 int repeat_count
= args
[3]->IntegerValue();
633 gesture_params
->anchor
= start
;
634 for (int i
= 0; i
< repeat_count
; i
++) {
635 gesture_params
->distances
.push_back(distance
);
636 gesture_params
->distances
.push_back(-distance
+ overscroll
);
639 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
640 // progress, we will leak the callback and context. This needs to be fixed,
642 context
.render_view_impl()->QueueSyntheticGesture(
643 gesture_params
.PassAs
<SyntheticGestureParams
>(),
644 base::Bind(&OnSyntheticGestureCompleted
,
645 callback_and_context
));
647 args
.GetReturnValue().Set(true);
650 static void BeginPinch(
651 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
652 GpuBenchmarkingContext context
;
653 if (!context
.Init(false))
656 int arglen
= args
.Length();
658 !args
[0]->IsNumber() ||
659 !args
[1]->IsNumber() ||
660 !args
[2]->IsNumber() ||
661 !args
[3]->IsFunction() ||
662 !args
[4]->IsNumber()) {
663 args
.GetReturnValue().Set(false);
667 scoped_ptr
<SyntheticPinchGestureParams
> gesture_params(
668 new SyntheticPinchGestureParams
);
670 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
671 float page_scale_factor
= context
.web_view()->pageScaleFactor();
673 gesture_params
->scale_factor
= args
[0]->NumberValue();
674 gesture_params
->anchor
.SetPoint(
675 args
[1]->IntegerValue() * page_scale_factor
,
676 args
[2]->IntegerValue() * page_scale_factor
);
677 gesture_params
->relative_pointer_speed_in_pixels_s
=
678 args
[4]->IntegerValue();
680 v8::Local
<v8::Function
> callback_local
=
681 v8::Local
<v8::Function
>::Cast(args
[3]);
683 scoped_refptr
<CallbackAndContext
> callback_and_context
=
684 new CallbackAndContext(args
.GetIsolate(),
686 context
.web_frame()->mainWorldScriptContext());
689 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
690 // progress, we will leak the callback and context. This needs to be fixed,
692 context
.render_view_impl()->QueueSyntheticGesture(
693 gesture_params
.PassAs
<SyntheticGestureParams
>(),
694 base::Bind(&OnSyntheticGestureCompleted
,
695 callback_and_context
));
697 args
.GetReturnValue().Set(true);
700 static void BeginTap(
701 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
702 GpuBenchmarkingContext context
;
703 if (!context
.Init(false))
706 int arglen
= args
.Length();
708 !args
[0]->IsNumber() ||
709 !args
[1]->IsNumber() ||
710 !args
[2]->IsFunction() ||
711 !args
[3]->IsNumber() ||
712 !args
[4]->IsNumber()) {
713 args
.GetReturnValue().Set(false);
717 scoped_ptr
<SyntheticTapGestureParams
> gesture_params(
718 new SyntheticTapGestureParams
);
720 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
721 float page_scale_factor
= context
.web_view()->pageScaleFactor();
723 gesture_params
->position
.SetPoint(
724 args
[0]->IntegerValue() * page_scale_factor
,
725 args
[1]->IntegerValue() * page_scale_factor
);
726 gesture_params
->duration_ms
= args
[3]->IntegerValue();
728 int gesture_source_type
= args
[4]->IntegerValue();
729 if (gesture_source_type
< 0 ||
730 gesture_source_type
> SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX
) {
731 args
.GetReturnValue().Set(false);
734 gesture_params
->gesture_source_type
=
735 static_cast<SyntheticGestureParams::GestureSourceType
>(
736 gesture_source_type
);
738 v8::Local
<v8::Function
> callback_local
=
739 v8::Local
<v8::Function
>::Cast(args
[2]);
741 scoped_refptr
<CallbackAndContext
> callback_and_context
=
742 new CallbackAndContext(args
.GetIsolate(),
744 context
.web_frame()->mainWorldScriptContext());
747 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
748 // progress, we will leak the callback and context. This needs to be fixed,
750 context
.render_view_impl()->QueueSyntheticGesture(
751 gesture_params
.PassAs
<SyntheticGestureParams
>(),
752 base::Bind(&OnSyntheticGestureCompleted
,
753 callback_and_context
));
755 args
.GetReturnValue().Set(true);
758 static void OnSnapshotCompleted(CallbackAndContext
* callback_and_context
,
759 const gfx::Size
& size
,
760 const std::vector
<unsigned char>& png
) {
761 v8::Isolate
* isolate
= callback_and_context
->isolate();
762 v8::HandleScope
scope(isolate
);
763 v8::Handle
<v8::Context
> context
= callback_and_context
->GetContext();
764 v8::Context::Scope
context_scope(context
);
765 WebLocalFrame
* frame
= WebLocalFrame::frameForContext(context
);
768 v8::Handle
<v8::Value
> result
;
770 if(!size
.IsEmpty()) {
771 v8::Handle
<v8::Object
> result_object
;
772 result_object
= v8::Object::New(isolate
);
774 result_object
->Set(v8::String::NewFromUtf8(isolate
, "width"),
775 v8::Number::New(isolate
, size
.width()));
776 result_object
->Set(v8::String::NewFromUtf8(isolate
, "height"),
777 v8::Number::New(isolate
, size
.height()));
779 std::string base64_png
;
780 base::Base64Encode(base::StringPiece(
781 reinterpret_cast<const char*>(&*png
.begin()), png
.size()),
784 result_object
->Set(v8::String::NewFromUtf8(isolate
, "data"),
785 v8::String::NewFromUtf8(isolate
,
787 v8::String::kNormalString
,
790 result
= result_object
;
792 result
= v8::Null(isolate
);
795 v8::Handle
<v8::Value
> argv
[] = { result
};
797 frame
->callFunctionEvenIfScriptDisabled(
798 callback_and_context
->GetCallback(),
799 v8::Object::New(isolate
),
805 static void BeginWindowSnapshotPNG(
806 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
807 GpuBenchmarkingContext context
;
808 if (!context
.Init(false))
811 if (!args
[0]->IsFunction())
814 v8::Local
<v8::Function
> callback_local
=
815 v8::Local
<v8::Function
>::Cast(args
[0]);
817 scoped_refptr
<CallbackAndContext
> callback_and_context
=
818 new CallbackAndContext(args
.GetIsolate(),
820 context
.web_frame()->mainWorldScriptContext());
822 context
.render_view_impl()->GetWindowSnapshot(
823 base::Bind(&OnSnapshotCompleted
, callback_and_context
));
826 static void ClearImageCache(
827 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
828 WebImageCache::clear();
831 static void OnMicroBenchmarkCompleted(
832 CallbackAndContext
* callback_and_context
,
833 scoped_ptr
<base::Value
> result
) {
834 v8::Isolate
* isolate
= callback_and_context
->isolate();
835 v8::HandleScope
scope(isolate
);
836 v8::Handle
<v8::Context
> context
= callback_and_context
->GetContext();
837 v8::Context::Scope
context_scope(context
);
838 WebLocalFrame
* frame
= WebLocalFrame::frameForContext(context
);
840 scoped_ptr
<V8ValueConverter
> converter
=
841 make_scoped_ptr(V8ValueConverter::create());
842 v8::Handle
<v8::Value
> value
= converter
->ToV8Value(result
.get(), context
);
843 v8::Handle
<v8::Value
> argv
[] = { value
};
845 frame
->callFunctionEvenIfScriptDisabled(
846 callback_and_context
->GetCallback(),
847 v8::Object::New(isolate
),
853 static void RunMicroBenchmark(
854 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
855 GpuBenchmarkingContext context
;
856 if (!context
.Init(true)) {
857 args
.GetReturnValue().Set(0);
861 if (args
.Length() != 3 ||
862 !args
[0]->IsString() ||
863 !args
[1]->IsFunction() ||
864 !args
[2]->IsObject()) {
865 args
.GetReturnValue().Set(0);
869 v8::Local
<v8::Function
> callback_local
=
870 v8::Local
<v8::Function
>::Cast(args
[1]);
872 scoped_refptr
<CallbackAndContext
> callback_and_context
=
873 new CallbackAndContext(args
.GetIsolate(),
875 context
.web_frame()->mainWorldScriptContext());
877 scoped_ptr
<V8ValueConverter
> converter
=
878 make_scoped_ptr(V8ValueConverter::create());
879 v8::Handle
<v8::Context
> v8_context
= callback_and_context
->GetContext();
880 scoped_ptr
<base::Value
> value
=
881 make_scoped_ptr(converter
->FromV8Value(args
[2], v8_context
));
883 v8::String::Utf8Value
benchmark(args
[0]);
885 args
.GetReturnValue().Set(context
.compositor()->ScheduleMicroBenchmark(
886 std::string(*benchmark
),
888 base::Bind(&OnMicroBenchmarkCompleted
, callback_and_context
)));
891 static void SendMessageToMicroBenchmark(
892 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
893 GpuBenchmarkingContext context
;
894 if (!context
.Init(true)) {
895 args
.GetReturnValue().Set(0);
899 if (args
.Length() != 2 || !args
[0]->IsNumber() || !args
[1]->IsObject()) {
900 args
.GetReturnValue().Set(0);
904 scoped_ptr
<V8ValueConverter
> converter
=
905 make_scoped_ptr(V8ValueConverter::create());
906 v8::Handle
<v8::Context
> v8_context
=
907 context
.web_frame()->mainWorldScriptContext();
908 scoped_ptr
<base::Value
> value
=
909 make_scoped_ptr(converter
->FromV8Value(args
[1], v8_context
));
912 converter
->FromV8Value(args
[0], v8_context
)->GetAsInteger(&id
);
913 args
.GetReturnValue().Set(
914 context
.compositor()->SendMessageToMicroBenchmark(id
, value
.Pass()));
917 static void HasGpuProcess(const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
918 GpuChannelHost
* gpu_channel
= RenderThreadImpl::current()->GetGpuChannel();
919 args
.GetReturnValue().Set(!!gpu_channel
);
923 v8::Extension
* GpuBenchmarkingExtension::Get() {
924 return new GpuBenchmarkingWrapper();
927 } // namespace content