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/file_util.h"
11 #include "base/files/file_path.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/browser_rendering_stats.h"
16 #include "content/common/gpu/gpu_rendering_stats.h"
17 #include "content/common/input/synthetic_gesture_params.h"
18 #include "content/common/input/synthetic_pinch_gesture_params.h"
19 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
20 #include "content/common/input/synthetic_tap_gesture_params.h"
21 #include "content/public/renderer/render_thread.h"
22 #include "content/public/renderer/v8_value_converter.h"
23 #include "content/renderer/gpu/render_widget_compositor.h"
24 #include "content/renderer/render_thread_impl.h"
25 #include "content/renderer/render_view_impl.h"
26 #include "content/renderer/skia_benchmarking_extension.h"
27 #include "third_party/WebKit/public/web/WebFrame.h"
28 #include "third_party/WebKit/public/web/WebImageCache.h"
29 #include "third_party/WebKit/public/web/WebView.h"
30 #include "third_party/skia/include/core/SkData.h"
31 #include "third_party/skia/include/core/SkGraphics.h"
32 #include "third_party/skia/include/core/SkPicture.h"
33 #include "third_party/skia/include/core/SkPixelRef.h"
34 #include "third_party/skia/include/core/SkStream.h"
35 #include "ui/gfx/codec/png_codec.h"
36 #include "v8/include/v8.h"
37 #include "webkit/renderer/compositor_bindings/web_rendering_stats_impl.h"
39 using blink::WebCanvas
;
40 using blink::WebFrame
;
41 using blink::WebImageCache
;
42 using blink::WebPrivatePtr
;
43 using blink::WebRenderingStatsImpl
;
47 const char kGpuBenchmarkingExtensionName
[] = "v8/GpuBenchmarking";
49 // offset parameter is deprecated/ignored, and will be remove from the
50 // signature in a future skia release. <reed@google.com>
51 static SkData
* EncodeBitmapToData(size_t* offset
, const SkBitmap
& bm
) {
52 SkPixelRef
* pr
= bm
.pixelRef();
54 SkData
* data
= pr
->refEncodedData();
58 std::vector
<unsigned char> vector
;
59 if (gfx::PNGCodec::EncodeBGRASkBitmap(bm
, false, &vector
)) {
60 return SkData::NewWithCopy(&vector
.front() , vector
.size());
67 class SkPictureSerializer
{
69 explicit SkPictureSerializer(const base::FilePath
& dirpath
)
72 // Let skia register known effect subclasses. This basically enables
73 // reflection on those subclasses required for picture serialization.
74 content::SkiaBenchmarkingExtension::InitSkGraphics();
77 // Recursively serializes the layer tree.
78 // Each layer in the tree is serialized into a separate skp file
79 // in the given directory.
80 void Serialize(const cc::Layer
* layer
) {
81 const cc::LayerList
& children
= layer
->children();
82 for (size_t i
= 0; i
< children
.size(); ++i
) {
83 Serialize(children
[i
].get());
86 skia::RefPtr
<SkPicture
> picture
= layer
->GetPicture();
90 // Serialize picture to file.
91 // TODO(alokp): Note that for this to work Chrome needs to be launched with
92 // --no-sandbox command-line flag. Get rid of this limitation.
94 std::string filename
= "layer_" + base::IntToString(layer_id_
++) + ".skp";
95 std::string filepath
= dirpath_
.AppendASCII(filename
).MaybeAsASCII();
96 DCHECK(!filepath
.empty());
97 SkFILEWStream
file(filepath
.c_str());
98 DCHECK(file
.isValid());
99 picture
->serialize(&file
, &EncodeBitmapToData
);
103 base::FilePath dirpath_
;
107 class RenderingStatsEnumerator
: public cc::RenderingStats::Enumerator
{
109 RenderingStatsEnumerator(v8::Isolate
* isolate
,
110 v8::Handle
<v8::Object
> stats_object
)
111 : isolate(isolate
), stats_object(stats_object
) {}
113 virtual void AddInt64(const char* name
, int64 value
) OVERRIDE
{
114 stats_object
->Set(v8::String::NewFromUtf8(isolate
, name
),
115 v8::Number::New(isolate
, value
));
118 virtual void AddDouble(const char* name
, double value
) OVERRIDE
{
119 stats_object
->Set(v8::String::NewFromUtf8(isolate
, name
),
120 v8::Number::New(isolate
, value
));
123 virtual void AddInt(const char* name
, int value
) OVERRIDE
{
124 stats_object
->Set(v8::String::NewFromUtf8(isolate
, name
),
125 v8::Integer::New(isolate
, value
));
128 virtual void AddTimeDeltaInSecondsF(const char* name
,
129 const base::TimeDelta
& value
) OVERRIDE
{
130 stats_object
->Set(v8::String::NewFromUtf8(isolate
, name
),
131 v8::Number::New(isolate
, value
.InSecondsF()));
135 v8::Isolate
* isolate
;
136 v8::Handle
<v8::Object
> stats_object
;
145 class CallbackAndContext
: public base::RefCounted
<CallbackAndContext
> {
147 CallbackAndContext(v8::Isolate
* isolate
,
148 v8::Handle
<v8::Function
> callback
,
149 v8::Handle
<v8::Context
> context
)
150 : isolate_(isolate
) {
151 callback_
.Reset(isolate_
, callback
);
152 context_
.Reset(isolate_
, context
);
155 v8::Isolate
* isolate() {
159 v8::Handle
<v8::Function
> GetCallback() {
160 return v8::Local
<v8::Function
>::New(isolate_
, callback_
);
163 v8::Handle
<v8::Context
> GetContext() {
164 return v8::Local
<v8::Context
>::New(isolate_
, context_
);
168 friend class base::RefCounted
<CallbackAndContext
>;
170 virtual ~CallbackAndContext() {
175 v8::Isolate
* isolate_
;
176 v8::Persistent
<v8::Function
> callback_
;
177 v8::Persistent
<v8::Context
> context_
;
178 DISALLOW_COPY_AND_ASSIGN(CallbackAndContext
);
181 class GpuBenchmarkingContext
{
183 GpuBenchmarkingContext()
186 render_view_impl_(NULL
),
189 bool Init(bool init_compositor
) {
190 web_frame_
= WebFrame::frameForCurrentContext();
194 web_view_
= web_frame_
->view();
200 render_view_impl_
= RenderViewImpl::FromWebView(web_view_
);
201 if (!render_view_impl_
) {
207 if (!init_compositor
)
210 compositor_
= render_view_impl_
->compositor();
214 render_view_impl_
= NULL
;
221 WebFrame
* web_frame() const {
222 DCHECK(web_frame_
!= NULL
);
225 WebView
* web_view() const {
226 DCHECK(web_view_
!= NULL
);
229 RenderViewImpl
* render_view_impl() const {
230 DCHECK(render_view_impl_
!= NULL
);
231 return render_view_impl_
;
233 RenderWidgetCompositor
* compositor() const {
234 DCHECK(compositor_
!= NULL
);
239 WebFrame
* web_frame_
;
241 RenderViewImpl
* render_view_impl_
;
242 RenderWidgetCompositor
* compositor_
;
244 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext
);
249 class GpuBenchmarkingWrapper
: public v8::Extension
{
251 GpuBenchmarkingWrapper() :
252 v8::Extension(kGpuBenchmarkingExtensionName
,
253 "if (typeof(chrome) == 'undefined') {"
256 "if (typeof(chrome.gpuBenchmarking) == 'undefined') {"
257 " chrome.gpuBenchmarking = {};"
259 "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {"
260 " native function SetNeedsDisplayOnAllLayers();"
261 " return SetNeedsDisplayOnAllLayers();"
263 "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = function() {"
264 " native function SetRasterizeOnlyVisibleContent();"
265 " return SetRasterizeOnlyVisibleContent();"
267 "chrome.gpuBenchmarking.renderingStats = function() {"
268 " native function GetRenderingStats();"
269 " return GetRenderingStats();"
271 "chrome.gpuBenchmarking.gpuRenderingStats = function() {"
272 " native function GetGpuRenderingStats();"
273 " return GetGpuRenderingStats();"
275 "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {"
276 " native function PrintToSkPicture();"
277 " return PrintToSkPicture(dirname);"
279 "chrome.gpuBenchmarking.DEFAULT_INPUT = 0;"
280 "chrome.gpuBenchmarking.TOUCH_INPUT = 1;"
281 "chrome.gpuBenchmarking.MOUSE_INPUT = 2;"
282 "chrome.gpuBenchmarking.smoothScrollBy = "
283 " function(pixels_to_scroll, opt_callback, opt_start_x,"
284 " opt_start_y, opt_gesture_source_type,"
285 " opt_direction, opt_speed_in_pixels_s) {"
286 " pixels_to_scroll = pixels_to_scroll || 0;"
287 " callback = opt_callback || function() { };"
288 " gesture_source_type = opt_gesture_source_type ||"
289 " chrome.gpuBenchmarking.DEFAULT_INPUT;"
290 " direction = opt_direction || 'down';"
291 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;"
292 " native function BeginSmoothScroll();"
293 " return BeginSmoothScroll(pixels_to_scroll, callback,"
294 " gesture_source_type, direction,"
295 " speed_in_pixels_s, true,"
296 " opt_start_x, opt_start_y);"
298 "chrome.gpuBenchmarking.smoothScrollBySendsTouch = function() {"
299 " native function SmoothScrollSendsTouch();"
300 " return SmoothScrollSendsTouch();"
302 "chrome.gpuBenchmarking.swipe = "
303 " function(direction, distance, opt_callback,"
304 " opt_start_x, opt_start_y,"
305 " opt_speed_in_pixels_s) {"
306 " direction = direction || 'up';"
307 " distance = distance || 0;"
308 " callback = opt_callback || function() { };"
309 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;"
310 " native function BeginSmoothScroll();"
311 " return BeginSmoothScroll(-distance, callback,"
312 " chrome.gpuBenchmarking.TOUCH_INPUT,"
313 " direction, speed_in_pixels_s, false,"
314 " opt_start_x, opt_start_y);"
316 "chrome.gpuBenchmarking.pinchBy = "
317 " function(zoom_in, pixels_to_cover, anchor_x, anchor_y,"
318 " opt_callback, opt_relative_pointer_speed_in_pixels_s) {"
319 " callback = opt_callback || function() { };"
320 " relative_pointer_speed_in_pixels_s ="
321 " opt_relative_pointer_speed_in_pixels_s || 800;"
322 " native function BeginPinch();"
323 " return BeginPinch(zoom_in, pixels_to_cover,"
324 " anchor_x, anchor_y, callback,"
325 " relative_pointer_speed_in_pixels_s);"
327 "chrome.gpuBenchmarking.tap = "
328 " function(position_x, position_y, opt_callback, opt_duration_ms,"
329 " opt_gesture_source_type) {"
330 " callback = opt_callback || function() { };"
331 " duration_ms = opt_duration_ms || 0;"
332 " gesture_source_type = opt_gesture_source_type ||"
333 " chrome.gpuBenchmarking.DEFAULT_INPUT;"
334 " native function BeginTap();"
335 " return BeginTap(position_x, position_y, callback, duration_ms,"
336 " gesture_source_type);"
338 "chrome.gpuBenchmarking.beginWindowSnapshotPNG = function(callback) {"
339 " native function BeginWindowSnapshotPNG();"
340 " BeginWindowSnapshotPNG(callback);"
342 "chrome.gpuBenchmarking.clearImageCache = function() {"
343 " native function ClearImageCache();"
344 " ClearImageCache();"
346 "chrome.gpuBenchmarking.runMicroBenchmark ="
347 " function(name, callback, opt_arguments) {"
348 " arguments = opt_arguments || {};"
349 " native function RunMicroBenchmark();"
350 " return RunMicroBenchmark(name, callback, arguments);"
352 "chrome.gpuBenchmarking.hasGpuProcess = function() {"
353 " native function HasGpuProcess();"
354 " return HasGpuProcess();"
357 virtual v8::Handle
<v8::FunctionTemplate
> GetNativeFunctionTemplate(
358 v8::Isolate
* isolate
,
359 v8::Handle
<v8::String
> name
) OVERRIDE
{
361 v8::String::NewFromUtf8(isolate
, "SetNeedsDisplayOnAllLayers")))
362 return v8::FunctionTemplate::New(isolate
, SetNeedsDisplayOnAllLayers
);
364 v8::String::NewFromUtf8(isolate
, "SetRasterizeOnlyVisibleContent")))
365 return v8::FunctionTemplate::New(isolate
, SetRasterizeOnlyVisibleContent
);
366 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "GetRenderingStats")))
367 return v8::FunctionTemplate::New(isolate
, GetRenderingStats
);
368 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "GetGpuRenderingStats")))
369 return v8::FunctionTemplate::New(isolate
, GetGpuRenderingStats
);
370 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "PrintToSkPicture")))
371 return v8::FunctionTemplate::New(isolate
, PrintToSkPicture
);
372 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "BeginSmoothScroll")))
373 return v8::FunctionTemplate::New(isolate
, BeginSmoothScroll
);
375 v8::String::NewFromUtf8(isolate
, "SmoothScrollSendsTouch")))
376 return v8::FunctionTemplate::New(isolate
, SmoothScrollSendsTouch
);
377 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "BeginPinch")))
378 return v8::FunctionTemplate::New(isolate
, BeginPinch
);
379 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "BeginTap")))
380 return v8::FunctionTemplate::New(isolate
, BeginTap
);
382 v8::String::NewFromUtf8(isolate
, "BeginWindowSnapshotPNG")))
383 return v8::FunctionTemplate::New(isolate
, BeginWindowSnapshotPNG
);
384 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "ClearImageCache")))
385 return v8::FunctionTemplate::New(isolate
, ClearImageCache
);
386 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "RunMicroBenchmark")))
387 return v8::FunctionTemplate::New(isolate
, RunMicroBenchmark
);
388 if (name
->Equals(v8::String::NewFromUtf8(isolate
, "HasGpuProcess")))
389 return v8::FunctionTemplate::New(isolate
, HasGpuProcess
);
391 return v8::Handle
<v8::FunctionTemplate
>();
394 static void SetNeedsDisplayOnAllLayers(
395 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
396 GpuBenchmarkingContext context
;
397 if (!context
.Init(true))
400 context
.compositor()->SetNeedsDisplayOnAllLayers();
403 static void SetRasterizeOnlyVisibleContent(
404 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
405 GpuBenchmarkingContext context
;
406 if (!context
.Init(true))
409 context
.compositor()->SetRasterizeOnlyVisibleContent();
412 static void GetRenderingStats(
413 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
415 GpuBenchmarkingContext context
;
416 if (!context
.Init(false))
419 WebRenderingStatsImpl stats
;
420 context
.render_view_impl()->GetRenderingStats(stats
);
422 content::GpuRenderingStats gpu_stats
;
423 context
.render_view_impl()->GetGpuRenderingStats(&gpu_stats
);
424 BrowserRenderingStats browser_stats
;
425 context
.render_view_impl()->GetBrowserRenderingStats(&browser_stats
);
426 v8::Handle
<v8::Object
> stats_object
= v8::Object::New(args
.GetIsolate());
428 RenderingStatsEnumerator
enumerator(args
.GetIsolate(), stats_object
);
429 stats
.rendering_stats
.EnumerateFields(&enumerator
);
430 gpu_stats
.EnumerateFields(&enumerator
);
431 browser_stats
.EnumerateFields(&enumerator
);
433 args
.GetReturnValue().Set(stats_object
);
436 static void GetGpuRenderingStats(
437 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
439 GpuBenchmarkingContext context
;
440 if (!context
.Init(false))
443 content::GpuRenderingStats gpu_stats
;
444 context
.render_view_impl()->GetGpuRenderingStats(&gpu_stats
);
446 v8::Isolate
* isolate
= args
.GetIsolate();
447 v8::Handle
<v8::Object
> stats_object
= v8::Object::New(isolate
);
448 RenderingStatsEnumerator
enumerator(isolate
, stats_object
);
449 gpu_stats
.EnumerateFields(&enumerator
);
451 args
.GetReturnValue().Set(stats_object
);
454 static void PrintToSkPicture(
455 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
456 if (args
.Length() != 1)
459 v8::String::Utf8Value
dirname(args
[0]);
460 if (dirname
.length() == 0)
463 GpuBenchmarkingContext context
;
464 if (!context
.Init(true))
467 const cc::Layer
* root_layer
= context
.compositor()->GetRootLayer();
471 base::FilePath
dirpath(
472 base::FilePath::StringType(*dirname
, *dirname
+ dirname
.length()));
473 if (!base::CreateDirectory(dirpath
) ||
474 !base::PathIsWritable(dirpath
)) {
475 std::string
msg("Path is not writable: ");
476 msg
.append(dirpath
.MaybeAsASCII());
477 v8::Isolate
* isolate
= args
.GetIsolate();
478 isolate
->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
479 isolate
, msg
.c_str(), v8::String::kNormalString
, msg
.length())));
483 SkPictureSerializer
serializer(dirpath
);
484 serializer
.Serialize(root_layer
);
487 static void OnSyntheticGestureCompleted(
488 CallbackAndContext
* callback_and_context
) {
489 v8::Isolate
* isolate
= callback_and_context
->isolate();
490 v8::HandleScope
scope(isolate
);
491 v8::Handle
<v8::Context
> context
= callback_and_context
->GetContext();
492 v8::Context::Scope
context_scope(context
);
493 WebFrame
* frame
= WebFrame::frameForContext(context
);
495 frame
->callFunctionEvenIfScriptDisabled(
496 callback_and_context
->GetCallback(),
497 v8::Object::New(isolate
),
503 static void SmoothScrollSendsTouch(
504 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
505 // TODO(epenner): Should other platforms emulate touch events?
506 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
507 args
.GetReturnValue().Set(true);
509 args
.GetReturnValue().Set(false);
513 static void BeginSmoothScroll(
514 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
515 GpuBenchmarkingContext context
;
516 if (!context
.Init(false))
519 // The last two arguments can be undefined. We check their validity later.
520 int arglen
= args
.Length();
522 !args
[0]->IsNumber() ||
523 !args
[1]->IsFunction() ||
524 !args
[2]->IsNumber() ||
525 !args
[3]->IsString() ||
526 !args
[4]->IsNumber() ||
527 !args
[5]->IsBoolean()) {
528 args
.GetReturnValue().Set(false);
532 v8::Local
<v8::Function
> callback_local
=
533 v8::Local
<v8::Function
>::Cast(args
[1]);
535 scoped_refptr
<CallbackAndContext
> callback_and_context
=
536 new CallbackAndContext(args
.GetIsolate(),
538 context
.web_frame()->mainWorldScriptContext());
540 scoped_ptr
<SyntheticSmoothScrollGestureParams
> gesture_params(
541 new SyntheticSmoothScrollGestureParams
);
543 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
544 float page_scale_factor
= context
.web_view()->pageScaleFactor();
546 int gesture_source_type
= args
[2]->IntegerValue();
547 if (gesture_source_type
< 0 ||
548 gesture_source_type
> SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX
) {
549 args
.GetReturnValue().Set(false);
552 gesture_params
->gesture_source_type
=
553 static_cast<SyntheticGestureParams::GestureSourceType
>(
554 gesture_source_type
);
556 int distance
= args
[0]->IntegerValue() * page_scale_factor
;
557 v8::String::Utf8Value
direction(args
[3]);
559 std::string
direction_str(*direction
);
560 if (direction_str
== "down")
561 gesture_params
->distance
.set_y(distance
);
562 else if (direction_str
== "up")
563 gesture_params
->distance
.set_y(-distance
);
564 else if (direction_str
== "right")
565 gesture_params
->distance
.set_x(distance
);
566 else if (direction_str
== "left")
567 gesture_params
->distance
.set_x(-distance
);
569 args
.GetReturnValue().Set(false);
573 gesture_params
->speed_in_pixels_s
= args
[4]->IntegerValue();
574 gesture_params
->prevent_fling
= args
[5]->BooleanValue();
576 // Account for the 2 optional arguments, start_x and start_y.
577 if (args
[6]->IsUndefined() || args
[7]->IsUndefined()) {
578 blink::WebRect rect
= context
.render_view_impl()->windowRect();
579 gesture_params
->anchor
.SetPoint(rect
.width
/ 2, rect
.height
/ 2);
580 } else if (args
[6]->IsNumber() && args
[7]->IsNumber()) {
581 gesture_params
->anchor
.SetPoint(
582 args
[6]->IntegerValue() * page_scale_factor
,
583 args
[7]->IntegerValue() * page_scale_factor
);
585 args
.GetReturnValue().Set(false);
589 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
590 // progress, we will leak the callback and context. This needs to be fixed,
592 context
.render_view_impl()->QueueSyntheticGesture(
593 gesture_params
.PassAs
<SyntheticGestureParams
>(),
594 base::Bind(&OnSyntheticGestureCompleted
,
595 callback_and_context
));
597 args
.GetReturnValue().Set(true);
600 static void BeginPinch(
601 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
602 GpuBenchmarkingContext context
;
603 if (!context
.Init(false))
606 int arglen
= args
.Length();
608 !args
[0]->IsBoolean() ||
609 !args
[1]->IsNumber() ||
610 !args
[2]->IsNumber() ||
611 !args
[3]->IsNumber() ||
612 !args
[4]->IsFunction() ||
613 !args
[5]->IsNumber()) {
614 args
.GetReturnValue().Set(false);
618 scoped_ptr
<SyntheticPinchGestureParams
> gesture_params(
619 new SyntheticPinchGestureParams
);
621 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
622 float page_scale_factor
= context
.web_view()->pageScaleFactor();
624 gesture_params
->zoom_in
= args
[0]->BooleanValue();
625 gesture_params
->total_num_pixels_covered
=
626 args
[1]->IntegerValue() * page_scale_factor
;
627 gesture_params
->anchor
.SetPoint(
628 args
[2]->IntegerValue() * page_scale_factor
,
629 args
[3]->IntegerValue() * page_scale_factor
);
630 gesture_params
->relative_pointer_speed_in_pixels_s
=
631 args
[5]->IntegerValue();
633 v8::Local
<v8::Function
> callback_local
=
634 v8::Local
<v8::Function
>::Cast(args
[4]);
636 scoped_refptr
<CallbackAndContext
> callback_and_context
=
637 new CallbackAndContext(args
.GetIsolate(),
639 context
.web_frame()->mainWorldScriptContext());
642 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
643 // progress, we will leak the callback and context. This needs to be fixed,
645 context
.render_view_impl()->QueueSyntheticGesture(
646 gesture_params
.PassAs
<SyntheticGestureParams
>(),
647 base::Bind(&OnSyntheticGestureCompleted
,
648 callback_and_context
));
650 args
.GetReturnValue().Set(true);
653 static void BeginTap(
654 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
655 GpuBenchmarkingContext context
;
656 if (!context
.Init(false))
659 int arglen
= args
.Length();
661 !args
[0]->IsNumber() ||
662 !args
[1]->IsNumber() ||
663 !args
[2]->IsFunction() ||
664 !args
[3]->IsNumber() ||
665 !args
[4]->IsNumber()) {
666 args
.GetReturnValue().Set(false);
670 scoped_ptr
<SyntheticTapGestureParams
> gesture_params(
671 new SyntheticTapGestureParams
);
673 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
674 float page_scale_factor
= context
.web_view()->pageScaleFactor();
676 gesture_params
->position
.SetPoint(
677 args
[0]->IntegerValue() * page_scale_factor
,
678 args
[1]->IntegerValue() * page_scale_factor
);
679 gesture_params
->duration_ms
= args
[3]->IntegerValue();
681 int gesture_source_type
= args
[4]->IntegerValue();
682 if (gesture_source_type
< 0 ||
683 gesture_source_type
> SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX
) {
684 args
.GetReturnValue().Set(false);
687 gesture_params
->gesture_source_type
=
688 static_cast<SyntheticGestureParams::GestureSourceType
>(
689 gesture_source_type
);
691 v8::Local
<v8::Function
> callback_local
=
692 v8::Local
<v8::Function
>::Cast(args
[2]);
694 scoped_refptr
<CallbackAndContext
> callback_and_context
=
695 new CallbackAndContext(args
.GetIsolate(),
697 context
.web_frame()->mainWorldScriptContext());
700 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
701 // progress, we will leak the callback and context. This needs to be fixed,
703 context
.render_view_impl()->QueueSyntheticGesture(
704 gesture_params
.PassAs
<SyntheticGestureParams
>(),
705 base::Bind(&OnSyntheticGestureCompleted
,
706 callback_and_context
));
708 args
.GetReturnValue().Set(true);
711 static void OnSnapshotCompleted(CallbackAndContext
* callback_and_context
,
712 const gfx::Size
& size
,
713 const std::vector
<unsigned char>& png
) {
714 v8::Isolate
* isolate
= callback_and_context
->isolate();
715 v8::HandleScope
scope(isolate
);
716 v8::Handle
<v8::Context
> context
= callback_and_context
->GetContext();
717 v8::Context::Scope
context_scope(context
);
718 WebFrame
* frame
= WebFrame::frameForContext(context
);
721 v8::Handle
<v8::Value
> result
;
723 if(!size
.IsEmpty()) {
724 v8::Handle
<v8::Object
> result_object
;
725 result_object
= v8::Object::New(isolate
);
727 result_object
->Set(v8::String::NewFromUtf8(isolate
, "width"),
728 v8::Number::New(isolate
, size
.width()));
729 result_object
->Set(v8::String::NewFromUtf8(isolate
, "height"),
730 v8::Number::New(isolate
, size
.height()));
732 std::string base64_png
;
733 base::Base64Encode(base::StringPiece(
734 reinterpret_cast<const char*>(&*png
.begin()), png
.size()),
737 result_object
->Set(v8::String::NewFromUtf8(isolate
, "data"),
738 v8::String::NewFromUtf8(isolate
,
740 v8::String::kNormalString
,
743 result
= result_object
;
745 result
= v8::Null(isolate
);
748 v8::Handle
<v8::Value
> argv
[] = { result
};
750 frame
->callFunctionEvenIfScriptDisabled(
751 callback_and_context
->GetCallback(),
752 v8::Object::New(isolate
),
758 static void BeginWindowSnapshotPNG(
759 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
760 GpuBenchmarkingContext context
;
761 if (!context
.Init(false))
764 if (!args
[0]->IsFunction())
767 v8::Local
<v8::Function
> callback_local
=
768 v8::Local
<v8::Function
>::Cast(args
[0]);
770 scoped_refptr
<CallbackAndContext
> callback_and_context
=
771 new CallbackAndContext(args
.GetIsolate(),
773 context
.web_frame()->mainWorldScriptContext());
775 context
.render_view_impl()->GetWindowSnapshot(
776 base::Bind(&OnSnapshotCompleted
, callback_and_context
));
779 static void ClearImageCache(
780 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
781 WebImageCache::clear();
784 static void OnMicroBenchmarkCompleted(
785 CallbackAndContext
* callback_and_context
,
786 scoped_ptr
<base::Value
> result
) {
787 v8::Isolate
* isolate
= callback_and_context
->isolate();
788 v8::HandleScope
scope(isolate
);
789 v8::Handle
<v8::Context
> context
= callback_and_context
->GetContext();
790 v8::Context::Scope
context_scope(context
);
791 WebFrame
* frame
= WebFrame::frameForContext(context
);
793 scoped_ptr
<V8ValueConverter
> converter
=
794 make_scoped_ptr(V8ValueConverter::create());
795 v8::Handle
<v8::Value
> value
= converter
->ToV8Value(result
.get(), context
);
796 v8::Handle
<v8::Value
> argv
[] = { value
};
798 frame
->callFunctionEvenIfScriptDisabled(
799 callback_and_context
->GetCallback(),
800 v8::Object::New(isolate
),
806 static void RunMicroBenchmark(
807 const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
808 GpuBenchmarkingContext context
;
809 if (!context
.Init(true)) {
810 args
.GetReturnValue().Set(false);
814 if (args
.Length() != 3 ||
815 !args
[0]->IsString() ||
816 !args
[1]->IsFunction() ||
817 !args
[2]->IsObject()) {
818 args
.GetReturnValue().Set(false);
822 v8::Local
<v8::Function
> callback_local
=
823 v8::Local
<v8::Function
>::Cast(args
[1]);
825 scoped_refptr
<CallbackAndContext
> callback_and_context
=
826 new CallbackAndContext(args
.GetIsolate(),
828 context
.web_frame()->mainWorldScriptContext());
830 scoped_ptr
<V8ValueConverter
> converter
=
831 make_scoped_ptr(V8ValueConverter::create());
832 v8::Handle
<v8::Context
> v8_context
= callback_and_context
->GetContext();
833 scoped_ptr
<base::Value
> value
=
834 make_scoped_ptr(converter
->FromV8Value(args
[2], v8_context
));
836 v8::String::Utf8Value
benchmark(args
[0]);
838 args
.GetReturnValue().Set(context
.compositor()->ScheduleMicroBenchmark(
839 std::string(*benchmark
),
841 base::Bind(&OnMicroBenchmarkCompleted
, callback_and_context
)));
844 static void HasGpuProcess(const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
845 GpuChannelHost
* gpu_channel
= RenderThreadImpl::current()->GetGpuChannel();
846 args
.GetReturnValue().Set(!!gpu_channel
);
850 v8::Extension
* GpuBenchmarkingExtension::Get() {
851 return new GpuBenchmarkingWrapper();
854 } // namespace content