Process Alt-Svc headers.
[chromium-blink-merge.git] / content / renderer / gpu / gpu_benchmarking_extension.cc
blob99f7e94e0b8421c79140dbbbd470ef8e16dfc684
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::Local<v8::Function> callback,
147 v8::Local<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::Local<v8::Function> GetCallback() {
158 return v8::Local<v8::Function>::New(isolate_, callback_);
161 v8::Local<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::Local<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::Local<v8::Value> value = converter->ToV8Value(result.get(), context);
257 v8::Local<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::Local<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::Local<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 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
293 float page_scale_factor = context.web_view()->pageScaleFactor();
295 if (gesture_source_type == SyntheticGestureParams::MOUSE_INPUT) {
296 // Ensure the mouse is centered and visible, in case it will
297 // trigger any hover or mousemove effects.
298 context.web_view()->setIsActive(true);
299 blink::WebRect contentRect =
300 context.web_view()->mainFrame()->visibleContentRect();
301 blink::WebMouseEvent mouseMove;
302 mouseMove.type = blink::WebInputEvent::MouseMove;
303 mouseMove.x = (contentRect.x + contentRect.width / 2) * page_scale_factor;
304 mouseMove.y = (contentRect.y + contentRect.height / 2) * page_scale_factor;
305 context.web_view()->handleInputEvent(mouseMove);
306 context.web_view()->setCursorVisibilityState(true);
309 scoped_refptr<CallbackAndContext> callback_and_context =
310 new CallbackAndContext(
311 isolate, callback, context.web_frame()->mainWorldScriptContext());
313 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params(
314 new SyntheticSmoothScrollGestureParams);
316 if (gesture_source_type < 0 ||
317 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
318 return false;
320 gesture_params->gesture_source_type =
321 static_cast<SyntheticGestureParams::GestureSourceType>(
322 gesture_source_type);
324 gesture_params->speed_in_pixels_s = speed_in_pixels_s;
325 gesture_params->prevent_fling = prevent_fling;
327 gesture_params->anchor.SetPoint(start_x * page_scale_factor,
328 start_y * page_scale_factor);
330 float distance_length = pixels_to_scroll * page_scale_factor;
331 gfx::Vector2dF distance;
332 if (direction == "down")
333 distance.set_y(-distance_length);
334 else if (direction == "up")
335 distance.set_y(distance_length);
336 else if (direction == "right")
337 distance.set_x(-distance_length);
338 else if (direction == "left")
339 distance.set_x(distance_length);
340 else if (direction == "upleft") {
341 distance.set_y(distance_length);
342 distance.set_x(distance_length);
343 } else if (direction == "upright") {
344 distance.set_y(distance_length);
345 distance.set_x(-distance_length);
346 } else if (direction == "downleft") {
347 distance.set_y(-distance_length);
348 distance.set_x(distance_length);
349 } else if (direction == "downright") {
350 distance.set_y(-distance_length);
351 distance.set_x(-distance_length);
352 } else {
353 return false;
355 gesture_params->distances.push_back(distance);
357 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
358 // progress, we will leak the callback and context. This needs to be fixed,
359 // somehow.
360 context.render_view_impl()->QueueSyntheticGesture(
361 gesture_params.Pass(),
362 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
364 return true;
367 bool BeginSmoothDrag(v8::Isolate* isolate,
368 float start_x,
369 float start_y,
370 float end_x,
371 float end_y,
372 v8::Local<v8::Function> callback,
373 int gesture_source_type,
374 float speed_in_pixels_s) {
375 GpuBenchmarkingContext context;
376 if (!context.Init(false))
377 return false;
378 scoped_refptr<CallbackAndContext> callback_and_context =
379 new CallbackAndContext(isolate, callback,
380 context.web_frame()->mainWorldScriptContext());
382 scoped_ptr<SyntheticSmoothDragGestureParams> gesture_params(
383 new SyntheticSmoothDragGestureParams);
385 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
386 float page_scale_factor = context.web_view()->pageScaleFactor();
388 gesture_params->start_point.SetPoint(start_x * page_scale_factor,
389 start_y * page_scale_factor);
390 gfx::PointF end_point(end_x * page_scale_factor,
391 end_y * page_scale_factor);
392 gfx::Vector2dF distance = end_point - gesture_params->start_point;
393 gesture_params->distances.push_back(distance);
394 gesture_params->speed_in_pixels_s = speed_in_pixels_s * page_scale_factor;
395 gesture_params->gesture_source_type =
396 static_cast<SyntheticGestureParams::GestureSourceType>(
397 gesture_source_type);
399 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
400 // progress, we will leak the callback and context. This needs to be fixed,
401 // somehow.
402 context.render_view_impl()->QueueSyntheticGesture(
403 gesture_params.Pass(),
404 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
406 return true;
409 } // namespace
411 gin::WrapperInfo GpuBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
413 // static
414 void GpuBenchmarking::Install(blink::WebFrame* frame) {
415 v8::Isolate* isolate = blink::mainThreadIsolate();
416 v8::HandleScope handle_scope(isolate);
417 v8::Local<v8::Context> context = frame->mainWorldScriptContext();
418 if (context.IsEmpty())
419 return;
421 v8::Context::Scope context_scope(context);
423 gin::Handle<GpuBenchmarking> controller =
424 gin::CreateHandle(isolate, new GpuBenchmarking());
425 if (controller.IsEmpty())
426 return;
428 v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate,
429 context->Global());
430 chrome->Set(gin::StringToV8(isolate, "gpuBenchmarking"), controller.ToV8());
433 GpuBenchmarking::GpuBenchmarking() {
436 GpuBenchmarking::~GpuBenchmarking() {
439 gin::ObjectTemplateBuilder GpuBenchmarking::GetObjectTemplateBuilder(
440 v8::Isolate* isolate) {
441 return gin::Wrappable<GpuBenchmarking>::GetObjectTemplateBuilder(isolate)
442 .SetMethod("setNeedsDisplayOnAllLayers",
443 &GpuBenchmarking::SetNeedsDisplayOnAllLayers)
444 .SetMethod("setRasterizeOnlyVisibleContent",
445 &GpuBenchmarking::SetRasterizeOnlyVisibleContent)
446 .SetMethod("printToSkPicture", &GpuBenchmarking::PrintToSkPicture)
447 .SetValue("DEFAULT_INPUT", 0)
448 .SetValue("TOUCH_INPUT", 1)
449 .SetValue("MOUSE_INPUT", 2)
450 .SetMethod("gestureSourceTypeSupported",
451 &GpuBenchmarking::GestureSourceTypeSupported)
452 .SetMethod("smoothScrollBy", &GpuBenchmarking::SmoothScrollBy)
453 .SetMethod("smoothDrag", &GpuBenchmarking::SmoothDrag)
454 .SetMethod("swipe", &GpuBenchmarking::Swipe)
455 .SetMethod("scrollBounce", &GpuBenchmarking::ScrollBounce)
456 // TODO(dominikg): Remove once JS interface changes have rolled into
457 // stable.
458 .SetValue("newPinchInterface", true)
459 .SetMethod("pinchBy", &GpuBenchmarking::PinchBy)
460 .SetMethod("tap", &GpuBenchmarking::Tap)
461 .SetMethod("clearImageCache", &GpuBenchmarking::ClearImageCache)
462 .SetMethod("runMicroBenchmark", &GpuBenchmarking::RunMicroBenchmark)
463 .SetMethod("sendMessageToMicroBenchmark",
464 &GpuBenchmarking::SendMessageToMicroBenchmark)
465 .SetMethod("hasGpuProcess", &GpuBenchmarking::HasGpuProcess);
468 void GpuBenchmarking::SetNeedsDisplayOnAllLayers() {
469 GpuBenchmarkingContext context;
470 if (!context.Init(true))
471 return;
473 context.compositor()->SetNeedsDisplayOnAllLayers();
476 void GpuBenchmarking::SetRasterizeOnlyVisibleContent() {
477 GpuBenchmarkingContext context;
478 if (!context.Init(true))
479 return;
481 context.compositor()->SetRasterizeOnlyVisibleContent();
484 void GpuBenchmarking::PrintToSkPicture(v8::Isolate* isolate,
485 const std::string& dirname) {
486 GpuBenchmarkingContext context;
487 if (!context.Init(true))
488 return;
490 const cc::Layer* root_layer = context.compositor()->GetRootLayer();
491 if (!root_layer)
492 return;
494 base::FilePath dirpath = base::FilePath::FromUTF8Unsafe(dirname);
495 if (!base::CreateDirectory(dirpath) ||
496 !base::PathIsWritable(dirpath)) {
497 std::string msg("Path is not writable: ");
498 msg.append(dirpath.MaybeAsASCII());
499 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
500 isolate, msg.c_str(), v8::String::kNormalString, msg.length())));
501 return;
504 SkPictureSerializer serializer(dirpath);
505 serializer.Serialize(root_layer);
508 bool GpuBenchmarking::GestureSourceTypeSupported(int gesture_source_type) {
509 if (gesture_source_type < 0 ||
510 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
511 return false;
514 return SyntheticGestureParams::IsGestureSourceTypeSupported(
515 static_cast<SyntheticGestureParams::GestureSourceType>(
516 gesture_source_type));
519 bool GpuBenchmarking::SmoothScrollBy(gin::Arguments* args) {
520 GpuBenchmarkingContext context;
521 if (!context.Init(true))
522 return false;
524 float page_scale_factor = context.web_view()->pageScaleFactor();
525 blink::WebRect rect = context.render_view_impl()->windowRect();
527 float pixels_to_scroll = 0;
528 v8::Local<v8::Function> callback;
529 float start_x = rect.width / (page_scale_factor * 2);
530 float start_y = rect.height / (page_scale_factor * 2);
531 int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
532 std::string direction = "down";
533 float speed_in_pixels_s = 800;
535 if (!GetOptionalArg(args, &pixels_to_scroll) ||
536 !GetOptionalArg(args, &callback) ||
537 !GetOptionalArg(args, &start_x) ||
538 !GetOptionalArg(args, &start_y) ||
539 !GetOptionalArg(args, &gesture_source_type) ||
540 !GetOptionalArg(args, &direction) ||
541 !GetOptionalArg(args, &speed_in_pixels_s)) {
542 return false;
545 return BeginSmoothScroll(args->isolate(),
546 pixels_to_scroll,
547 callback,
548 gesture_source_type,
549 direction,
550 speed_in_pixels_s,
551 true,
552 start_x,
553 start_y);
556 bool GpuBenchmarking::SmoothDrag(gin::Arguments* args) {
557 GpuBenchmarkingContext context;
558 if (!context.Init(true))
559 return false;
561 float start_x;
562 float start_y;
563 float end_x;
564 float end_y;
565 v8::Local<v8::Function> callback;
566 int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
567 float speed_in_pixels_s = 800;
569 if (!GetArg(args, &start_x) ||
570 !GetArg(args, &start_y) ||
571 !GetArg(args, &end_x) ||
572 !GetArg(args, &end_y) ||
573 !GetOptionalArg(args, &callback) ||
574 !GetOptionalArg(args, &gesture_source_type) ||
575 !GetOptionalArg(args, &speed_in_pixels_s)) {
576 return false;
579 return BeginSmoothDrag(args->isolate(),
580 start_x,
581 start_y,
582 end_x,
583 end_y,
584 callback,
585 gesture_source_type,
586 speed_in_pixels_s);
589 bool GpuBenchmarking::Swipe(gin::Arguments* args) {
590 GpuBenchmarkingContext context;
591 if (!context.Init(true))
592 return false;
594 float page_scale_factor = context.web_view()->pageScaleFactor();
595 blink::WebRect rect = context.render_view_impl()->windowRect();
597 std::string direction = "up";
598 float pixels_to_scroll = 0;
599 v8::Local<v8::Function> callback;
600 float start_x = rect.width / (page_scale_factor * 2);
601 float start_y = rect.height / (page_scale_factor * 2);
602 float speed_in_pixels_s = 800;
604 if (!GetOptionalArg(args, &direction) ||
605 !GetOptionalArg(args, &pixels_to_scroll) ||
606 !GetOptionalArg(args, &callback) ||
607 !GetOptionalArg(args, &start_x) ||
608 !GetOptionalArg(args, &start_y) ||
609 !GetOptionalArg(args, &speed_in_pixels_s)) {
610 return false;
613 return BeginSmoothScroll(args->isolate(),
614 -pixels_to_scroll,
615 callback,
616 1, // TOUCH_INPUT
617 direction,
618 speed_in_pixels_s,
619 false,
620 start_x,
621 start_y);
624 bool GpuBenchmarking::ScrollBounce(gin::Arguments* args) {
625 GpuBenchmarkingContext context;
626 if (!context.Init(false))
627 return false;
629 float page_scale_factor = context.web_view()->pageScaleFactor();
630 blink::WebRect rect = context.render_view_impl()->windowRect();
632 std::string direction = "down";
633 float distance_length = 0;
634 float overscroll_length = 0;
635 int repeat_count = 1;
636 v8::Local<v8::Function> callback;
637 float start_x = rect.width / (page_scale_factor * 2);
638 float start_y = rect.height / (page_scale_factor * 2);
639 float speed_in_pixels_s = 800;
641 if (!GetOptionalArg(args, &direction) ||
642 !GetOptionalArg(args, &distance_length) ||
643 !GetOptionalArg(args, &overscroll_length) ||
644 !GetOptionalArg(args, &repeat_count) ||
645 !GetOptionalArg(args, &callback) ||
646 !GetOptionalArg(args, &start_x) ||
647 !GetOptionalArg(args, &start_y) ||
648 !GetOptionalArg(args, &speed_in_pixels_s)) {
649 return false;
652 scoped_refptr<CallbackAndContext> callback_and_context =
653 new CallbackAndContext(args->isolate(),
654 callback,
655 context.web_frame()->mainWorldScriptContext());
657 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params(
658 new SyntheticSmoothScrollGestureParams);
660 gesture_params->speed_in_pixels_s = speed_in_pixels_s;
662 gesture_params->anchor.SetPoint(start_x * page_scale_factor,
663 start_y * page_scale_factor);
665 distance_length *= page_scale_factor;
666 overscroll_length *= page_scale_factor;
667 gfx::Vector2dF distance;
668 gfx::Vector2dF overscroll;
669 if (direction == "down") {
670 distance.set_y(-distance_length);
671 overscroll.set_y(overscroll_length);
672 } else if (direction == "up") {
673 distance.set_y(distance_length);
674 overscroll.set_y(-overscroll_length);
675 } else if (direction == "right") {
676 distance.set_x(-distance_length);
677 overscroll.set_x(overscroll_length);
678 } else if (direction == "left") {
679 distance.set_x(distance_length);
680 overscroll.set_x(-overscroll_length);
681 } else {
682 return false;
685 for (int i = 0; i < repeat_count; i++) {
686 gesture_params->distances.push_back(distance);
687 gesture_params->distances.push_back(-distance + overscroll);
690 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
691 // progress, we will leak the callback and context. This needs to be fixed,
692 // somehow.
693 context.render_view_impl()->QueueSyntheticGesture(
694 gesture_params.Pass(),
695 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
697 return true;
700 bool GpuBenchmarking::PinchBy(gin::Arguments* args) {
701 GpuBenchmarkingContext context;
702 if (!context.Init(false))
703 return false;
705 float scale_factor;
706 float anchor_x;
707 float anchor_y;
708 v8::Local<v8::Function> callback;
709 float relative_pointer_speed_in_pixels_s = 800;
712 if (!GetArg(args, &scale_factor) ||
713 !GetArg(args, &anchor_x) ||
714 !GetArg(args, &anchor_y) ||
715 !GetOptionalArg(args, &callback) ||
716 !GetOptionalArg(args, &relative_pointer_speed_in_pixels_s)) {
717 return false;
720 scoped_ptr<SyntheticPinchGestureParams> gesture_params(
721 new SyntheticPinchGestureParams);
723 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
724 float page_scale_factor = context.web_view()->pageScaleFactor();
726 gesture_params->scale_factor = scale_factor;
727 gesture_params->anchor.SetPoint(anchor_x * page_scale_factor,
728 anchor_y * page_scale_factor);
729 gesture_params->relative_pointer_speed_in_pixels_s =
730 relative_pointer_speed_in_pixels_s;
732 scoped_refptr<CallbackAndContext> callback_and_context =
733 new CallbackAndContext(args->isolate(),
734 callback,
735 context.web_frame()->mainWorldScriptContext());
738 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
739 // progress, we will leak the callback and context. This needs to be fixed,
740 // somehow.
741 context.render_view_impl()->QueueSyntheticGesture(
742 gesture_params.Pass(),
743 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
745 return true;
748 bool GpuBenchmarking::Tap(gin::Arguments* args) {
749 GpuBenchmarkingContext context;
750 if (!context.Init(false))
751 return false;
753 float position_x;
754 float position_y;
755 v8::Local<v8::Function> callback;
756 int duration_ms = 50;
757 int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
759 if (!GetArg(args, &position_x) ||
760 !GetArg(args, &position_y) ||
761 !GetOptionalArg(args, &callback) ||
762 !GetOptionalArg(args, &duration_ms) ||
763 !GetOptionalArg(args, &gesture_source_type)) {
764 return false;
767 scoped_ptr<SyntheticTapGestureParams> gesture_params(
768 new SyntheticTapGestureParams);
770 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
771 float page_scale_factor = context.web_view()->pageScaleFactor();
773 gesture_params->position.SetPoint(position_x * page_scale_factor,
774 position_y * page_scale_factor);
775 gesture_params->duration_ms = duration_ms;
777 if (gesture_source_type < 0 ||
778 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
779 return false;
781 gesture_params->gesture_source_type =
782 static_cast<SyntheticGestureParams::GestureSourceType>(
783 gesture_source_type);
785 scoped_refptr<CallbackAndContext> callback_and_context =
786 new CallbackAndContext(args->isolate(),
787 callback,
788 context.web_frame()->mainWorldScriptContext());
790 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
791 // progress, we will leak the callback and context. This needs to be fixed,
792 // somehow.
793 context.render_view_impl()->QueueSyntheticGesture(
794 gesture_params.Pass(),
795 base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
797 return true;
800 void GpuBenchmarking::ClearImageCache() {
801 WebImageCache::clear();
804 int GpuBenchmarking::RunMicroBenchmark(gin::Arguments* args) {
805 GpuBenchmarkingContext context;
806 if (!context.Init(true))
807 return 0;
809 std::string name;
810 v8::Local<v8::Function> callback;
811 v8::Local<v8::Object> arguments;
813 if (!GetArg(args, &name) || !GetArg(args, &callback) ||
814 !GetOptionalArg(args, &arguments)) {
815 return 0;
818 scoped_refptr<CallbackAndContext> callback_and_context =
819 new CallbackAndContext(args->isolate(),
820 callback,
821 context.web_frame()->mainWorldScriptContext());
823 scoped_ptr<V8ValueConverter> converter =
824 make_scoped_ptr(V8ValueConverter::create());
825 v8::Local<v8::Context> v8_context = callback_and_context->GetContext();
826 scoped_ptr<base::Value> value =
827 make_scoped_ptr(converter->FromV8Value(arguments, v8_context));
829 return context.compositor()->ScheduleMicroBenchmark(
830 name,
831 value.Pass(),
832 base::Bind(&OnMicroBenchmarkCompleted, callback_and_context));
835 bool GpuBenchmarking::SendMessageToMicroBenchmark(
836 int id,
837 v8::Local<v8::Object> message) {
838 GpuBenchmarkingContext context;
839 if (!context.Init(true))
840 return false;
842 scoped_ptr<V8ValueConverter> converter =
843 make_scoped_ptr(V8ValueConverter::create());
844 v8::Local<v8::Context> v8_context =
845 context.web_frame()->mainWorldScriptContext();
846 scoped_ptr<base::Value> value =
847 make_scoped_ptr(converter->FromV8Value(message, v8_context));
849 return context.compositor()->SendMessageToMicroBenchmark(id, value.Pass());
852 bool GpuBenchmarking::HasGpuProcess() {
853 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
854 return !!gpu_channel;
857 } // namespace content