Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / gpu / gpu_benchmarking_extension.cc
blob45a350a3466474bf75d400c5a6e16642e110ca9c
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"
7 #include <string>
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_drag_gesture_params.h"
18 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
19 #include "content/common/input/synthetic_tap_gesture_params.h"
20 #include "content/public/child/v8_value_converter.h"
21 #include "content/public/renderer/render_thread.h"
22 #include "content/renderer/chrome_object_extensions_utils.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 "gin/arguments.h"
28 #include "gin/handle.h"
29 #include "gin/object_template_builder.h"
30 #include "third_party/WebKit/public/web/WebImageCache.h"
31 #include "third_party/WebKit/public/web/WebKit.h"
32 #include "third_party/WebKit/public/web/WebLocalFrame.h"
33 #include "third_party/WebKit/public/web/WebView.h"
34 #include "third_party/skia/include/core/SkData.h"
35 #include "third_party/skia/include/core/SkGraphics.h"
36 #include "third_party/skia/include/core/SkPicture.h"
37 #include "third_party/skia/include/core/SkPixelRef.h"
38 #include "third_party/skia/include/core/SkPixelSerializer.h"
39 #include "third_party/skia/include/core/SkStream.h"
40 #include "ui/gfx/codec/png_codec.h"
41 #include "v8/include/v8.h"
43 using blink::WebCanvas;
44 using blink::WebLocalFrame;
45 using blink::WebImageCache;
46 using blink::WebPrivatePtr;
47 using blink::WebSize;
48 using blink::WebView;
50 namespace content {
52 namespace {
54 class PNGSerializer : public SkPixelSerializer {
55 protected:
56 bool onUseEncodedData(const void* data, size_t len) override { return true; }
58 SkData* onEncodePixels(const SkImageInfo& info,
59 const void* pixels,
60 size_t row_bytes) override {
61 SkBitmap bm;
62 // The const_cast is fine, since we only read from the bitmap.
63 if (bm.installPixels(info, const_cast<void*>(pixels), row_bytes)) {
64 std::vector<unsigned char> vector;
65 if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
66 return SkData::NewWithCopy(&vector.front(), vector.size());
69 return nullptr;
73 class SkPictureSerializer {
74 public:
75 explicit SkPictureSerializer(const base::FilePath& dirpath)
76 : dirpath_(dirpath),
77 layer_id_(0) {
78 // Let skia register known effect subclasses. This basically enables
79 // reflection on those subclasses required for picture serialization.
80 SkiaBenchmarking::Initialize();
83 // Recursively serializes the layer tree.
84 // Each layer in the tree is serialized into a separate skp file
85 // in the given directory.
86 void Serialize(const cc::Layer* layer) {
87 const cc::LayerList& children = layer->children();
88 for (size_t i = 0; i < children.size(); ++i) {
89 Serialize(children[i].get());
92 skia::RefPtr<SkPicture> picture = layer->GetPicture();
93 if (!picture)
94 return;
96 // Serialize picture to file.
97 // TODO(alokp): Note that for this to work Chrome needs to be launched with
98 // --no-sandbox command-line flag. Get rid of this limitation.
99 // CRBUG: 139640.
100 std::string filename = "layer_" + base::IntToString(layer_id_++) + ".skp";
101 std::string filepath = dirpath_.AppendASCII(filename).MaybeAsASCII();
102 DCHECK(!filepath.empty());
103 SkFILEWStream file(filepath.c_str());
104 DCHECK(file.isValid());
106 PNGSerializer serializer;
107 picture->serialize(&file, &serializer);
110 private:
111 base::FilePath dirpath_;
112 int layer_id_;
115 template <typename T>
116 bool GetArg(gin::Arguments* args, T* value) {
117 if (!args->GetNext(value)) {
118 args->ThrowError();
119 return false;
121 return true;
124 template <>
125 bool GetArg(gin::Arguments* args, int* value) {
126 float number;
127 bool ret = GetArg(args, &number);
128 *value = number;
129 return ret;
132 template <typename T>
133 bool GetOptionalArg(gin::Arguments* args, T* value) {
134 if (args->PeekNext().IsEmpty())
135 return true;
136 if (args->PeekNext()->IsUndefined()) {
137 args->Skip();
138 return true;
140 return GetArg(args, value);
143 class CallbackAndContext : public base::RefCounted<CallbackAndContext> {
144 public:
145 CallbackAndContext(v8::Isolate* isolate,
146 v8::Handle<v8::Function> callback,
147 v8::Handle<v8::Context> context)
148 : isolate_(isolate) {
149 callback_.Reset(isolate_, callback);
150 context_.Reset(isolate_, context);
153 v8::Isolate* isolate() {
154 return isolate_;
157 v8::Handle<v8::Function> GetCallback() {
158 return v8::Local<v8::Function>::New(isolate_, callback_);
161 v8::Handle<v8::Context> GetContext() {
162 return v8::Local<v8::Context>::New(isolate_, context_);
165 private:
166 friend class base::RefCounted<CallbackAndContext>;
168 virtual ~CallbackAndContext() {
169 callback_.Reset();
170 context_.Reset();
173 v8::Isolate* isolate_;
174 v8::Persistent<v8::Function> callback_;
175 v8::Persistent<v8::Context> context_;
176 DISALLOW_COPY_AND_ASSIGN(CallbackAndContext);
179 class GpuBenchmarkingContext {
180 public:
181 GpuBenchmarkingContext()
182 : web_frame_(NULL),
183 web_view_(NULL),
184 render_view_impl_(NULL),
185 compositor_(NULL) {}
187 bool Init(bool init_compositor) {
188 web_frame_ = WebLocalFrame::frameForCurrentContext();
189 if (!web_frame_)
190 return false;
192 web_view_ = web_frame_->view();
193 if (!web_view_) {
194 web_frame_ = NULL;
195 return false;
198 render_view_impl_ = RenderViewImpl::FromWebView(web_view_);
199 if (!render_view_impl_) {
200 web_frame_ = NULL;
201 web_view_ = NULL;
202 return false;
205 if (!init_compositor)
206 return true;
208 compositor_ = render_view_impl_->compositor();
209 if (!compositor_) {
210 web_frame_ = NULL;
211 web_view_ = NULL;
212 render_view_impl_ = NULL;
213 return false;
216 return true;
219 WebLocalFrame* web_frame() const {
220 DCHECK(web_frame_ != NULL);
221 return web_frame_;
223 WebView* web_view() const {
224 DCHECK(web_view_ != NULL);
225 return web_view_;
227 RenderViewImpl* render_view_impl() const {
228 DCHECK(render_view_impl_ != NULL);
229 return render_view_impl_;
231 RenderWidgetCompositor* compositor() const {
232 DCHECK(compositor_ != NULL);
233 return compositor_;
236 private:
237 WebLocalFrame* web_frame_;
238 WebView* web_view_;
239 RenderViewImpl* render_view_impl_;
240 RenderWidgetCompositor* compositor_;
242 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext);
245 void OnMicroBenchmarkCompleted(
246 CallbackAndContext* callback_and_context,
247 scoped_ptr<base::Value> result) {
248 v8::Isolate* isolate = callback_and_context->isolate();
249 v8::HandleScope scope(isolate);
250 v8::Handle<v8::Context> context = callback_and_context->GetContext();
251 v8::Context::Scope context_scope(context);
252 WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
253 if (frame) {
254 scoped_ptr<V8ValueConverter> converter =
255 make_scoped_ptr(V8ValueConverter::create());
256 v8::Handle<v8::Value> value = converter->ToV8Value(result.get(), context);
257 v8::Handle<v8::Value> argv[] = { value };
259 frame->callFunctionEvenIfScriptDisabled(
260 callback_and_context->GetCallback(),
261 v8::Object::New(isolate),
263 argv);
267 void OnSyntheticGestureCompleted(CallbackAndContext* callback_and_context) {
268 v8::Isolate* isolate = callback_and_context->isolate();
269 v8::HandleScope scope(isolate);
270 v8::Handle<v8::Context> context = callback_and_context->GetContext();
271 v8::Context::Scope context_scope(context);
272 WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
273 if (frame) {
274 frame->callFunctionEvenIfScriptDisabled(
275 callback_and_context->GetCallback(), v8::Object::New(isolate), 0, NULL);
279 bool BeginSmoothScroll(v8::Isolate* isolate,
280 float pixels_to_scroll,
281 v8::Handle<v8::Function> callback,
282 int gesture_source_type,
283 const std::string& direction,
284 float speed_in_pixels_s,
285 bool prevent_fling,
286 float start_x,
287 float start_y) {
288 GpuBenchmarkingContext context;
289 if (!context.Init(false))
290 return false;
292 scoped_refptr<CallbackAndContext> callback_and_context =
293 new CallbackAndContext(
294 isolate, callback, context.web_frame()->mainWorldScriptContext());
296 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params(
297 new SyntheticSmoothScrollGestureParams);
299 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
300 float page_scale_factor = context.web_view()->pageScaleFactor();
302 if (gesture_source_type < 0 ||
303 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
304 return false;
306 gesture_params->gesture_source_type =
307 static_cast<SyntheticGestureParams::GestureSourceType>(
308 gesture_source_type);
310 gesture_params->speed_in_pixels_s = speed_in_pixels_s;
311 gesture_params->prevent_fling = prevent_fling;
313 gesture_params->anchor.SetPoint(start_x * page_scale_factor,
314 start_y * page_scale_factor);
316 float distance_length = pixels_to_scroll * page_scale_factor;
317 gfx::Vector2dF distance;
318 if (direction == "down")
319 distance.set_y(-distance_length);
320 else if (direction == "up")
321 distance.set_y(distance_length);
322 else if (direction == "right")
323 distance.set_x(-distance_length);
324 else if (direction == "left")
325 distance.set_x(distance_length);
326 else if (direction == "upleft") {
327 distance.set_y(distance_length);
328 distance.set_x(distance_length);
329 } else if (direction == "upright") {
330 distance.set_y(distance_length);
331 distance.set_x(-distance_length);
332 } else if (direction == "downleft") {
333 distance.set_y(-distance_length);
334 distance.set_x(distance_length);
335 } else if (direction == "downright") {
336 distance.set_y(-distance_length);
337 distance.set_x(-distance_length);
338 } else {
339 return false;
341 gesture_params->distances.push_back(distance);
343 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
344 // progress, we will leak the callback and context. This needs to be fixed,
345 // somehow.
346 context.render_view_impl()->QueueSyntheticGesture(
347 gesture_params.Pass(),
348 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
350 return true;
353 bool BeginSmoothDrag(v8::Isolate* isolate,
354 float start_x,
355 float start_y,
356 float end_x,
357 float end_y,
358 v8::Handle<v8::Function> callback,
359 int gesture_source_type,
360 float speed_in_pixels_s) {
361 GpuBenchmarkingContext context;
362 if (!context.Init(false))
363 return false;
364 scoped_refptr<CallbackAndContext> callback_and_context =
365 new CallbackAndContext(isolate, callback,
366 context.web_frame()->mainWorldScriptContext());
368 scoped_ptr<SyntheticSmoothDragGestureParams> gesture_params(
369 new SyntheticSmoothDragGestureParams);
371 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
372 float page_scale_factor = context.web_view()->pageScaleFactor();
374 gesture_params->start_point.SetPoint(start_x * page_scale_factor,
375 start_y * page_scale_factor);
376 gfx::PointF end_point(end_x * page_scale_factor,
377 end_y * page_scale_factor);
378 gfx::Vector2dF distance = end_point - gesture_params->start_point;
379 gesture_params->distances.push_back(distance);
380 gesture_params->speed_in_pixels_s = speed_in_pixels_s * page_scale_factor;
381 gesture_params->gesture_source_type =
382 static_cast<SyntheticGestureParams::GestureSourceType>(
383 gesture_source_type);
385 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
386 // progress, we will leak the callback and context. This needs to be fixed,
387 // somehow.
388 context.render_view_impl()->QueueSyntheticGesture(
389 gesture_params.Pass(),
390 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
392 return true;
395 } // namespace
397 gin::WrapperInfo GpuBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
399 // static
400 void GpuBenchmarking::Install(blink::WebFrame* frame) {
401 v8::Isolate* isolate = blink::mainThreadIsolate();
402 v8::HandleScope handle_scope(isolate);
403 v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
404 if (context.IsEmpty())
405 return;
407 v8::Context::Scope context_scope(context);
409 gin::Handle<GpuBenchmarking> controller =
410 gin::CreateHandle(isolate, new GpuBenchmarking());
411 if (controller.IsEmpty())
412 return;
414 v8::Handle<v8::Object> chrome = GetOrCreateChromeObject(isolate,
415 context->Global());
416 chrome->Set(gin::StringToV8(isolate, "gpuBenchmarking"), controller.ToV8());
419 GpuBenchmarking::GpuBenchmarking() {
422 GpuBenchmarking::~GpuBenchmarking() {
425 gin::ObjectTemplateBuilder GpuBenchmarking::GetObjectTemplateBuilder(
426 v8::Isolate* isolate) {
427 return gin::Wrappable<GpuBenchmarking>::GetObjectTemplateBuilder(isolate)
428 .SetMethod("setNeedsDisplayOnAllLayers",
429 &GpuBenchmarking::SetNeedsDisplayOnAllLayers)
430 .SetMethod("setRasterizeOnlyVisibleContent",
431 &GpuBenchmarking::SetRasterizeOnlyVisibleContent)
432 .SetMethod("printToSkPicture", &GpuBenchmarking::PrintToSkPicture)
433 .SetValue("DEFAULT_INPUT", 0)
434 .SetValue("TOUCH_INPUT", 1)
435 .SetValue("MOUSE_INPUT", 2)
436 .SetMethod("gestureSourceTypeSupported",
437 &GpuBenchmarking::GestureSourceTypeSupported)
438 .SetMethod("smoothScrollBy", &GpuBenchmarking::SmoothScrollBy)
439 .SetMethod("smoothDrag", &GpuBenchmarking::SmoothDrag)
440 .SetMethod("swipe", &GpuBenchmarking::Swipe)
441 .SetMethod("scrollBounce", &GpuBenchmarking::ScrollBounce)
442 // TODO(dominikg): Remove once JS interface changes have rolled into
443 // stable.
444 .SetValue("newPinchInterface", true)
445 .SetMethod("pinchBy", &GpuBenchmarking::PinchBy)
446 .SetMethod("tap", &GpuBenchmarking::Tap)
447 .SetMethod("clearImageCache", &GpuBenchmarking::ClearImageCache)
448 .SetMethod("runMicroBenchmark", &GpuBenchmarking::RunMicroBenchmark)
449 .SetMethod("sendMessageToMicroBenchmark",
450 &GpuBenchmarking::SendMessageToMicroBenchmark)
451 .SetMethod("hasGpuProcess", &GpuBenchmarking::HasGpuProcess);
454 void GpuBenchmarking::SetNeedsDisplayOnAllLayers() {
455 GpuBenchmarkingContext context;
456 if (!context.Init(true))
457 return;
459 context.compositor()->SetNeedsDisplayOnAllLayers();
462 void GpuBenchmarking::SetRasterizeOnlyVisibleContent() {
463 GpuBenchmarkingContext context;
464 if (!context.Init(true))
465 return;
467 context.compositor()->SetRasterizeOnlyVisibleContent();
470 void GpuBenchmarking::PrintToSkPicture(v8::Isolate* isolate,
471 const std::string& dirname) {
472 GpuBenchmarkingContext context;
473 if (!context.Init(true))
474 return;
476 const cc::Layer* root_layer = context.compositor()->GetRootLayer();
477 if (!root_layer)
478 return;
480 base::FilePath dirpath = base::FilePath::FromUTF8Unsafe(dirname);
481 if (!base::CreateDirectory(dirpath) ||
482 !base::PathIsWritable(dirpath)) {
483 std::string msg("Path is not writable: ");
484 msg.append(dirpath.MaybeAsASCII());
485 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
486 isolate, msg.c_str(), v8::String::kNormalString, msg.length())));
487 return;
490 SkPictureSerializer serializer(dirpath);
491 serializer.Serialize(root_layer);
494 bool GpuBenchmarking::GestureSourceTypeSupported(int gesture_source_type) {
495 if (gesture_source_type < 0 ||
496 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
497 return false;
500 return SyntheticGestureParams::IsGestureSourceTypeSupported(
501 static_cast<SyntheticGestureParams::GestureSourceType>(
502 gesture_source_type));
505 bool GpuBenchmarking::SmoothScrollBy(gin::Arguments* args) {
506 GpuBenchmarkingContext context;
507 if (!context.Init(true))
508 return false;
510 float page_scale_factor = context.web_view()->pageScaleFactor();
511 blink::WebRect rect = context.render_view_impl()->windowRect();
513 float pixels_to_scroll = 0;
514 v8::Handle<v8::Function> callback;
515 float start_x = rect.width / (page_scale_factor * 2);
516 float start_y = rect.height / (page_scale_factor * 2);
517 int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
518 std::string direction = "down";
519 float speed_in_pixels_s = 800;
521 if (!GetOptionalArg(args, &pixels_to_scroll) ||
522 !GetOptionalArg(args, &callback) ||
523 !GetOptionalArg(args, &start_x) ||
524 !GetOptionalArg(args, &start_y) ||
525 !GetOptionalArg(args, &gesture_source_type) ||
526 !GetOptionalArg(args, &direction) ||
527 !GetOptionalArg(args, &speed_in_pixels_s)) {
528 return false;
531 return BeginSmoothScroll(args->isolate(),
532 pixels_to_scroll,
533 callback,
534 gesture_source_type,
535 direction,
536 speed_in_pixels_s,
537 true,
538 start_x,
539 start_y);
542 bool GpuBenchmarking::SmoothDrag(gin::Arguments* args) {
543 GpuBenchmarkingContext context;
544 if (!context.Init(true))
545 return false;
547 float start_x;
548 float start_y;
549 float end_x;
550 float end_y;
551 v8::Handle<v8::Function> callback;
552 int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
553 float speed_in_pixels_s = 800;
555 if (!GetArg(args, &start_x) ||
556 !GetArg(args, &start_y) ||
557 !GetArg(args, &end_x) ||
558 !GetArg(args, &end_y) ||
559 !GetOptionalArg(args, &callback) ||
560 !GetOptionalArg(args, &gesture_source_type) ||
561 !GetOptionalArg(args, &speed_in_pixels_s)) {
562 return false;
565 return BeginSmoothDrag(args->isolate(),
566 start_x,
567 start_y,
568 end_x,
569 end_y,
570 callback,
571 gesture_source_type,
572 speed_in_pixels_s);
575 bool GpuBenchmarking::Swipe(gin::Arguments* args) {
576 GpuBenchmarkingContext context;
577 if (!context.Init(true))
578 return false;
580 float page_scale_factor = context.web_view()->pageScaleFactor();
581 blink::WebRect rect = context.render_view_impl()->windowRect();
583 std::string direction = "up";
584 float pixels_to_scroll = 0;
585 v8::Handle<v8::Function> callback;
586 float start_x = rect.width / (page_scale_factor * 2);
587 float start_y = rect.height / (page_scale_factor * 2);
588 float speed_in_pixels_s = 800;
590 if (!GetOptionalArg(args, &direction) ||
591 !GetOptionalArg(args, &pixels_to_scroll) ||
592 !GetOptionalArg(args, &callback) ||
593 !GetOptionalArg(args, &start_x) ||
594 !GetOptionalArg(args, &start_y) ||
595 !GetOptionalArg(args, &speed_in_pixels_s)) {
596 return false;
599 return BeginSmoothScroll(args->isolate(),
600 -pixels_to_scroll,
601 callback,
602 1, // TOUCH_INPUT
603 direction,
604 speed_in_pixels_s,
605 false,
606 start_x,
607 start_y);
610 bool GpuBenchmarking::ScrollBounce(gin::Arguments* args) {
611 GpuBenchmarkingContext context;
612 if (!context.Init(false))
613 return false;
615 float page_scale_factor = context.web_view()->pageScaleFactor();
616 blink::WebRect rect = context.render_view_impl()->windowRect();
618 std::string direction = "down";
619 float distance_length = 0;
620 float overscroll_length = 0;
621 int repeat_count = 1;
622 v8::Handle<v8::Function> callback;
623 float start_x = rect.width / (page_scale_factor * 2);
624 float start_y = rect.height / (page_scale_factor * 2);
625 float speed_in_pixels_s = 800;
627 if (!GetOptionalArg(args, &direction) ||
628 !GetOptionalArg(args, &distance_length) ||
629 !GetOptionalArg(args, &overscroll_length) ||
630 !GetOptionalArg(args, &repeat_count) ||
631 !GetOptionalArg(args, &callback) ||
632 !GetOptionalArg(args, &start_x) ||
633 !GetOptionalArg(args, &start_y) ||
634 !GetOptionalArg(args, &speed_in_pixels_s)) {
635 return false;
638 scoped_refptr<CallbackAndContext> callback_and_context =
639 new CallbackAndContext(args->isolate(),
640 callback,
641 context.web_frame()->mainWorldScriptContext());
643 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params(
644 new SyntheticSmoothScrollGestureParams);
646 gesture_params->speed_in_pixels_s = speed_in_pixels_s;
648 gesture_params->anchor.SetPoint(start_x * page_scale_factor,
649 start_y * page_scale_factor);
651 distance_length *= page_scale_factor;
652 overscroll_length *= page_scale_factor;
653 gfx::Vector2dF distance;
654 gfx::Vector2dF overscroll;
655 if (direction == "down") {
656 distance.set_y(-distance_length);
657 overscroll.set_y(overscroll_length);
658 } else if (direction == "up") {
659 distance.set_y(distance_length);
660 overscroll.set_y(-overscroll_length);
661 } else if (direction == "right") {
662 distance.set_x(-distance_length);
663 overscroll.set_x(overscroll_length);
664 } else if (direction == "left") {
665 distance.set_x(distance_length);
666 overscroll.set_x(-overscroll_length);
667 } else {
668 return false;
671 for (int i = 0; i < repeat_count; i++) {
672 gesture_params->distances.push_back(distance);
673 gesture_params->distances.push_back(-distance + overscroll);
676 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
677 // progress, we will leak the callback and context. This needs to be fixed,
678 // somehow.
679 context.render_view_impl()->QueueSyntheticGesture(
680 gesture_params.Pass(),
681 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
683 return true;
686 bool GpuBenchmarking::PinchBy(gin::Arguments* args) {
687 GpuBenchmarkingContext context;
688 if (!context.Init(false))
689 return false;
691 float scale_factor;
692 float anchor_x;
693 float anchor_y;
694 v8::Handle<v8::Function> callback;
695 float relative_pointer_speed_in_pixels_s = 800;
698 if (!GetArg(args, &scale_factor) ||
699 !GetArg(args, &anchor_x) ||
700 !GetArg(args, &anchor_y) ||
701 !GetOptionalArg(args, &callback) ||
702 !GetOptionalArg(args, &relative_pointer_speed_in_pixels_s)) {
703 return false;
706 scoped_ptr<SyntheticPinchGestureParams> gesture_params(
707 new SyntheticPinchGestureParams);
709 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
710 float page_scale_factor = context.web_view()->pageScaleFactor();
712 gesture_params->scale_factor = scale_factor;
713 gesture_params->anchor.SetPoint(anchor_x * page_scale_factor,
714 anchor_y * page_scale_factor);
715 gesture_params->relative_pointer_speed_in_pixels_s =
716 relative_pointer_speed_in_pixels_s;
718 scoped_refptr<CallbackAndContext> callback_and_context =
719 new CallbackAndContext(args->isolate(),
720 callback,
721 context.web_frame()->mainWorldScriptContext());
724 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
725 // progress, we will leak the callback and context. This needs to be fixed,
726 // somehow.
727 context.render_view_impl()->QueueSyntheticGesture(
728 gesture_params.Pass(),
729 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
731 return true;
734 bool GpuBenchmarking::Tap(gin::Arguments* args) {
735 GpuBenchmarkingContext context;
736 if (!context.Init(false))
737 return false;
739 float position_x;
740 float position_y;
741 v8::Handle<v8::Function> callback;
742 int duration_ms = 50;
743 int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
745 if (!GetArg(args, &position_x) ||
746 !GetArg(args, &position_y) ||
747 !GetOptionalArg(args, &callback) ||
748 !GetOptionalArg(args, &duration_ms) ||
749 !GetOptionalArg(args, &gesture_source_type)) {
750 return false;
753 scoped_ptr<SyntheticTapGestureParams> gesture_params(
754 new SyntheticTapGestureParams);
756 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
757 float page_scale_factor = context.web_view()->pageScaleFactor();
759 gesture_params->position.SetPoint(position_x * page_scale_factor,
760 position_y * page_scale_factor);
761 gesture_params->duration_ms = duration_ms;
763 if (gesture_source_type < 0 ||
764 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
765 return false;
767 gesture_params->gesture_source_type =
768 static_cast<SyntheticGestureParams::GestureSourceType>(
769 gesture_source_type);
771 scoped_refptr<CallbackAndContext> callback_and_context =
772 new CallbackAndContext(args->isolate(),
773 callback,
774 context.web_frame()->mainWorldScriptContext());
776 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
777 // progress, we will leak the callback and context. This needs to be fixed,
778 // somehow.
779 context.render_view_impl()->QueueSyntheticGesture(
780 gesture_params.Pass(),
781 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
783 return true;
786 void GpuBenchmarking::ClearImageCache() {
787 WebImageCache::clear();
790 int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) {
791 GpuBenchmarkingContext context;
792 if (!context.Init(true))
793 return 0;
795 std::string name;
796 v8::Handle<v8::Function> callback;
797 v8::Handle<v8::Object> arguments;
799 if (!GetArg(args, &name) || !GetArg(args, &callback) ||
800 !GetOptionalArg(args, &arguments)) {
801 return 0;
804 scoped_refptr<CallbackAndContext> callback_and_context =
805 new CallbackAndContext(args->isolate(),
806 callback,
807 context.web_frame()->mainWorldScriptContext());
809 scoped_ptr<V8ValueConverter> converter =
810 make_scoped_ptr(V8ValueConverter::create());
811 v8::Handle<v8::Context> v8_context = callback_and_context->GetContext();
812 scoped_ptr<base::Value> value =
813 make_scoped_ptr(converter->FromV8Value(arguments, v8_context));
815 return context.compositor()->ScheduleMicroBenchmark(
816 name,
817 value.Pass(),
818 base::Bind(&OnMicroBenchmarkCompleted, callback_and_context));
821 bool GpuBenchmarking::SendMessageToMicroBenchmark(
822 int id,
823 v8::Handle<v8::Object> message) {
824 GpuBenchmarkingContext context;
825 if (!context.Init(true))
826 return false;
828 scoped_ptr<V8ValueConverter> converter =
829 make_scoped_ptr(V8ValueConverter::create());
830 v8::Handle<v8::Context> v8_context =
831 context.web_frame()->mainWorldScriptContext();
832 scoped_ptr<base::Value> value =
833 make_scoped_ptr(converter->FromV8Value(message, v8_context));
835 return context.compositor()->SendMessageToMicroBenchmark(id, value.Pass());
838 bool GpuBenchmarking::HasGpuProcess() {
839 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
840 return !!gpu_channel;
843 } // namespace content