1a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// found in the LICENSE file.
4a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "content/renderer/skia_benchmarking_extension.h"
6a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/base64.h"
8fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "base/time/time.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/values.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "cc/base/math_util.h"
11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "cc/resources/picture.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/public/renderer/v8_value_converter.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/renderer/render_thread_impl.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "gin/arguments.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "gin/handle.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "gin/object_template_builder.h"
17fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "skia/ext/benchmarking_canvas.h"
189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/WebKit/public/web/WebArrayBufferConverter.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebFrame.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/WebKit/public/web/WebKit.h"
22a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "third_party/skia/include/core/SkCanvas.h"
23a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "third_party/skia/include/core/SkColorPriv.h"
24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "third_party/skia/include/core/SkGraphics.h"
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "third_party/skia/include/core/SkStream.h"
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "third_party/skia/src/utils/debugger/SkDebugCanvas.h"
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "third_party/skia/src/utils/debugger/SkDrawCommand.h"
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/rect_conversions.h"
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/skia_util.h"
30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "v8/include/v8.h"
31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace content {
34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<base::Value> ParsePictureArg(v8::Isolate* isolate,
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        v8::Handle<v8::Value> arg) {
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<content::V8ValueConverter> converter(
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      content::V8ValueConverter::create());
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return scoped_ptr<base::Value>(
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      converter->FromV8Value(arg, isolate->GetCurrentContext()));
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<cc::Picture> ParsePictureStr(v8::Isolate* isolate,
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           v8::Handle<v8::Value> arg) {
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<base::Value> picture_value = ParsePictureArg(isolate, arg);
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!picture_value)
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return NULL;
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return cc::Picture::CreateFromSkpValue(picture_value.get());
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<cc::Picture> ParsePictureHash(v8::Isolate* isolate,
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            v8::Handle<v8::Value> arg) {
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<base::Value> picture_value = ParsePictureArg(isolate, arg);
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!picture_value)
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return NULL;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return cc::Picture::CreateFromValue(picture_value.get());
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)gin::WrapperInfo SkiaBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
64a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkiaBenchmarking::Install(blink::WebFrame* frame) {
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Isolate* isolate = blink::mainThreadIsolate();
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::HandleScope handle_scope(isolate);
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (context.IsEmpty())
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Context::Scope context_scope(context);
74a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gin::Handle<SkiaBenchmarking> controller =
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gin::CreateHandle(isolate, new SkiaBenchmarking());
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (controller.IsEmpty())
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Object> global = context->Global();
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Object> chrome =
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      global->Get(gin::StringToV8(isolate, "chrome"))->ToObject();
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (chrome.IsEmpty()) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    chrome = v8::Object::New(isolate);
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    global->Set(gin::StringToV8(isolate, "chrome"), chrome);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  chrome->Set(gin::StringToV8(isolate, "skiaBenchmarking"), controller.ToV8());
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkiaBenchmarking::Initialize() {
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(RenderThreadImpl::current());
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // FIXME: remove this after Skia updates SkGraphics::Init() to be
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //        thread-safe and idempotent.
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static bool skia_initialized = false;
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!skia_initialized) {
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(WARNING) << "Enabling unsafe Skia benchmarking extension.";
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SkGraphics::Init();
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    skia_initialized = true;
100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SkiaBenchmarking::SkiaBenchmarking() {
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Initialize();
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SkiaBenchmarking::~SkiaBenchmarking() {}
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)gin::ObjectTemplateBuilder SkiaBenchmarking::GetObjectTemplateBuilder(
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    v8::Isolate* isolate) {
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return gin::Wrappable<SkiaBenchmarking>::GetObjectTemplateBuilder(isolate)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .SetMethod("rasterize", &SkiaBenchmarking::Rasterize)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .SetMethod("getOps", &SkiaBenchmarking::GetOps)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .SetMethod("getOpTimings", &SkiaBenchmarking::GetOpTimings)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .SetMethod("getInfo", &SkiaBenchmarking::GetInfo);
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkiaBenchmarking::Rasterize(gin::Arguments* args) {
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Isolate* isolate = args->isolate();
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (args->PeekNext().IsEmpty())
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Value> picture_handle;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->GetNext(&picture_handle);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<cc::Picture> picture =
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ParsePictureHash(isolate, picture_handle);
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!picture.get())
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  double scale = 1.0;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Rect clip_rect(picture->LayerRect());
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int stop_index = -1;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool overdraw = false;
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  v8::Handle<v8::Context> context = isolate->GetCurrentContext();
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!args->PeekNext().IsEmpty()) {
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    v8::Handle<v8::Value> params;
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    args->GetNext(&params);
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<content::V8ValueConverter> converter(
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        content::V8ValueConverter::create());
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::Value> params_value(
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        converter->FromV8Value(params, context));
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::DictionaryValue* params_dict = NULL;
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (params_value.get() && params_value->GetAsDictionary(&params_dict)) {
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params_dict->GetDouble("scale", &scale);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params_dict->GetInteger("stop", &stop_index);
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params_dict->GetBoolean("overdraw", &overdraw);
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::Value* clip_value = NULL;
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (params_dict->Get("clip", &clip_value))
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        cc::MathUtil::FromValue(clip_value, &clip_rect);
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::RectF clip(clip_rect);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  clip.Intersect(picture->LayerRect());
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  clip.Scale(scale);
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Rect snapped_clip = gfx::ToEnclosingRect(clip);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SkBitmap bitmap;
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!bitmap.tryAllocN32Pixels(snapped_clip.width(), snapped_clip.height()))
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bitmap.eraseARGB(0, 0, 0, 0);
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SkCanvas canvas(bitmap);
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  canvas.translate(SkFloatToScalar(-clip.x()), SkFloatToScalar(-clip.y()));
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  canvas.clipRect(gfx::RectToSkRect(snapped_clip));
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  canvas.scale(scale, scale);
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  canvas.translate(picture->LayerRect().x(), picture->LayerRect().y());
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // First, build a debug canvas for the given picture.
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SkDebugCanvas debug_canvas(picture->LayerRect().width(),
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             picture->LayerRect().height());
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  picture->Replay(&debug_canvas);
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Raster the requested command subset into the bitmap-backed canvas.
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int last_index = debug_canvas.getSize() - 1;
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (last_index >= 0) {
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    debug_canvas.setOverdrawViz(overdraw);
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    debug_canvas.drawTo(
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        &canvas,
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        stop_index < 0 ? last_index : std::min(last_index, stop_index));
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
184fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blink::WebArrayBuffer buffer =
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blink::WebArrayBuffer::create(bitmap.getSize(), 1);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uint32* packed_pixels = reinterpret_cast<uint32*>(bitmap.getPixels());
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uint8* buffer_pixels = reinterpret_cast<uint8*>(buffer.data());
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Swizzle from native Skia format to RGBA as we copy out.
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < bitmap.getSize(); i += 4) {
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint32 c = packed_pixels[i >> 2];
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    buffer_pixels[i] = SkGetPackedR32(c);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    buffer_pixels[i + 1] = SkGetPackedG32(c);
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    buffer_pixels[i + 2] = SkGetPackedB32(c);
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    buffer_pixels[i + 3] = SkGetPackedA32(c);
196fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  }
19758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Object> result = v8::Object::New(isolate);
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->Set(v8::String::NewFromUtf8(isolate, "width"),
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              v8::Number::New(isolate, snapped_clip.width()));
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->Set(v8::String::NewFromUtf8(isolate, "height"),
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              v8::Number::New(isolate, snapped_clip.height()));
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->Set(v8::String::NewFromUtf8(isolate, "data"),
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              blink::WebArrayBufferConverter::toV8Value(
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  &buffer, context->Global(), isolate));
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->Return(result);
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkiaBenchmarking::GetOps(gin::Arguments* args) {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Isolate* isolate = args->isolate();
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (args->PeekNext().IsEmpty())
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Value> picture_handle;
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->GetNext(&picture_handle);
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<cc::Picture> picture =
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ParsePictureHash(isolate, picture_handle);
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!picture.get())
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Rect bounds = picture->LayerRect();
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SkDebugCanvas canvas(bounds.width(), bounds.height());
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  picture->Replay(&canvas);
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Array> result = v8::Array::New(isolate, canvas.getSize());
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < canvas.getSize(); ++i) {
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DrawType cmd_type = canvas.getDrawCommandAt(i)->getType();
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    v8::Handle<v8::Object> cmd = v8::Object::New(isolate);
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cmd->Set(v8::String::NewFromUtf8(isolate, "cmd_type"),
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             v8::Integer::New(isolate, cmd_type));
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cmd->Set(v8::String::NewFromUtf8(isolate, "cmd_string"),
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             v8::String::NewFromUtf8(
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 isolate, SkDrawCommand::GetCommandString(cmd_type)));
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SkTDArray<SkString*>* info = canvas.getCommandInfo(i);
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(info);
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    v8::Local<v8::Array> v8_info = v8::Array::New(isolate, info->count());
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (int j = 0; j < info->count(); ++j) {
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const SkString* info_str = (*info)[j];
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(info_str);
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      v8_info->Set(j, v8::String::NewFromUtf8(isolate, info_str->c_str()));
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
24458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cmd->Set(v8::String::NewFromUtf8(isolate, "info"), v8_info);
24658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result->Set(i, cmd);
24858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
249a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->Return(result.As<v8::Object>());
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
252a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkiaBenchmarking::GetOpTimings(gin::Arguments* args) {
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Isolate* isolate = args->isolate();
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (args->PeekNext().IsEmpty())
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Value> picture_handle;
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->GetNext(&picture_handle);
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<cc::Picture> picture =
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ParsePictureHash(isolate, picture_handle);
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!picture.get())
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Rect bounds = picture->LayerRect();
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Measure the total time by drawing straight into a bitmap-backed canvas.
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SkBitmap bitmap;
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bitmap.allocN32Pixels(bounds.width(), bounds.height());
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SkCanvas bitmap_canvas(bitmap);
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bitmap_canvas.clear(SK_ColorTRANSPARENT);
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::TimeTicks t0 = base::TimeTicks::HighResNow();
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  picture->Replay(&bitmap_canvas);
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::TimeDelta total_time = base::TimeTicks::HighResNow() - t0;
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Gather per-op timing info by drawing into a BenchmarkingCanvas.
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  skia::BenchmarkingCanvas benchmarking_canvas(bounds.width(), bounds.height());
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  picture->Replay(&benchmarking_canvas);
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Local<v8::Array> op_times =
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      v8::Array::New(isolate, benchmarking_canvas.CommandCount());
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < benchmarking_canvas.CommandCount(); ++i)
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    op_times->Set(i, v8::Number::New(isolate, benchmarking_canvas.GetTime(i)));
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Object> result = v8::Object::New(isolate);
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->Set(v8::String::NewFromUtf8(isolate, "total_time"),
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              v8::Number::New(isolate, total_time.InMillisecondsF()));
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->Set(v8::String::NewFromUtf8(isolate, "cmd_times"), op_times);
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->Return(result);
290a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
291a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkiaBenchmarking::GetInfo(gin::Arguments* args) {
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Isolate* isolate = args->isolate();
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (args->PeekNext().IsEmpty())
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Value> picture_handle;
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->GetNext(&picture_handle);
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<cc::Picture> picture =
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ParsePictureStr(isolate, picture_handle);
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!picture.get())
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  v8::Handle<v8::Object> result = v8::Object::New(isolate);
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->Set(v8::String::NewFromUtf8(isolate, "width"),
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              v8::Number::New(isolate, picture->LayerRect().width()));
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result->Set(v8::String::NewFromUtf8(isolate, "height"),
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              v8::Number::New(isolate, picture->LayerRect().height()));
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  args->Return(result);
310a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
311a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
312a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} // namespace content
313