Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / ppapi / examples / mouse_lock / mouse_lock.cc
blob3b1644f7a43fc8a5830071a32a91f08d54ae0f97
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 <cmath>
6 #include <stdarg.h>
7 #include <stdio.h>
9 #include "ppapi/c/ppb_console.h"
10 #include "ppapi/c/ppb_input_event.h"
11 #include "ppapi/cpp/graphics_2d.h"
12 #include "ppapi/cpp/image_data.h"
13 #include "ppapi/cpp/input_event.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/logging.h"
16 #include "ppapi/cpp/module.h"
17 #include "ppapi/cpp/mouse_lock.h"
18 #include "ppapi/cpp/private/flash_fullscreen.h"
19 #include "ppapi/cpp/rect.h"
20 #include "ppapi/cpp/var.h"
21 #include "ppapi/utility/completion_callback_factory.h"
23 class MyInstance : public pp::Instance, public pp::MouseLock {
24 public:
25 explicit MyInstance(PP_Instance instance)
26 : pp::Instance(instance),
27 pp::MouseLock(this),
28 width_(0),
29 height_(0),
30 mouse_locked_(false),
31 pending_paint_(false),
32 waiting_for_flush_completion_(false),
33 callback_factory_(this),
34 console_(NULL),
35 flash_fullscreen_(this) {
37 virtual ~MyInstance() {}
39 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
40 console_ = reinterpret_cast<const PPB_Console*>(
41 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
42 if (!console_)
43 return false;
45 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE |
46 PP_INPUTEVENT_CLASS_KEYBOARD);
47 return true;
50 virtual bool HandleInputEvent(const pp::InputEvent& event) {
51 switch (event.GetType()) {
52 case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
53 pp::MouseInputEvent mouse_event(event);
54 if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
55 !mouse_locked_) {
56 LockMouse(callback_factory_.NewCallback(&MyInstance::DidLockMouse));
58 return true;
60 case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
61 pp::MouseInputEvent mouse_event(event);
62 mouse_movement_ = mouse_event.GetMovement();
63 static unsigned int i = 0;
64 Log(PP_LOGLEVEL_LOG, "[%d] movementX: %d; movementY: %d\n", i++,
65 mouse_movement_.x(), mouse_movement_.y());
66 Paint();
67 return true;
69 case PP_INPUTEVENT_TYPE_KEYDOWN: {
70 pp::KeyboardInputEvent key_event(event);
71 if (key_event.GetKeyCode() == 13) {
72 // Lock the mouse when the Enter key is pressed.
73 if (mouse_locked_)
74 UnlockMouse();
75 else
76 LockMouse(callback_factory_.NewCallback(&MyInstance::DidLockMouse));
77 return true;
78 } else if (key_event.GetKeyCode() == 70) {
79 // Enter Flash fullscreen mode when the 'f' key is pressed.
80 if (!flash_fullscreen_.IsFullscreen())
81 flash_fullscreen_.SetFullscreen(true);
82 return true;
84 return false;
86 default:
87 return false;
91 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
92 if (position.size().width() == width_ &&
93 position.size().height() == height_)
94 return; // We don't care about the position, only the size.
96 width_ = position.size().width();
97 height_ = position.size().height();
99 device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), false);
100 if (!BindGraphics(device_context_))
101 return;
103 Paint();
106 virtual void MouseLockLost() {
107 if (mouse_locked_) {
108 mouse_locked_ = false;
109 Paint();
110 } else {
111 PP_NOTREACHED();
115 private:
116 void DidLockMouse(int32_t result) {
117 mouse_locked_ = result == PP_OK;
118 mouse_movement_.set_x(0);
119 mouse_movement_.set_y(0);
120 Paint();
123 void DidFlush(int32_t result) {
124 waiting_for_flush_completion_ = false;
125 if (pending_paint_) {
126 pending_paint_ = false;
127 Paint();
131 void Paint() {
132 if (waiting_for_flush_completion_) {
133 pending_paint_ = true;
134 return;
137 pp::ImageData image = PaintImage(width_, height_);
138 if (!image.is_null()) {
139 device_context_.ReplaceContents(&image);
140 waiting_for_flush_completion_ = true;
141 device_context_.Flush(
142 callback_factory_.NewCallback(&MyInstance::DidFlush));
146 pp::ImageData PaintImage(int width, int height) {
147 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
148 pp::Size(width, height), false);
149 if (image.is_null())
150 return image;
152 const static int kCenteralSpotRadius = 5;
153 const static uint32_t kBackgroundColor = 0xfff0f0f0;
154 const static uint32_t kLockedForegroundColor = 0xfff08080;
155 const static uint32_t kUnlockedForegroundColor = 0xff80f080;
157 int center_x = width / 2;
158 int center_y = height / 2;
159 pp::Point vertex(mouse_movement_.x() + center_x,
160 mouse_movement_.y() + center_y);
161 pp::Point anchor_1;
162 pp::Point anchor_2;
163 enum {
164 LEFT = 0,
165 RIGHT = 1,
166 UP = 2,
167 DOWN = 3
168 } direction = LEFT;
169 bool draw_needle = GetDistance(mouse_movement_.x(), mouse_movement_.y(),
170 0, 0) > kCenteralSpotRadius;
171 if (draw_needle) {
172 if (abs(mouse_movement_.x()) >= abs(mouse_movement_.y())) {
173 anchor_1.set_x(center_x);
174 anchor_1.set_y(center_y - kCenteralSpotRadius);
175 anchor_2.set_x(center_x);
176 anchor_2.set_y(center_y + kCenteralSpotRadius);
177 direction = (mouse_movement_.x() < 0) ? LEFT : RIGHT;
178 if (direction == LEFT)
179 anchor_1.swap(anchor_2);
180 } else {
181 anchor_1.set_x(center_x + kCenteralSpotRadius);
182 anchor_1.set_y(center_y);
183 anchor_2.set_x(center_x - kCenteralSpotRadius);
184 anchor_2.set_y(center_y);
185 direction = (mouse_movement_.y() < 0) ? UP : DOWN;
186 if (direction == UP)
187 anchor_1.swap(anchor_2);
190 uint32_t foreground_color = mouse_locked_ ? kLockedForegroundColor :
191 kUnlockedForegroundColor;
192 for (int y = 0; y < image.size().height(); ++y) {
193 for (int x = 0; x < image.size().width(); ++x) {
194 if (GetDistance(x, y, center_x, center_y) < kCenteralSpotRadius) {
195 *image.GetAddr32(pp::Point(x, y)) = foreground_color;
196 continue;
198 if (draw_needle) {
199 bool within_bound_1 =
200 ((y - anchor_1.y()) * (vertex.x() - anchor_1.x())) >
201 ((vertex.y() - anchor_1.y()) * (x - anchor_1.x()));
202 bool within_bound_2 =
203 ((y - anchor_2.y()) * (vertex.x() - anchor_2.x())) <
204 ((vertex.y() - anchor_2.y()) * (x - anchor_2.x()));
205 bool within_bound_3 =
206 (direction == UP && y < center_y) ||
207 (direction == DOWN && y > center_y) ||
208 (direction == LEFT && x < center_x) ||
209 (direction == RIGHT && x > center_x);
211 if (within_bound_1 && within_bound_2 && within_bound_3) {
212 *image.GetAddr32(pp::Point(x, y)) = foreground_color;
213 continue;
216 *image.GetAddr32(pp::Point(x, y)) = kBackgroundColor;
220 return image;
223 double GetDistance(int point_1_x, int point_1_y,
224 int point_2_x, int point_2_y) {
225 return sqrt(pow(static_cast<double>(point_1_x - point_2_x), 2) +
226 pow(static_cast<double>(point_1_y - point_2_y), 2));
229 void Log(PP_LogLevel level, const char* format, ...) {
230 va_list args;
231 va_start(args, format);
232 char buf[512];
233 vsnprintf(buf, sizeof(buf) - 1, format, args);
234 buf[sizeof(buf) - 1] = '\0';
235 va_end(args);
237 pp::Var value(buf);
238 console_->Log(pp_instance(), level, value.pp_var());
241 int width_;
242 int height_;
244 bool mouse_locked_;
245 pp::Point mouse_movement_;
247 bool pending_paint_;
248 bool waiting_for_flush_completion_;
250 pp::CompletionCallbackFactory<MyInstance> callback_factory_;
252 const PPB_Console* console_;
254 pp::FlashFullscreen flash_fullscreen_;
256 pp::Graphics2D device_context_;
259 // This object is the global object representing this plugin library as long
260 // as it is loaded.
261 class MyModule : public pp::Module {
262 public:
263 MyModule() : pp::Module() {}
264 virtual ~MyModule() {}
266 // Override CreateInstance to create your customized Instance object.
267 virtual pp::Instance* CreateInstance(PP_Instance instance) {
268 return new MyInstance(instance);
272 namespace pp {
274 // Factory function for your specialization of the Module object.
275 Module* CreateModule() {
276 return new MyModule();
279 } // namespace pp