Update To 11.40.268.0
[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/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/chrome_object_extensions_utils.h"
22 #include "content/renderer/gpu/render_widget_compositor.h"
23 #include "content/renderer/render_thread_impl.h"
24 #include "content/renderer/render_view_impl.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"
29 #include "third_party/WebKit/public/web/WebImageCache.h"
30 #include "third_party/WebKit/public/web/WebKit.h"
31 #include "third_party/WebKit/public/web/WebLocalFrame.h"
32 #include "third_party/WebKit/public/web/WebView.h"
33 #include "third_party/skia/include/core/SkData.h"
34 #include "third_party/skia/include/core/SkGraphics.h"
35 #include "third_party/skia/include/core/SkPicture.h"
36 #include "third_party/skia/include/core/SkPixelRef.h"
37 #include "third_party/skia/include/core/SkStream.h"
38 #include "ui/gfx/codec/png_codec.h"
39 #include "v8/include/v8.h"
40
41 using blink::WebCanvas;
42 using blink::WebLocalFrame;
43 using blink::WebImageCache;
44 using blink::WebPrivatePtr;
45 using blink::WebSize;
46 using blink::WebView;
47
48 namespace content {
49
50 namespace {
51
52 // offset parameter is deprecated/ignored, and will be remove from the
53 // signature in a future skia release. <reed@google.com>
54 SkData* EncodeBitmapToData(size_t* offset, const SkBitmap& bm) {
55   SkPixelRef* pr = bm.pixelRef();
56   if (pr != NULL) {
57     SkData* data = pr->refEncodedData();
58     if (data != NULL)
59       return data;
60   }
61   std::vector<unsigned char> vector;
62   if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
63     return SkData::NewWithCopy(&vector.front(), vector.size());
64   }
65   return NULL;
66 }
67
68 class SkPictureSerializer {
69  public:
70   explicit SkPictureSerializer(const base::FilePath& dirpath)
71       : dirpath_(dirpath),
72         layer_id_(0) {
73     // Let skia register known effect subclasses. This basically enables
74     // reflection on those subclasses required for picture serialization.
75     SkiaBenchmarking::Initialize();
76   }
77
78   // Recursively serializes the layer tree.
79   // Each layer in the tree is serialized into a separate skp file
80   // in the given directory.
81   void Serialize(const cc::Layer* layer) {
82     const cc::LayerList& children = layer->children();
83     for (size_t i = 0; i < children.size(); ++i) {
84       Serialize(children[i].get());
85     }
86
87     skia::RefPtr<SkPicture> picture = layer->GetPicture();
88     if (!picture)
89       return;
90
91     // Serialize picture to file.
92     // TODO(alokp): Note that for this to work Chrome needs to be launched with
93     // --no-sandbox command-line flag. Get rid of this limitation.
94     // CRBUG: 139640.
95     std::string filename = "layer_" + base::IntToString(layer_id_++) + ".skp";
96     std::string filepath = dirpath_.AppendASCII(filename).MaybeAsASCII();
97     DCHECK(!filepath.empty());
98     SkFILEWStream file(filepath.c_str());
99     DCHECK(file.isValid());
100     picture->serialize(&file, &EncodeBitmapToData);
101   }
102
103  private:
104   base::FilePath dirpath_;
105   int layer_id_;
106 };
107
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 }
116
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 }
124
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 }
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_.Reset();
163     context_.Reset();
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_ = WebLocalFrame::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   WebLocalFrame* 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   WebLocalFrame* web_frame_;
231   WebView* web_view_;
232   RenderViewImpl* render_view_impl_;
233   RenderWidgetCompositor* compositor_;
234
235   DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext);
236 };
237
238 void OnMicroBenchmarkCompleted(
239     CallbackAndContext* callback_and_context,
240     scoped_ptr<base::Value> result) {
241   v8::Isolate* isolate = callback_and_context->isolate();
242   v8::HandleScope scope(isolate);
243   v8::Handle<v8::Context> context = callback_and_context->GetContext();
244   v8::Context::Scope context_scope(context);
245   WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
246   if (frame) {
247     scoped_ptr<V8ValueConverter> converter =
248         make_scoped_ptr(V8ValueConverter::create());
249     v8::Handle<v8::Value> value = converter->ToV8Value(result.get(), context);
250     v8::Handle<v8::Value> argv[] = { value };
251
252     frame->callFunctionEvenIfScriptDisabled(
253         callback_and_context->GetCallback(),
254         v8::Object::New(isolate),
255         1,
256         argv);
257   }
258 }
259
260 void OnSnapshotCompleted(CallbackAndContext* callback_and_context,
261                          const gfx::Size& size,
262                          const std::vector<unsigned char>& png) {
263   v8::Isolate* isolate = callback_and_context->isolate();
264   v8::HandleScope scope(isolate);
265   v8::Handle<v8::Context> context = callback_and_context->GetContext();
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);
295     }
296
297     v8::Handle<v8::Value> argv[] = {result};
298
299     frame->callFunctionEvenIfScriptDisabled(
300         callback_and_context->GetCallback(), v8::Object::New(isolate), 1, argv);
301   }
302 }
303
304 void OnSyntheticGestureCompleted(CallbackAndContext* callback_and_context) {
305   v8::Isolate* isolate = callback_and_context->isolate();
306   v8::HandleScope scope(isolate);
307   v8::Handle<v8::Context> context = callback_and_context->GetContext();
308   v8::Context::Scope context_scope(context);
309   WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
310   if (frame) {
311     frame->callFunctionEvenIfScriptDisabled(
312         callback_and_context->GetCallback(), v8::Object::New(isolate), 0, NULL);
313   }
314 }
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() {
806     GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
807     return !!gpu_channel;
808 }
809
810 }  // namespace content