blob: ae1a8c354dd7aba2551d5eff2c20851aeb853358 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <unistd.h>
#include <string>
#include "base/bind.h"
#include "base/macros.h"
#include "mojo/application/application_runner_chromium.h"
#include "mojo/public/c/system/main.h"
#include "mojo/public/cpp/application/connect.h"
#include "mojo/ui/choreographer.h"
#include "mojo/ui/ganesh_view.h"
#include "mojo/ui/input_handler.h"
#include "mojo/ui/view_provider_app.h"
#include "third_party/dejavu-fonts-ttf-2.34/kDejaVuSansMonoRegular.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
namespace examples {
namespace {
constexpr uint32_t kContentImageResourceId = 1;
constexpr uint32_t kRootNodeId = mojo::gfx::composition::kSceneRootNodeId;
enum class Action {
kHang10,
kStutter30,
kCrash,
};
struct Button {
const char* label;
Action action;
};
const Button kButtons[] = {
{"Hang for 10 seconds", Action::kHang10},
{"Stutter for 30 seconds", Action::kStutter30},
{"Crash!", Action::kCrash},
};
constexpr SkScalar kButtonWidth = 300;
constexpr SkScalar kButtonHeight = 30;
constexpr SkScalar kMargin = 15;
} // namespace
class JankView : public mojo::ui::GaneshView,
public mojo::ui::ChoreographerDelegate,
public mojo::ui::InputListener {
public:
JankView(mojo::InterfaceHandle<mojo::ApplicationConnector> app_connector,
mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request)
: GaneshView(app_connector.Pass(), view_owner_request.Pass(), "Jank"),
choreographer_(scene(), this),
input_handler_(GetViewServiceProvider(), this),
typeface_(skia::AdoptRef(SkTypeface::CreateFromStream(
new SkMemoryStream(font_data::kDejaVuSansMonoRegular.data,
font_data::kDejaVuSansMonoRegular.size)))) {}
~JankView() override {}
private:
// |GaneshView|:
void OnPropertiesChanged(
uint32_t old_scene_version,
mojo::ui::ViewPropertiesPtr old_properties) override {
choreographer_.ScheduleDraw();
}
// |InputListener|:
void OnEvent(mojo::EventPtr event, const OnEventCallback& callback) override {
if (event->pointer_data && event->action == mojo::EventType::POINTER_DOWN) {
SkScalar x = event->pointer_data->x;
SkScalar y = event->pointer_data->y;
if (x >= kMargin && x <= kButtonWidth + kMargin) {
int index = (y - kMargin) / (kButtonHeight + kMargin);
if (index >= 0 &&
size_t(index) < sizeof(kButtons) / sizeof(kButtons[0]) &&
y < (kButtonHeight + kMargin) * (index + 1))
OnClick(kButtons[index]);
}
}
callback.Run(false);
}
// |ChoreographerDelegate|:
void OnDraw(const mojo::gfx::composition::FrameInfo& frame_info,
const base::TimeDelta& time_delta) override {
if (!properties())
return;
auto update = mojo::gfx::composition::SceneUpdate::New();
const mojo::Size& size = *properties()->view_layout->size;
if (size.width > 0 && size.height > 0) {
mojo::RectF bounds;
bounds.width = size.width;
bounds.height = size.height;
mojo::gfx::composition::ResourcePtr content_resource =
ganesh_renderer()->DrawCanvas(
size, base::Bind(&JankView::DrawContent, base::Unretained(this)));
DCHECK(content_resource);
update->resources.insert(kContentImageResourceId,
content_resource.Pass());
auto root_node = mojo::gfx::composition::Node::New();
root_node->hit_test_behavior =
mojo::gfx::composition::HitTestBehavior::New();
root_node->op = mojo::gfx::composition::NodeOp::New();
root_node->op->set_image(mojo::gfx::composition::ImageNodeOp::New());
root_node->op->get_image()->content_rect = bounds.Clone();
root_node->op->get_image()->image_resource_id = kContentImageResourceId;
update->nodes.insert(kRootNodeId, root_node.Pass());
} else {
auto root_node = mojo::gfx::composition::Node::New();
update->nodes.insert(kRootNodeId, root_node.Pass());
}
scene()->Update(update.Pass());
auto metadata = mojo::gfx::composition::SceneMetadata::New();
metadata->version = scene_version();
scene()->Publish(metadata.Pass());
choreographer_.ScheduleDraw();
if (MojoGetTimeTicksNow() < stutter_end_time_)
sleep(2);
}
void DrawContent(const mojo::skia::GaneshContext::Scope& ganesh_scope,
const mojo::Size& size,
SkCanvas* canvas) {
SkScalar hsv[3] = {fmod(MojoGetTimeTicksNow() * 0.000001f * 60, 360.f), 1,
1};
canvas->clear(SkHSVToColor(hsv));
SkScalar x = kMargin;
SkScalar y = kMargin;
for (const auto& button : kButtons) {
DrawButton(canvas, button.label,
SkRect::MakeXYWH(x, y, kButtonWidth, kButtonHeight));
y += kButtonHeight + kMargin;
}
}
void DrawButton(SkCanvas* canvas, const char* label, const SkRect& bounds) {
SkPaint boxPaint;
boxPaint.setColor(SkColorSetRGB(200, 200, 200));
canvas->drawRect(bounds, boxPaint);
boxPaint.setColor(SkColorSetRGB(40, 40, 40));
boxPaint.setStyle(SkPaint::kStroke_Style);
canvas->drawRect(bounds, boxPaint);
SkPaint textPaint;
textPaint.setColor(SK_ColorBLACK);
textPaint.setTextSize(16);
textPaint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
textPaint.setTypeface(typeface_.get());
textPaint.setAntiAlias(true);
SkRect textBounds;
textPaint.measureText(label, strlen(label), &textBounds);
canvas->drawText(label, strlen(label),
bounds.centerX() - textBounds.centerX(),
bounds.centerY() - textBounds.centerY(), textPaint);
}
void OnClick(const Button& button) {
LOG(INFO) << "Clicked: " << button.label;
switch (button.action) {
case Action::kHang10: {
sleep(10);
break;
}
case Action::kStutter30: {
stutter_end_time_ = MojoGetTimeTicksNow() + 30 * 1000000;
break;
}
case Action::kCrash: {
abort();
break;
}
}
}
mojo::ui::Choreographer choreographer_;
mojo::ui::InputHandler input_handler_;
skia::RefPtr<SkTypeface> typeface_;
int64_t stutter_end_time_ = 0u;
DISALLOW_COPY_AND_ASSIGN(JankView);
};
class JankApp : public mojo::ui::ViewProviderApp {
public:
JankApp() {}
~JankApp() override {}
void CreateView(
const std::string& connection_url,
mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request,
mojo::InterfaceRequest<mojo::ServiceProvider> services) override {
new JankView(mojo::CreateApplicationConnector(app_impl()->shell()),
view_owner_request.Pass());
}
private:
DISALLOW_COPY_AND_ASSIGN(JankApp);
};
} // namespace examples
MojoResult MojoMain(MojoHandle application_request) {
mojo::ApplicationRunnerChromium runner(new examples::JankApp());
return runner.Run(application_request);
}