- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / gpu / gpu_benchmarking_extension.cc
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.
4
5 #include "content/renderer/gpu/gpu_benchmarking_extension.h"
6
7 #include <string>
8
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/public/renderer/render_thread.h"
18 #include "content/public/renderer/v8_value_converter.h"
19 #include "content/renderer/gpu/render_widget_compositor.h"
20 #include "content/renderer/render_thread_impl.h"
21 #include "content/renderer/render_view_impl.h"
22 #include "content/renderer/skia_benchmarking_extension.h"
23 #include "third_party/WebKit/public/web/WebFrame.h"
24 #include "third_party/WebKit/public/web/WebImageCache.h"
25 #include "third_party/WebKit/public/web/WebView.h"
26 #include "third_party/skia/include/core/SkData.h"
27 #include "third_party/skia/include/core/SkGraphics.h"
28 #include "third_party/skia/include/core/SkPicture.h"
29 #include "third_party/skia/include/core/SkPixelRef.h"
30 #include "third_party/skia/include/core/SkStream.h"
31 #include "ui/gfx/codec/png_codec.h"
32 #include "v8/include/v8.h"
33 #include "webkit/renderer/compositor_bindings/web_rendering_stats_impl.h"
34
35 using WebKit::WebCanvas;
36 using WebKit::WebFrame;
37 using WebKit::WebImageCache;
38 using WebKit::WebPrivatePtr;
39 using WebKit::WebRenderingStatsImpl;
40 using WebKit::WebSize;
41 using WebKit::WebView;
42
43 const char kGpuBenchmarkingExtensionName[] = "v8/GpuBenchmarking";
44
45 static SkData* EncodeBitmapToData(size_t* offset, const SkBitmap& bm) {
46     SkPixelRef* pr = bm.pixelRef();
47     if (pr != NULL) {
48         SkData* data = pr->refEncodedData();
49         if (data != NULL) {
50             *offset = bm.pixelRefOffset();
51             return data;
52         }
53     }
54     std::vector<unsigned char> vector;
55     if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
56         return SkData::NewWithCopy(&vector.front() , vector.size());
57     }
58     return NULL;
59 }
60
61 namespace {
62
63 class SkPictureSerializer {
64  public:
65   explicit SkPictureSerializer(const base::FilePath& dirpath)
66       : dirpath_(dirpath),
67         layer_id_(0) {
68     // Let skia register known effect subclasses. This basically enables
69     // reflection on those subclasses required for picture serialization.
70     content::SkiaBenchmarkingExtension::InitSkGraphics();
71   }
72
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());
80     }
81
82     skia::RefPtr<SkPicture> picture = layer->GetPicture();
83     if (!picture)
84       return;
85
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.
89     // CRBUG: 139640.
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);
96   }
97
98  private:
99   base::FilePath dirpath_;
100   int layer_id_;
101 };
102
103 class RenderingStatsEnumerator : public cc::RenderingStats::Enumerator {
104  public:
105   RenderingStatsEnumerator(v8::Handle<v8::Object> stats_object)
106       : stats_object(stats_object) { }
107
108   virtual void AddInt64(const char* name, int64 value) OVERRIDE {
109     stats_object->Set(v8::String::New(name), v8::Number::New(value));
110   }
111
112   virtual void AddDouble(const char* name, double value) OVERRIDE {
113     stats_object->Set(v8::String::New(name), v8::Number::New(value));
114   }
115
116   virtual void AddInt(const char* name, int value) OVERRIDE {
117     stats_object->Set(v8::String::New(name), v8::Integer::New(value));
118   }
119
120   virtual void AddTimeDeltaInSecondsF(const char* name,
121                                       const base::TimeDelta& value) OVERRIDE {
122     stats_object->Set(v8::String::New(name),
123                       v8::Number::New(value.InSecondsF()));
124   }
125
126  private:
127   v8::Handle<v8::Object> stats_object;
128 };
129
130 }  // namespace
131
132 namespace content {
133
134 namespace {
135
136 class CallbackAndContext : public base::RefCounted<CallbackAndContext> {
137  public:
138   CallbackAndContext(v8::Isolate* isolate,
139                      v8::Handle<v8::Function> callback,
140                      v8::Handle<v8::Context> context)
141       : isolate_(isolate) {
142     callback_.Reset(isolate_, callback);
143     context_.Reset(isolate_, context);
144   }
145
146   v8::Isolate* isolate() {
147     return isolate_;
148   }
149
150   v8::Handle<v8::Function> GetCallback() {
151     return v8::Local<v8::Function>::New(isolate_, callback_);
152   }
153
154   v8::Handle<v8::Context> GetContext() {
155     return v8::Local<v8::Context>::New(isolate_, context_);
156   }
157
158  private:
159   friend class base::RefCounted<CallbackAndContext>;
160
161   virtual ~CallbackAndContext() {
162     callback_.Dispose();
163     context_.Dispose();
164   }
165
166   v8::Isolate* isolate_;
167   v8::Persistent<v8::Function> callback_;
168   v8::Persistent<v8::Context> context_;
169   DISALLOW_COPY_AND_ASSIGN(CallbackAndContext);
170 };
171
172 class GpuBenchmarkingContext {
173  public:
174   GpuBenchmarkingContext()
175       : web_frame_(NULL),
176         web_view_(NULL),
177         render_view_impl_(NULL),
178         compositor_(NULL) {}
179
180   bool Init(bool init_compositor) {
181     web_frame_ = WebFrame::frameForCurrentContext();
182     if (!web_frame_)
183       return false;
184
185     web_view_ = web_frame_->view();
186     if (!web_view_) {
187       web_frame_ = NULL;
188       return false;
189     }
190
191     render_view_impl_ = RenderViewImpl::FromWebView(web_view_);
192     if (!render_view_impl_) {
193       web_frame_ = NULL;
194       web_view_ = NULL;
195       return false;
196     }
197
198     if (!init_compositor)
199       return true;
200
201     compositor_ = render_view_impl_->compositor();
202     if (!compositor_) {
203       web_frame_ = NULL;
204       web_view_ = NULL;
205       render_view_impl_ = NULL;
206       return false;
207     }
208
209     return true;
210   }
211
212   WebFrame* web_frame() const {
213     DCHECK(web_frame_ != NULL);
214     return web_frame_;
215   }
216   WebView* web_view() const {
217     DCHECK(web_view_ != NULL);
218     return web_view_;
219   }
220   RenderViewImpl* render_view_impl() const {
221     DCHECK(render_view_impl_ != NULL);
222     return render_view_impl_;
223   }
224   RenderWidgetCompositor* compositor() const {
225     DCHECK(compositor_ != NULL);
226     return compositor_;
227   }
228
229  private:
230   WebFrame* web_frame_;
231   WebView* web_view_;
232   RenderViewImpl* render_view_impl_;
233   RenderWidgetCompositor* compositor_;
234
235   DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext);
236 };
237
238 }  // namespace
239
240 class GpuBenchmarkingWrapper : public v8::Extension {
241  public:
242   GpuBenchmarkingWrapper() :
243       v8::Extension(kGpuBenchmarkingExtensionName,
244           "if (typeof(chrome) == 'undefined') {"
245           "  chrome = {};"
246           "};"
247           "if (typeof(chrome.gpuBenchmarking) == 'undefined') {"
248           "  chrome.gpuBenchmarking = {};"
249           "};"
250           "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {"
251           "  native function SetNeedsDisplayOnAllLayers();"
252           "  return SetNeedsDisplayOnAllLayers();"
253           "};"
254           "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = function() {"
255           "  native function SetRasterizeOnlyVisibleContent();"
256           "  return SetRasterizeOnlyVisibleContent();"
257           "};"
258           "chrome.gpuBenchmarking.renderingStats = function() {"
259           "  native function GetRenderingStats();"
260           "  return GetRenderingStats();"
261           "};"
262           "chrome.gpuBenchmarking.gpuRenderingStats = function() {"
263           "  native function GetGpuRenderingStats();"
264           "  return GetGpuRenderingStats();"
265           "};"
266           "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {"
267           "  native function PrintToSkPicture();"
268           "  return PrintToSkPicture(dirname);"
269           "};"
270           "chrome.gpuBenchmarking.smoothScrollBy = "
271           "    function(pixels_to_scroll, opt_callback, opt_mouse_event_x,"
272           "             opt_mouse_event_y) {"
273           "  pixels_to_scroll = pixels_to_scroll || 0;"
274           "  callback = opt_callback || function() { };"
275           "  native function BeginSmoothScroll();"
276           "  if (typeof opt_mouse_event_x !== 'undefined' &&"
277           "      typeof opt_mouse_event_y !== 'undefined') {"
278           "    return BeginSmoothScroll(pixels_to_scroll >= 0, callback,"
279           "                             Math.abs(pixels_to_scroll),"
280           "                             opt_mouse_event_x, opt_mouse_event_y);"
281           "  } else {"
282           "    return BeginSmoothScroll(pixels_to_scroll >= 0, callback,"
283           "                             Math.abs(pixels_to_scroll));"
284           "  }"
285           "};"
286           "chrome.gpuBenchmarking.smoothScrollBySendsTouch = function() {"
287           "  native function SmoothScrollSendsTouch();"
288           "  return SmoothScrollSendsTouch();"
289           "};"
290           "chrome.gpuBenchmarking.pinchBy = "
291           "    function(zoom_in, pixels_to_move, anchor_x, anchor_y,"
292           "             opt_callback) {"
293           "  callback = opt_callback || function() { };"
294           "  native function BeginPinch();"
295           "  return BeginPinch(zoom_in, pixels_to_move,"
296           "                    anchor_x, anchor_y, callback);"
297           "};"
298           "chrome.gpuBenchmarking.beginWindowSnapshotPNG = function(callback) {"
299           "  native function BeginWindowSnapshotPNG();"
300           "  BeginWindowSnapshotPNG(callback);"
301           "};"
302           "chrome.gpuBenchmarking.clearImageCache = function() {"
303           "  native function ClearImageCache();"
304           "  ClearImageCache();"
305           "};"
306           "chrome.gpuBenchmarking.runMicroBenchmark ="
307           "    function(name, callback, opt_arguments) {"
308           "  arguments = opt_arguments || {};"
309           "  native function RunMicroBenchmark();"
310           "  return RunMicroBenchmark(name, callback, arguments);"
311           "};"
312           "chrome.gpuBenchmarking.hasGpuProcess = function() {"
313           "  native function HasGpuProcess();"
314           "  return HasGpuProcess();"
315           "};") {}
316
317   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
318       v8::Handle<v8::String> name) OVERRIDE {
319     if (name->Equals(v8::String::New("SetNeedsDisplayOnAllLayers")))
320       return v8::FunctionTemplate::New(SetNeedsDisplayOnAllLayers);
321     if (name->Equals(v8::String::New("SetRasterizeOnlyVisibleContent")))
322       return v8::FunctionTemplate::New(SetRasterizeOnlyVisibleContent);
323     if (name->Equals(v8::String::New("GetRenderingStats")))
324       return v8::FunctionTemplate::New(GetRenderingStats);
325     if (name->Equals(v8::String::New("GetGpuRenderingStats")))
326       return v8::FunctionTemplate::New(GetGpuRenderingStats);
327     if (name->Equals(v8::String::New("PrintToSkPicture")))
328       return v8::FunctionTemplate::New(PrintToSkPicture);
329     if (name->Equals(v8::String::New("BeginSmoothScroll")))
330       return v8::FunctionTemplate::New(BeginSmoothScroll);
331     if (name->Equals(v8::String::New("SmoothScrollSendsTouch")))
332       return v8::FunctionTemplate::New(SmoothScrollSendsTouch);
333     if (name->Equals(v8::String::New("BeginPinch")))
334       return v8::FunctionTemplate::New(BeginPinch);
335     if (name->Equals(v8::String::New("BeginWindowSnapshotPNG")))
336       return v8::FunctionTemplate::New(BeginWindowSnapshotPNG);
337     if (name->Equals(v8::String::New("ClearImageCache")))
338       return v8::FunctionTemplate::New(ClearImageCache);
339     if (name->Equals(v8::String::New("RunMicroBenchmark")))
340       return v8::FunctionTemplate::New(RunMicroBenchmark);
341     if (name->Equals(v8::String::New("HasGpuProcess")))
342       return v8::FunctionTemplate::New(HasGpuProcess);
343
344     return v8::Handle<v8::FunctionTemplate>();
345   }
346
347   static void SetNeedsDisplayOnAllLayers(
348       const v8::FunctionCallbackInfo<v8::Value>& args) {
349     GpuBenchmarkingContext context;
350     if (!context.Init(true))
351       return;
352
353     context.compositor()->SetNeedsDisplayOnAllLayers();
354   }
355
356   static void SetRasterizeOnlyVisibleContent(
357       const v8::FunctionCallbackInfo<v8::Value>& args) {
358     GpuBenchmarkingContext context;
359     if (!context.Init(true))
360       return;
361
362     context.compositor()->SetRasterizeOnlyVisibleContent();
363   }
364
365   static void GetRenderingStats(
366       const v8::FunctionCallbackInfo<v8::Value>& args) {
367
368     GpuBenchmarkingContext context;
369     if (!context.Init(false))
370       return;
371
372     WebRenderingStatsImpl stats;
373     context.render_view_impl()->GetRenderingStats(stats);
374
375     content::GpuRenderingStats gpu_stats;
376     context.render_view_impl()->GetGpuRenderingStats(&gpu_stats);
377     BrowserRenderingStats browser_stats;
378     context.render_view_impl()->GetBrowserRenderingStats(&browser_stats);
379     v8::Handle<v8::Object> stats_object = v8::Object::New();
380
381     RenderingStatsEnumerator enumerator(stats_object);
382     stats.rendering_stats.EnumerateFields(&enumerator);
383     gpu_stats.EnumerateFields(&enumerator);
384     browser_stats.EnumerateFields(&enumerator);
385
386     args.GetReturnValue().Set(stats_object);
387   }
388
389   static void GetGpuRenderingStats(
390       const v8::FunctionCallbackInfo<v8::Value>& args) {
391
392     GpuBenchmarkingContext context;
393     if (!context.Init(false))
394       return;
395
396     content::GpuRenderingStats gpu_stats;
397     context.render_view_impl()->GetGpuRenderingStats(&gpu_stats);
398
399     v8::Handle<v8::Object> stats_object = v8::Object::New();
400     RenderingStatsEnumerator enumerator(stats_object);
401     gpu_stats.EnumerateFields(&enumerator);
402
403     args.GetReturnValue().Set(stats_object);
404   }
405
406   static void PrintToSkPicture(
407       const v8::FunctionCallbackInfo<v8::Value>& args) {
408     if (args.Length() != 1)
409       return;
410
411     v8::String::AsciiValue dirname(args[0]);
412     if (dirname.length() == 0)
413       return;
414
415     GpuBenchmarkingContext context;
416     if (!context.Init(true))
417       return;
418
419     const cc::Layer* root_layer = context.compositor()->GetRootLayer();
420     if (!root_layer)
421       return;
422
423     base::FilePath dirpath(
424         base::FilePath::StringType(*dirname, *dirname + dirname.length()));
425     if (!file_util::CreateDirectory(dirpath) ||
426         !base::PathIsWritable(dirpath)) {
427       std::string msg("Path is not writable: ");
428       msg.append(dirpath.MaybeAsASCII());
429       v8::ThrowException(v8::Exception::Error(
430           v8::String::New(msg.c_str(), msg.length())));
431       return;
432     }
433
434     SkPictureSerializer serializer(dirpath);
435     serializer.Serialize(root_layer);
436   }
437
438   static void OnSmoothScrollCompleted(
439       CallbackAndContext* callback_and_context) {
440     v8::HandleScope scope(callback_and_context->isolate());
441     v8::Handle<v8::Context> context = callback_and_context->GetContext();
442     v8::Context::Scope context_scope(context);
443     WebFrame* frame = WebFrame::frameForContext(context);
444     if (frame) {
445       frame->callFunctionEvenIfScriptDisabled(
446           callback_and_context->GetCallback(), v8::Object::New(), 0, NULL);
447     }
448   }
449
450   static void SmoothScrollSendsTouch(
451       const v8::FunctionCallbackInfo<v8::Value>& args) {
452     // TODO(epenner): Should other platforms emulate touch events?
453 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
454     args.GetReturnValue().Set(true);
455 #else
456     args.GetReturnValue().Set(false);
457 #endif
458   }
459
460   static void BeginSmoothScroll(
461       const v8::FunctionCallbackInfo<v8::Value>& args) {
462     GpuBenchmarkingContext context;
463     if (!context.Init(false))
464       return;
465
466     // Account for the 2 optional arguments, mouse_event_x and mouse_event_y.
467     int arglen = args.Length();
468     if (arglen < 3 ||
469         !args[0]->IsBoolean() ||
470         !args[1]->IsFunction() ||
471         !args[2]->IsNumber()) {
472       args.GetReturnValue().Set(false);
473       return;
474     }
475
476     bool scroll_down = args[0]->BooleanValue();
477     v8::Local<v8::Function> callback_local =
478         v8::Local<v8::Function>::Cast(args[1]);
479
480     scoped_refptr<CallbackAndContext> callback_and_context =
481         new CallbackAndContext(args.GetIsolate(),
482                                callback_local,
483                                context.web_frame()->mainWorldScriptContext());
484
485     int pixels_to_scroll = args[2]->IntegerValue();
486
487     int mouse_event_x = 0;
488     int mouse_event_y = 0;
489
490     if (arglen == 3) {
491       WebKit::WebRect rect = context.render_view_impl()->windowRect();
492       mouse_event_x = rect.x + rect.width / 2;
493       mouse_event_y = rect.y + rect.height / 2;
494     } else {
495       if (arglen != 5 ||
496           !args[3]->IsNumber() ||
497           !args[4]->IsNumber()) {
498         args.GetReturnValue().Set(false);
499         return;
500       }
501
502       mouse_event_x = args[3]->IntegerValue() *
503           context.web_view()->pageScaleFactor();
504       mouse_event_y = args[4]->IntegerValue() *
505           context.web_view()->pageScaleFactor();
506     }
507
508     // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
509     // progress, we will leak the callback and context. This needs to be fixed,
510     // somehow.
511     context.render_view_impl()->BeginSmoothScroll(
512         scroll_down,
513         base::Bind(&OnSmoothScrollCompleted,
514                    callback_and_context),
515         pixels_to_scroll,
516         mouse_event_x,
517         mouse_event_y);
518
519     args.GetReturnValue().Set(true);
520   }
521
522   static void BeginPinch(
523       const v8::FunctionCallbackInfo<v8::Value>& args) {
524     GpuBenchmarkingContext context;
525     if (!context.Init(false))
526       return;
527
528     int arglen = args.Length();
529     if (arglen < 5 ||
530         !args[0]->IsBoolean() ||
531         !args[1]->IsNumber() ||
532         !args[2]->IsNumber() ||
533         !args[3]->IsNumber() ||
534         !args[4]->IsFunction()) {
535       args.GetReturnValue().Set(false);
536       return;
537     }
538
539     bool zoom_in = args[0]->BooleanValue();
540     int pixels_to_move = args[1]->IntegerValue();
541     int anchor_x = args[2]->IntegerValue();
542     int anchor_y = args[3]->IntegerValue();
543
544     v8::Local<v8::Function> callback_local =
545         v8::Local<v8::Function>::Cast(args[4]);
546
547     scoped_refptr<CallbackAndContext> callback_and_context =
548         new CallbackAndContext(args.GetIsolate(),
549                                callback_local,
550                                context.web_frame()->mainWorldScriptContext());
551
552
553     // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
554     // progress, we will leak the callback and context. This needs to be fixed,
555     // somehow.
556     context.render_view_impl()->BeginPinch(
557         zoom_in,
558         pixels_to_move,
559         anchor_x,
560         anchor_y,
561         base::Bind(&OnSmoothScrollCompleted,
562                    callback_and_context));
563
564     args.GetReturnValue().Set(true);
565   }
566
567   static void OnSnapshotCompleted(CallbackAndContext* callback_and_context,
568                                   const gfx::Size& size,
569                                   const std::vector<unsigned char>& png) {
570     v8::HandleScope scope(callback_and_context->isolate());
571     v8::Handle<v8::Context> context = callback_and_context->GetContext();
572     v8::Context::Scope context_scope(context);
573     WebFrame* frame = WebFrame::frameForContext(context);
574     if (frame) {
575
576       v8::Handle<v8::Value> result;
577
578       if(!size.IsEmpty()) {
579         v8::Handle<v8::Object> result_object;
580         result_object = v8::Object::New();
581
582         result_object->Set(v8::String::New("width"),
583                            v8::Number::New(size.width()));
584         result_object->Set(v8::String::New("height"),
585                            v8::Number::New(size.height()));
586
587         std::string base64_png;
588         base::Base64Encode(base::StringPiece(
589             reinterpret_cast<const char*>(&*png.begin()), png.size()),
590             &base64_png);
591
592         result_object->Set(v8::String::New("data"),
593             v8::String::New(base64_png.c_str(), base64_png.size()));
594
595         result = result_object;
596       } else {
597         result = v8::Null();
598       }
599
600       v8::Handle<v8::Value> argv[] = { result };
601
602       frame->callFunctionEvenIfScriptDisabled(
603           callback_and_context->GetCallback(), v8::Object::New(), 1, argv);
604     }
605   }
606
607   static void BeginWindowSnapshotPNG(
608       const v8::FunctionCallbackInfo<v8::Value>& args) {
609     GpuBenchmarkingContext context;
610     if (!context.Init(false))
611       return;
612
613     if (!args[0]->IsFunction())
614       return;
615
616     v8::Local<v8::Function> callback_local =
617         v8::Local<v8::Function>::Cast(args[0]);
618
619     scoped_refptr<CallbackAndContext> callback_and_context =
620         new CallbackAndContext(args.GetIsolate(),
621                                callback_local,
622                                context.web_frame()->mainWorldScriptContext());
623
624     context.render_view_impl()->GetWindowSnapshot(
625         base::Bind(&OnSnapshotCompleted, callback_and_context));
626   }
627
628   static void ClearImageCache(
629       const v8::FunctionCallbackInfo<v8::Value>& args) {
630     WebImageCache::clear();
631   }
632
633   static void OnMicroBenchmarkCompleted(
634       CallbackAndContext* callback_and_context,
635       scoped_ptr<base::Value> result) {
636     v8::HandleScope scope(callback_and_context->isolate());
637     v8::Handle<v8::Context> context = callback_and_context->GetContext();
638     v8::Context::Scope context_scope(context);
639     WebFrame* frame = WebFrame::frameForContext(context);
640     if (frame) {
641       scoped_ptr<V8ValueConverter> converter =
642           make_scoped_ptr(V8ValueConverter::create());
643       v8::Handle<v8::Value> value = converter->ToV8Value(result.get(), context);
644       v8::Handle<v8::Value> argv[] = { value };
645
646       frame->callFunctionEvenIfScriptDisabled(
647           callback_and_context->GetCallback(), v8::Object::New(), 1, argv);
648     }
649   }
650
651   static void RunMicroBenchmark(
652       const v8::FunctionCallbackInfo<v8::Value>& args) {
653     GpuBenchmarkingContext context;
654     if (!context.Init(true)) {
655       args.GetReturnValue().Set(false);
656       return;
657     }
658
659     if (args.Length() != 3 ||
660         !args[0]->IsString() ||
661         !args[1]->IsFunction() ||
662         !args[2]->IsObject()) {
663       args.GetReturnValue().Set(false);
664       return;
665     }
666
667     v8::Local<v8::Function> callback_local =
668         v8::Local<v8::Function>::Cast(args[1]);
669
670     scoped_refptr<CallbackAndContext> callback_and_context =
671         new CallbackAndContext(args.GetIsolate(),
672                                callback_local,
673                                context.web_frame()->mainWorldScriptContext());
674
675     scoped_ptr<V8ValueConverter> converter =
676         make_scoped_ptr(V8ValueConverter::create());
677     v8::Handle<v8::Context> v8_context = callback_and_context->GetContext();
678     scoped_ptr<base::Value> value =
679         make_scoped_ptr(converter->FromV8Value(args[2], v8_context));
680
681     v8::String::Utf8Value benchmark(args[0]);
682     DCHECK(*benchmark);
683     args.GetReturnValue().Set(context.compositor()->ScheduleMicroBenchmark(
684         std::string(*benchmark),
685         value.Pass(),
686         base::Bind(&OnMicroBenchmarkCompleted, callback_and_context)));
687   }
688
689   static void HasGpuProcess(const v8::FunctionCallbackInfo<v8::Value>& args) {
690     GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
691     args.GetReturnValue().Set(!!gpu_channel);
692   }
693 };
694
695 v8::Extension* GpuBenchmarkingExtension::Get() {
696   return new GpuBenchmarkingWrapper();
697 }
698
699 }  // namespace content