Replace FINAL and OVERRIDE with their C++11 counterparts in content/renderer
[chromium-blink-merge.git] / content / renderer / gpu / gpu_benchmarking_extension.cc
blob4af1540bad8ec0a978bec0a2b19bad6d827f04f9
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_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/gpu/render_widget_compositor.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "content/renderer/render_view_impl.h"
24 #include "content/renderer/skia_benchmarking_extension.h"
25 #include "third_party/WebKit/public/web/WebImageCache.h"
26 #include "third_party/WebKit/public/web/WebLocalFrame.h"
27 #include "third_party/WebKit/public/web/WebView.h"
28 #include "third_party/skia/include/core/SkData.h"
29 #include "third_party/skia/include/core/SkGraphics.h"
30 #include "third_party/skia/include/core/SkPicture.h"
31 #include "third_party/skia/include/core/SkPixelRef.h"
32 #include "third_party/skia/include/core/SkStream.h"
33 #include "ui/gfx/codec/png_codec.h"
34 #include "v8/include/v8.h"
36 using blink::WebCanvas;
37 using blink::WebLocalFrame;
38 using blink::WebImageCache;
39 using blink::WebPrivatePtr;
40 using blink::WebSize;
41 using blink::WebView;
43 const char kGpuBenchmarkingExtensionName[] = "v8/GpuBenchmarking";
45 // offset parameter is deprecated/ignored, and will be remove from the
46 // signature in a future skia release. <reed@google.com>
47 static SkData* EncodeBitmapToData(size_t* offset, const SkBitmap& bm) {
48 SkPixelRef* pr = bm.pixelRef();
49 if (pr != NULL) {
50 SkData* data = pr->refEncodedData();
51 if (data != NULL)
52 return data;
54 std::vector<unsigned char> vector;
55 if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
56 return SkData::NewWithCopy(&vector.front() , vector.size());
58 return NULL;
61 namespace {
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::SkiaBenchmarking::Initialize();
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());
82 skia::RefPtr<SkPicture> picture = layer->GetPicture();
83 if (!picture)
84 return;
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);
98 private:
99 base::FilePath dirpath_;
100 int layer_id_;
103 } // namespace
105 namespace content {
107 namespace {
109 class CallbackAndContext : public base::RefCounted<CallbackAndContext> {
110 public:
111 CallbackAndContext(v8::Isolate* isolate,
112 v8::Handle<v8::Function> callback,
113 v8::Handle<v8::Context> context)
114 : isolate_(isolate) {
115 callback_.Reset(isolate_, callback);
116 context_.Reset(isolate_, context);
119 v8::Isolate* isolate() {
120 return isolate_;
123 v8::Handle<v8::Function> GetCallback() {
124 return v8::Local<v8::Function>::New(isolate_, callback_);
127 v8::Handle<v8::Context> GetContext() {
128 return v8::Local<v8::Context>::New(isolate_, context_);
131 private:
132 friend class base::RefCounted<CallbackAndContext>;
134 virtual ~CallbackAndContext() {
135 callback_.Reset();
136 context_.Reset();
139 v8::Isolate* isolate_;
140 v8::Persistent<v8::Function> callback_;
141 v8::Persistent<v8::Context> context_;
142 DISALLOW_COPY_AND_ASSIGN(CallbackAndContext);
145 class GpuBenchmarkingContext {
146 public:
147 GpuBenchmarkingContext()
148 : web_frame_(NULL),
149 web_view_(NULL),
150 render_view_impl_(NULL),
151 compositor_(NULL) {}
153 bool Init(bool init_compositor) {
154 web_frame_ = WebLocalFrame::frameForCurrentContext();
155 if (!web_frame_)
156 return false;
158 web_view_ = web_frame_->view();
159 if (!web_view_) {
160 web_frame_ = NULL;
161 return false;
164 render_view_impl_ = RenderViewImpl::FromWebView(web_view_);
165 if (!render_view_impl_) {
166 web_frame_ = NULL;
167 web_view_ = NULL;
168 return false;
171 if (!init_compositor)
172 return true;
174 compositor_ = render_view_impl_->compositor();
175 if (!compositor_) {
176 web_frame_ = NULL;
177 web_view_ = NULL;
178 render_view_impl_ = NULL;
179 return false;
182 return true;
185 WebLocalFrame* web_frame() const {
186 DCHECK(web_frame_ != NULL);
187 return web_frame_;
189 WebView* web_view() const {
190 DCHECK(web_view_ != NULL);
191 return web_view_;
193 RenderViewImpl* render_view_impl() const {
194 DCHECK(render_view_impl_ != NULL);
195 return render_view_impl_;
197 RenderWidgetCompositor* compositor() const {
198 DCHECK(compositor_ != NULL);
199 return compositor_;
202 private:
203 WebLocalFrame* web_frame_;
204 WebView* web_view_;
205 RenderViewImpl* render_view_impl_;
206 RenderWidgetCompositor* compositor_;
208 DISALLOW_COPY_AND_ASSIGN(GpuBenchmarkingContext);
211 } // namespace
213 class GpuBenchmarkingWrapper : public v8::Extension {
214 public:
215 GpuBenchmarkingWrapper() :
216 v8::Extension(kGpuBenchmarkingExtensionName,
217 "if (typeof(chrome) == 'undefined') {"
218 " chrome = {};"
219 "};"
220 "if (typeof(chrome.gpuBenchmarking) == 'undefined') {"
221 " chrome.gpuBenchmarking = {};"
222 "};"
223 "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {"
224 " native function SetNeedsDisplayOnAllLayers();"
225 " return SetNeedsDisplayOnAllLayers();"
226 "};"
227 "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = "
228 "function() {"
229 " native function SetRasterizeOnlyVisibleContent();"
230 " return SetRasterizeOnlyVisibleContent();"
231 "};"
232 "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {"
233 " native function PrintToSkPicture();"
234 " return PrintToSkPicture(dirname);"
235 "};"
236 "chrome.gpuBenchmarking.DEFAULT_INPUT = 0;"
237 "chrome.gpuBenchmarking.TOUCH_INPUT = 1;"
238 "chrome.gpuBenchmarking.MOUSE_INPUT = 2;"
239 "chrome.gpuBenchmarking.gestureSourceTypeSupported = "
240 " function(gesture_source_type) {"
241 " native function GestureSourceTypeSupported();"
242 " return GestureSourceTypeSupported(gesture_source_type);"
243 "};"
244 "chrome.gpuBenchmarking.smoothScrollBy = "
245 " function(pixels_to_scroll, opt_callback, opt_start_x,"
246 " opt_start_y, opt_gesture_source_type,"
247 " opt_direction, opt_speed_in_pixels_s) {"
248 " pixels_to_scroll = pixels_to_scroll || 0;"
249 " callback = opt_callback || function() { };"
250 " gesture_source_type = opt_gesture_source_type ||"
251 " chrome.gpuBenchmarking.DEFAULT_INPUT;"
252 " direction = opt_direction || 'down';"
253 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;"
254 " native function BeginSmoothScroll();"
255 " return BeginSmoothScroll(pixels_to_scroll, callback,"
256 " gesture_source_type, direction,"
257 " speed_in_pixels_s, true,"
258 " opt_start_x, opt_start_y);"
259 "};"
260 "chrome.gpuBenchmarking.swipe = "
261 " function(direction, distance, opt_callback,"
262 " opt_start_x, opt_start_y,"
263 " opt_speed_in_pixels_s) {"
264 " direction = direction || 'up';"
265 " distance = distance || 0;"
266 " callback = opt_callback || function() { };"
267 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;"
268 " native function BeginSmoothScroll();"
269 " return BeginSmoothScroll(-distance, callback,"
270 " chrome.gpuBenchmarking.TOUCH_INPUT,"
271 " direction, speed_in_pixels_s, false,"
272 " opt_start_x, opt_start_y);"
273 "};"
274 "chrome.gpuBenchmarking.scrollBounce = "
275 " function(direction, distance, overscroll, opt_repeat_count,"
276 " opt_callback, opt_start_x, opt_start_y,"
277 " opt_speed_in_pixels_s) {"
278 " direction = direction || 'down';"
279 " distance = distance || 0;"
280 " overscroll = overscroll || 0;"
281 " repeat_count = opt_repeat_count || 1;"
282 " callback = opt_callback || function() { };"
283 " speed_in_pixels_s = opt_speed_in_pixels_s || 800;"
284 " native function BeginScrollBounce();"
285 " return BeginScrollBounce(direction, distance, overscroll,"
286 " repeat_count, callback,"
287 " speed_in_pixels_s,"
288 " opt_start_x, opt_start_y);"
289 "};"
290 // TODO(dominikg): Remove once JS interface changes have rolled into
291 // stable.
292 "chrome.gpuBenchmarking.newPinchInterface = true;"
293 "chrome.gpuBenchmarking.pinchBy = "
294 " function(scale_factor, anchor_x, anchor_y,"
295 " opt_callback, "
296 "opt_relative_pointer_speed_in_pixels_s) {"
297 " callback = opt_callback || function() { };"
298 " relative_pointer_speed_in_pixels_s ="
299 " opt_relative_pointer_speed_in_pixels_s || 800;"
300 " native function BeginPinch();"
301 " return BeginPinch(scale_factor, anchor_x, anchor_y, callback,"
302 " relative_pointer_speed_in_pixels_s);"
303 "};"
304 "chrome.gpuBenchmarking.tap = "
305 " function(position_x, position_y, opt_callback, "
306 "opt_duration_ms,"
307 " opt_gesture_source_type) {"
308 " callback = opt_callback || function() { };"
309 " duration_ms = opt_duration_ms || 50;"
310 " gesture_source_type = opt_gesture_source_type ||"
311 " chrome.gpuBenchmarking.DEFAULT_INPUT;"
312 " native function BeginTap();"
313 " return BeginTap(position_x, position_y, callback, duration_ms,"
314 " gesture_source_type);"
315 "};"
316 "chrome.gpuBenchmarking.beginWindowSnapshotPNG = "
317 "function(callback) {"
318 " native function BeginWindowSnapshotPNG();"
319 " BeginWindowSnapshotPNG(callback);"
320 "};"
321 "chrome.gpuBenchmarking.clearImageCache = function() {"
322 " native function ClearImageCache();"
323 " ClearImageCache();"
324 "};"
325 "chrome.gpuBenchmarking.runMicroBenchmark ="
326 " function(name, callback, opt_arguments) {"
327 " arguments = opt_arguments || {};"
328 " native function RunMicroBenchmark();"
329 " return RunMicroBenchmark(name, callback, arguments);"
330 "};"
331 "chrome.gpuBenchmarking.sendMessageToMicroBenchmark ="
332 " function(id, arguments) {"
333 " native function SendMessageToMicroBenchmark();"
334 " return SendMessageToMicroBenchmark(id, arguments);"
335 "};"
336 "chrome.gpuBenchmarking.hasGpuProcess = function() {"
337 " native function HasGpuProcess();"
338 " return HasGpuProcess();"
339 "};") {}
341 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
342 v8::Isolate* isolate,
343 v8::Handle<v8::String> name) override {
344 if (name->Equals(
345 v8::String::NewFromUtf8(isolate, "SetNeedsDisplayOnAllLayers")))
346 return v8::FunctionTemplate::New(isolate, SetNeedsDisplayOnAllLayers);
347 if (name->Equals(
348 v8::String::NewFromUtf8(isolate, "SetRasterizeOnlyVisibleContent")))
349 return v8::FunctionTemplate::New(isolate, SetRasterizeOnlyVisibleContent);
350 if (name->Equals(v8::String::NewFromUtf8(isolate, "PrintToSkPicture")))
351 return v8::FunctionTemplate::New(isolate, PrintToSkPicture);
352 if (name->Equals(
353 v8::String::NewFromUtf8(isolate, "GestureSourceTypeSupported")))
354 return v8::FunctionTemplate::New(isolate, GestureSourceTypeSupported);
355 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginSmoothScroll")))
356 return v8::FunctionTemplate::New(isolate, BeginSmoothScroll);
357 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginScrollBounce")))
358 return v8::FunctionTemplate::New(isolate, BeginScrollBounce);
359 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginPinch")))
360 return v8::FunctionTemplate::New(isolate, BeginPinch);
361 if (name->Equals(v8::String::NewFromUtf8(isolate, "BeginTap")))
362 return v8::FunctionTemplate::New(isolate, BeginTap);
363 if (name->Equals(
364 v8::String::NewFromUtf8(isolate, "BeginWindowSnapshotPNG")))
365 return v8::FunctionTemplate::New(isolate, BeginWindowSnapshotPNG);
366 if (name->Equals(v8::String::NewFromUtf8(isolate, "ClearImageCache")))
367 return v8::FunctionTemplate::New(isolate, ClearImageCache);
368 if (name->Equals(v8::String::NewFromUtf8(isolate, "RunMicroBenchmark")))
369 return v8::FunctionTemplate::New(isolate, RunMicroBenchmark);
370 if (name->Equals(
371 v8::String::NewFromUtf8(isolate, "SendMessageToMicroBenchmark")))
372 return v8::FunctionTemplate::New(isolate, SendMessageToMicroBenchmark);
373 if (name->Equals(v8::String::NewFromUtf8(isolate, "HasGpuProcess")))
374 return v8::FunctionTemplate::New(isolate, HasGpuProcess);
376 return v8::Handle<v8::FunctionTemplate>();
379 static void SetNeedsDisplayOnAllLayers(
380 const v8::FunctionCallbackInfo<v8::Value>& args) {
381 GpuBenchmarkingContext context;
382 if (!context.Init(true))
383 return;
385 context.compositor()->SetNeedsDisplayOnAllLayers();
388 static void SetRasterizeOnlyVisibleContent(
389 const v8::FunctionCallbackInfo<v8::Value>& args) {
390 GpuBenchmarkingContext context;
391 if (!context.Init(true))
392 return;
394 context.compositor()->SetRasterizeOnlyVisibleContent();
397 static void PrintToSkPicture(
398 const v8::FunctionCallbackInfo<v8::Value>& args) {
399 if (args.Length() != 1)
400 return;
402 v8::String::Utf8Value dirname(args[0]);
403 if (dirname.length() == 0)
404 return;
406 GpuBenchmarkingContext context;
407 if (!context.Init(true))
408 return;
410 const cc::Layer* root_layer = context.compositor()->GetRootLayer();
411 if (!root_layer)
412 return;
414 base::FilePath dirpath(
415 base::FilePath::StringType(*dirname, *dirname + dirname.length()));
416 if (!base::CreateDirectory(dirpath) ||
417 !base::PathIsWritable(dirpath)) {
418 std::string msg("Path is not writable: ");
419 msg.append(dirpath.MaybeAsASCII());
420 v8::Isolate* isolate = args.GetIsolate();
421 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
422 isolate, msg.c_str(), v8::String::kNormalString, msg.length())));
423 return;
426 SkPictureSerializer serializer(dirpath);
427 serializer.Serialize(root_layer);
430 static void OnSyntheticGestureCompleted(
431 CallbackAndContext* callback_and_context) {
432 v8::Isolate* isolate = callback_and_context->isolate();
433 v8::HandleScope scope(isolate);
434 v8::Handle<v8::Context> context = callback_and_context->GetContext();
435 v8::Context::Scope context_scope(context);
436 WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
437 if (frame) {
438 frame->callFunctionEvenIfScriptDisabled(
439 callback_and_context->GetCallback(),
440 v8::Object::New(isolate),
442 NULL);
446 static void GestureSourceTypeSupported(
447 const v8::FunctionCallbackInfo<v8::Value>& args) {
448 if (args.Length() != 1 || !args[0]->IsNumber()) {
449 args.GetReturnValue().Set(false);
450 return;
453 int gesture_source_type = args[0]->IntegerValue();
454 if (gesture_source_type < 0 ||
455 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
456 args.GetReturnValue().Set(false);
457 return;
460 bool is_supported = SyntheticGestureParams::IsGestureSourceTypeSupported(
461 static_cast<SyntheticGestureParams::GestureSourceType>(
462 gesture_source_type));
463 args.GetReturnValue().Set(is_supported);
466 static void BeginSmoothScroll(
467 const v8::FunctionCallbackInfo<v8::Value>& args) {
468 GpuBenchmarkingContext context;
469 if (!context.Init(false))
470 return;
472 // The last two arguments can be undefined. We check their validity later.
473 int arglen = args.Length();
474 if (arglen < 8 ||
475 !args[0]->IsNumber() ||
476 !args[1]->IsFunction() ||
477 !args[2]->IsNumber() ||
478 !args[3]->IsString() ||
479 !args[4]->IsNumber() ||
480 !args[5]->IsBoolean()) {
481 args.GetReturnValue().Set(false);
482 return;
485 v8::Local<v8::Function> callback_local =
486 v8::Local<v8::Function>::Cast(args[1]);
488 scoped_refptr<CallbackAndContext> callback_and_context =
489 new CallbackAndContext(args.GetIsolate(),
490 callback_local,
491 context.web_frame()->mainWorldScriptContext());
493 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params(
494 new SyntheticSmoothScrollGestureParams);
496 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
497 float page_scale_factor = context.web_view()->pageScaleFactor();
499 int gesture_source_type = args[2]->IntegerValue();
500 if (gesture_source_type < 0 ||
501 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
502 args.GetReturnValue().Set(false);
503 return;
505 gesture_params->gesture_source_type =
506 static_cast<SyntheticGestureParams::GestureSourceType>(
507 gesture_source_type);
509 gesture_params->speed_in_pixels_s = args[4]->IntegerValue();
510 gesture_params->prevent_fling = args[5]->BooleanValue();
512 // Account for the 2 optional arguments, start_x and start_y.
513 gfx::Point anchor;
514 if (args[6]->IsUndefined() || args[7]->IsUndefined()) {
515 blink::WebRect rect = context.render_view_impl()->windowRect();
516 anchor.SetPoint(rect.width / 2, rect.height / 2);
517 } else if (args[6]->IsNumber() && args[7]->IsNumber()) {
518 anchor.SetPoint(args[6]->IntegerValue() * page_scale_factor,
519 args[7]->IntegerValue() * page_scale_factor);
520 } else {
521 args.GetReturnValue().Set(false);
522 return;
524 gesture_params->anchor = anchor;
526 int distance_length = args[0]->IntegerValue() * page_scale_factor;
527 gfx::Vector2d distance;
528 v8::String::Utf8Value direction(args[3]);
529 DCHECK(*direction);
530 std::string direction_str(*direction);
531 if (direction_str == "down")
532 distance.set_y(-distance_length);
533 else if (direction_str == "up")
534 distance.set_y(distance_length);
535 else if (direction_str == "right")
536 distance.set_x(-distance_length);
537 else if (direction_str == "left")
538 distance.set_x(distance_length);
539 else {
540 args.GetReturnValue().Set(false);
541 return;
543 gesture_params->distances.push_back(distance);
545 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
546 // progress, we will leak the callback and context. This needs to be fixed,
547 // somehow.
548 context.render_view_impl()->QueueSyntheticGesture(
549 gesture_params.PassAs<SyntheticGestureParams>(),
550 base::Bind(&OnSyntheticGestureCompleted,
551 callback_and_context));
553 args.GetReturnValue().Set(true);
556 static void BeginScrollBounce(
557 const v8::FunctionCallbackInfo<v8::Value>& args) {
558 GpuBenchmarkingContext context;
559 if (!context.Init(false))
560 return;
562 // The last two arguments can be undefined. We check their validity later.
563 int arglen = args.Length();
564 if (arglen < 8 ||
565 !args[0]->IsString() ||
566 !args[1]->IsNumber() ||
567 !args[2]->IsNumber() ||
568 !args[3]->IsNumber() ||
569 !args[4]->IsFunction() ||
570 !args[5]->IsNumber()) {
571 args.GetReturnValue().Set(false);
572 return;
575 v8::Local<v8::Function> callback_local =
576 v8::Local<v8::Function>::Cast(args[4]);
578 scoped_refptr<CallbackAndContext> callback_and_context =
579 new CallbackAndContext(args.GetIsolate(),
580 callback_local,
581 context.web_frame()->mainWorldScriptContext());
583 scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params(
584 new SyntheticSmoothScrollGestureParams);
586 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
587 float page_scale_factor = context.web_view()->pageScaleFactor();
589 gesture_params->speed_in_pixels_s = args[5]->IntegerValue();
591 // Account for the 2 optional arguments, start_x and start_y.
592 gfx::Point start;
593 if (args[6]->IsUndefined() || args[7]->IsUndefined()) {
594 blink::WebRect rect = context.render_view_impl()->windowRect();
595 start.SetPoint(rect.width / 2, rect.height / 2);
596 } else if (args[6]->IsNumber() && args[7]->IsNumber()) {
597 start.SetPoint(args[6]->IntegerValue() * page_scale_factor,
598 args[7]->IntegerValue() * page_scale_factor);
599 } else {
600 args.GetReturnValue().Set(false);
601 return;
604 int distance_length = args[1]->IntegerValue() * page_scale_factor;
605 int overscroll_length = args[2]->IntegerValue() * page_scale_factor;
606 gfx::Vector2d distance;
607 gfx::Vector2d overscroll;
608 v8::String::Utf8Value direction(args[0]);
609 DCHECK(*direction);
610 std::string direction_str(*direction);
611 if (direction_str == "down") {
612 distance.set_y(-distance_length);
613 overscroll.set_y(overscroll_length);
615 else if (direction_str == "up") {
616 distance.set_y(distance_length);
617 overscroll.set_y(-overscroll_length);
619 else if (direction_str == "right") {
620 distance.set_x(-distance_length);
621 overscroll.set_x(overscroll_length);
623 else if (direction_str == "left") {
624 distance.set_x(distance_length);
625 overscroll.set_x(-overscroll_length);
627 else {
628 args.GetReturnValue().Set(false);
629 return;
632 int repeat_count = args[3]->IntegerValue();
633 gesture_params->anchor = start;
634 for (int i = 0; i < repeat_count; i++) {
635 gesture_params->distances.push_back(distance);
636 gesture_params->distances.push_back(-distance + overscroll);
639 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
640 // progress, we will leak the callback and context. This needs to be fixed,
641 // somehow.
642 context.render_view_impl()->QueueSyntheticGesture(
643 gesture_params.PassAs<SyntheticGestureParams>(),
644 base::Bind(&OnSyntheticGestureCompleted,
645 callback_and_context));
647 args.GetReturnValue().Set(true);
650 static void BeginPinch(
651 const v8::FunctionCallbackInfo<v8::Value>& args) {
652 GpuBenchmarkingContext context;
653 if (!context.Init(false))
654 return;
656 int arglen = args.Length();
657 if (arglen < 5 ||
658 !args[0]->IsNumber() ||
659 !args[1]->IsNumber() ||
660 !args[2]->IsNumber() ||
661 !args[3]->IsFunction() ||
662 !args[4]->IsNumber()) {
663 args.GetReturnValue().Set(false);
664 return;
667 scoped_ptr<SyntheticPinchGestureParams> gesture_params(
668 new SyntheticPinchGestureParams);
670 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
671 float page_scale_factor = context.web_view()->pageScaleFactor();
673 gesture_params->scale_factor = args[0]->NumberValue();
674 gesture_params->anchor.SetPoint(
675 args[1]->IntegerValue() * page_scale_factor,
676 args[2]->IntegerValue() * page_scale_factor);
677 gesture_params->relative_pointer_speed_in_pixels_s =
678 args[4]->IntegerValue();
680 v8::Local<v8::Function> callback_local =
681 v8::Local<v8::Function>::Cast(args[3]);
683 scoped_refptr<CallbackAndContext> callback_and_context =
684 new CallbackAndContext(args.GetIsolate(),
685 callback_local,
686 context.web_frame()->mainWorldScriptContext());
689 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
690 // progress, we will leak the callback and context. This needs to be fixed,
691 // somehow.
692 context.render_view_impl()->QueueSyntheticGesture(
693 gesture_params.PassAs<SyntheticGestureParams>(),
694 base::Bind(&OnSyntheticGestureCompleted,
695 callback_and_context));
697 args.GetReturnValue().Set(true);
700 static void BeginTap(
701 const v8::FunctionCallbackInfo<v8::Value>& args) {
702 GpuBenchmarkingContext context;
703 if (!context.Init(false))
704 return;
706 int arglen = args.Length();
707 if (arglen < 5 ||
708 !args[0]->IsNumber() ||
709 !args[1]->IsNumber() ||
710 !args[2]->IsFunction() ||
711 !args[3]->IsNumber() ||
712 !args[4]->IsNumber()) {
713 args.GetReturnValue().Set(false);
714 return;
717 scoped_ptr<SyntheticTapGestureParams> gesture_params(
718 new SyntheticTapGestureParams);
720 // Convert coordinates from CSS pixels to density independent pixels (DIPs).
721 float page_scale_factor = context.web_view()->pageScaleFactor();
723 gesture_params->position.SetPoint(
724 args[0]->IntegerValue() * page_scale_factor,
725 args[1]->IntegerValue() * page_scale_factor);
726 gesture_params->duration_ms = args[3]->IntegerValue();
728 int gesture_source_type = args[4]->IntegerValue();
729 if (gesture_source_type < 0 ||
730 gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
731 args.GetReturnValue().Set(false);
732 return;
734 gesture_params->gesture_source_type =
735 static_cast<SyntheticGestureParams::GestureSourceType>(
736 gesture_source_type);
738 v8::Local<v8::Function> callback_local =
739 v8::Local<v8::Function>::Cast(args[2]);
741 scoped_refptr<CallbackAndContext> callback_and_context =
742 new CallbackAndContext(args.GetIsolate(),
743 callback_local,
744 context.web_frame()->mainWorldScriptContext());
747 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
748 // progress, we will leak the callback and context. This needs to be fixed,
749 // somehow.
750 context.render_view_impl()->QueueSyntheticGesture(
751 gesture_params.PassAs<SyntheticGestureParams>(),
752 base::Bind(&OnSyntheticGestureCompleted,
753 callback_and_context));
755 args.GetReturnValue().Set(true);
758 static void OnSnapshotCompleted(CallbackAndContext* callback_and_context,
759 const gfx::Size& size,
760 const std::vector<unsigned char>& png) {
761 v8::Isolate* isolate = callback_and_context->isolate();
762 v8::HandleScope scope(isolate);
763 v8::Handle<v8::Context> context = callback_and_context->GetContext();
764 v8::Context::Scope context_scope(context);
765 WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
766 if (frame) {
768 v8::Handle<v8::Value> result;
770 if(!size.IsEmpty()) {
771 v8::Handle<v8::Object> result_object;
772 result_object = v8::Object::New(isolate);
774 result_object->Set(v8::String::NewFromUtf8(isolate, "width"),
775 v8::Number::New(isolate, size.width()));
776 result_object->Set(v8::String::NewFromUtf8(isolate, "height"),
777 v8::Number::New(isolate, size.height()));
779 std::string base64_png;
780 base::Base64Encode(base::StringPiece(
781 reinterpret_cast<const char*>(&*png.begin()), png.size()),
782 &base64_png);
784 result_object->Set(v8::String::NewFromUtf8(isolate, "data"),
785 v8::String::NewFromUtf8(isolate,
786 base64_png.c_str(),
787 v8::String::kNormalString,
788 base64_png.size()));
790 result = result_object;
791 } else {
792 result = v8::Null(isolate);
795 v8::Handle<v8::Value> argv[] = { result };
797 frame->callFunctionEvenIfScriptDisabled(
798 callback_and_context->GetCallback(),
799 v8::Object::New(isolate),
801 argv);
805 static void BeginWindowSnapshotPNG(
806 const v8::FunctionCallbackInfo<v8::Value>& args) {
807 GpuBenchmarkingContext context;
808 if (!context.Init(false))
809 return;
811 if (!args[0]->IsFunction())
812 return;
814 v8::Local<v8::Function> callback_local =
815 v8::Local<v8::Function>::Cast(args[0]);
817 scoped_refptr<CallbackAndContext> callback_and_context =
818 new CallbackAndContext(args.GetIsolate(),
819 callback_local,
820 context.web_frame()->mainWorldScriptContext());
822 context.render_view_impl()->GetWindowSnapshot(
823 base::Bind(&OnSnapshotCompleted, callback_and_context));
826 static void ClearImageCache(
827 const v8::FunctionCallbackInfo<v8::Value>& args) {
828 WebImageCache::clear();
831 static void OnMicroBenchmarkCompleted(
832 CallbackAndContext* callback_and_context,
833 scoped_ptr<base::Value> result) {
834 v8::Isolate* isolate = callback_and_context->isolate();
835 v8::HandleScope scope(isolate);
836 v8::Handle<v8::Context> context = callback_and_context->GetContext();
837 v8::Context::Scope context_scope(context);
838 WebLocalFrame* frame = WebLocalFrame::frameForContext(context);
839 if (frame) {
840 scoped_ptr<V8ValueConverter> converter =
841 make_scoped_ptr(V8ValueConverter::create());
842 v8::Handle<v8::Value> value = converter->ToV8Value(result.get(), context);
843 v8::Handle<v8::Value> argv[] = { value };
845 frame->callFunctionEvenIfScriptDisabled(
846 callback_and_context->GetCallback(),
847 v8::Object::New(isolate),
849 argv);
853 static void RunMicroBenchmark(
854 const v8::FunctionCallbackInfo<v8::Value>& args) {
855 GpuBenchmarkingContext context;
856 if (!context.Init(true)) {
857 args.GetReturnValue().Set(0);
858 return;
861 if (args.Length() != 3 ||
862 !args[0]->IsString() ||
863 !args[1]->IsFunction() ||
864 !args[2]->IsObject()) {
865 args.GetReturnValue().Set(0);
866 return;
869 v8::Local<v8::Function> callback_local =
870 v8::Local<v8::Function>::Cast(args[1]);
872 scoped_refptr<CallbackAndContext> callback_and_context =
873 new CallbackAndContext(args.GetIsolate(),
874 callback_local,
875 context.web_frame()->mainWorldScriptContext());
877 scoped_ptr<V8ValueConverter> converter =
878 make_scoped_ptr(V8ValueConverter::create());
879 v8::Handle<v8::Context> v8_context = callback_and_context->GetContext();
880 scoped_ptr<base::Value> value =
881 make_scoped_ptr(converter->FromV8Value(args[2], v8_context));
883 v8::String::Utf8Value benchmark(args[0]);
884 DCHECK(*benchmark);
885 args.GetReturnValue().Set(context.compositor()->ScheduleMicroBenchmark(
886 std::string(*benchmark),
887 value.Pass(),
888 base::Bind(&OnMicroBenchmarkCompleted, callback_and_context)));
891 static void SendMessageToMicroBenchmark(
892 const v8::FunctionCallbackInfo<v8::Value>& args) {
893 GpuBenchmarkingContext context;
894 if (!context.Init(true)) {
895 args.GetReturnValue().Set(0);
896 return;
899 if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsObject()) {
900 args.GetReturnValue().Set(0);
901 return;
904 scoped_ptr<V8ValueConverter> converter =
905 make_scoped_ptr(V8ValueConverter::create());
906 v8::Handle<v8::Context> v8_context =
907 context.web_frame()->mainWorldScriptContext();
908 scoped_ptr<base::Value> value =
909 make_scoped_ptr(converter->FromV8Value(args[1], v8_context));
911 int id = 0;
912 converter->FromV8Value(args[0], v8_context)->GetAsInteger(&id);
913 args.GetReturnValue().Set(
914 context.compositor()->SendMessageToMicroBenchmark(id, value.Pass()));
917 static void HasGpuProcess(const v8::FunctionCallbackInfo<v8::Value>& args) {
918 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel();
919 args.GetReturnValue().Set(!!gpu_channel);
923 v8::Extension* GpuBenchmarkingExtension::Get() {
924 return new GpuBenchmarkingWrapper();
927 } // namespace content