Add Media.AudioRendererEvents histogram to measure how often OnRenderError() is called.
[chromium-blink-merge.git] / native_client_sdk / src / examples / mouselock / mouselock.cc
blob9aefac1396b4f261a1e9ce530dccdf1f88c9cee7
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 <cstdlib>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <string.h>
11 #include <algorithm>
13 #include "mouselock.h"
15 #ifdef WIN32
16 #undef min
17 #undef max
18 #undef PostMessage
19 #endif
21 // Indicate the direction of the mouse location relative to the center of the
22 // view. These values are used to determine which 2D quadrant the needle lies
23 // in.
24 typedef enum {
25 kLeft = 0,
26 kRight = 1,
27 kUp = 2,
28 kDown = 3
29 } MouseDirection;
31 namespace {
32 const int kCentralSpotRadius = 5;
33 const uint32_t kReturnKeyCode = 13;
34 const uint32_t kBackgroundColor = 0xff606060;
35 const uint32_t kForegroundColor = 0xfff08080;
36 } // namespace
38 namespace mouselock {
40 MouseLockInstance::~MouseLockInstance() {
41 free(background_scanline_);
42 background_scanline_ = NULL;
45 bool MouseLockInstance::Init(uint32_t argc,
46 const char* argn[],
47 const char* argv[]) {
48 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE |
49 PP_INPUTEVENT_CLASS_KEYBOARD);
50 return true;
53 bool MouseLockInstance::HandleInputEvent(const pp::InputEvent& event) {
54 switch (event.GetType()) {
55 case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
56 if (mouse_locked_) {
57 UnlockMouse();
58 } else {
59 LockMouse(callback_factory_.NewCallback(
60 &MouseLockInstance::DidLockMouse));
62 return true;
65 case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
66 pp::MouseInputEvent mouse_event(event);
67 mouse_movement_ = mouse_event.GetMovement();
68 Paint();
69 return true;
72 case PP_INPUTEVENT_TYPE_KEYDOWN: {
73 pp::KeyboardInputEvent key_event(event);
75 // Switch in and out of fullscreen when 'Enter' is hit
76 if (key_event.GetKeyCode() == kReturnKeyCode) {
77 // Ignore switch if in transition
78 if (!is_context_bound_)
79 return true;
81 if (fullscreen_.IsFullscreen()) {
82 if (!fullscreen_.SetFullscreen(false)) {
83 Log("Could not leave fullscreen mode\n");
84 } else {
85 is_context_bound_ = false;
87 } else {
88 if (!fullscreen_.SetFullscreen(true)) {
89 Log("Could not enter fullscreen mode\n");
90 } else {
91 is_context_bound_ = false;
95 return true;
98 case PP_INPUTEVENT_TYPE_MOUSEUP:
99 case PP_INPUTEVENT_TYPE_MOUSEENTER:
100 case PP_INPUTEVENT_TYPE_MOUSELEAVE:
101 case PP_INPUTEVENT_TYPE_WHEEL:
102 case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
103 case PP_INPUTEVENT_TYPE_KEYUP:
104 case PP_INPUTEVENT_TYPE_CHAR:
105 case PP_INPUTEVENT_TYPE_CONTEXTMENU:
106 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
107 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
108 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
109 case PP_INPUTEVENT_TYPE_IME_TEXT:
110 case PP_INPUTEVENT_TYPE_UNDEFINED:
111 case PP_INPUTEVENT_TYPE_TOUCHSTART:
112 case PP_INPUTEVENT_TYPE_TOUCHMOVE:
113 case PP_INPUTEVENT_TYPE_TOUCHEND:
114 case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
115 default:
116 return false;
120 void MouseLockInstance::DidChangeView(const pp::View& view) {
121 // DidChangeView can get called for many reasons, so we only want to
122 // rebuild the device context if we really need to.
124 if ((size_ == view.GetRect().size()) &&
125 (was_fullscreen_ == view.IsFullscreen()) && is_context_bound_) {
126 Log("DidChangeView SKIP %d,%d FULL=%s CTX Bound=%s",
127 view.GetRect().width(), view.GetRect().height(),
128 view.IsFullscreen() ? "true" : "false",
129 is_context_bound_ ? "true" : "false");
130 return;
133 Log("DidChangeView DO %d,%d FULL=%s CTX Bound=%s",
134 view.GetRect().width(), view.GetRect().height(),
135 view.IsFullscreen() ? "true" : "false",
136 is_context_bound_ ? "true" : "false");
138 size_ = view.GetRect().size();
139 device_context_ = pp::Graphics2D(this, size_, false);
140 waiting_for_flush_completion_ = false;
142 is_context_bound_ = BindGraphics(device_context_);
143 if (!is_context_bound_) {
144 Log("Could not bind to 2D context\n.");
145 return;
146 } else {
147 Log("Bound to 2D context size %d,%d.\n", size_.width(), size_.height());
150 // Create a scanline for fill.
151 delete[] background_scanline_;
152 background_scanline_ = new uint32_t[size_.width()];
153 uint32_t* bg_pixel = background_scanline_;
154 for (int x = 0; x < size_.width(); ++x) {
155 *bg_pixel++ = kBackgroundColor;
158 // Remember if we are fullscreen or not
159 was_fullscreen_ = view.IsFullscreen();
161 // Paint this context
162 Paint();
165 void MouseLockInstance::MouseLockLost() {
166 if (mouse_locked_) {
167 Log("Mouselock unlocked.\n");
168 mouse_locked_ = false;
169 Paint();
173 void MouseLockInstance::DidLockMouse(int32_t result) {
174 mouse_locked_ = result == PP_OK;
175 if (result != PP_OK) {
176 Log("Mouselock failed with failed with error number %d.\n", result);
178 mouse_movement_.set_x(0);
179 mouse_movement_.set_y(0);
180 Paint();
183 void MouseLockInstance::DidFlush(int32_t result) {
184 if (result != 0) Log("Flushed failed with error number %d.\n", result);
185 waiting_for_flush_completion_ = false;
188 void MouseLockInstance::Paint() {
189 // If we are already waiting to paint...
190 if (waiting_for_flush_completion_) {
191 return;
194 pp::ImageData image = PaintImage(size_);
195 if (image.is_null()) {
196 Log("Could not create image data\n");
197 return;
200 device_context_.ReplaceContents(&image);
201 waiting_for_flush_completion_ = true;
202 device_context_.Flush(
203 callback_factory_.NewCallback(&MouseLockInstance::DidFlush));
207 pp::ImageData MouseLockInstance::PaintImage(const pp::Size& size) {
208 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
209 if (image.is_null() || image.data() == NULL) {
210 Log("Skipping image.\n");
211 return image;
214 ClearToBackground(&image);
216 DrawCenterSpot(&image, kForegroundColor);
217 DrawNeedle(&image, kForegroundColor);
218 return image;
221 void MouseLockInstance::ClearToBackground(pp::ImageData* image) {
222 if (image == NULL) {
223 Log("ClearToBackground with NULL image.");
224 return;
226 if (background_scanline_ == NULL) {
227 Log("ClearToBackground with no scanline.");
228 return;
230 int image_height = image->size().height();
231 int image_width = image->size().width();
233 for (int y = 0; y < image_height; ++y) {
234 uint32_t* scanline = image->GetAddr32(pp::Point(0, y));
235 memcpy(scanline,
236 background_scanline_,
237 image_width * sizeof(*background_scanline_));
241 void MouseLockInstance::DrawCenterSpot(pp::ImageData* image,
242 uint32_t spot_color) {
243 if (image == NULL) {
244 Log("DrawCenterSpot with NULL image");
245 return;
247 // Draw the center spot. The ROI is bounded by the size of the spot, plus
248 // one pixel.
249 int center_x = image->size().width() / 2;
250 int center_y = image->size().height() / 2;
251 int region_of_interest_radius = kCentralSpotRadius + 1;
253 pp::Point left_top(std::max(0, center_x - region_of_interest_radius),
254 std::max(0, center_y - region_of_interest_radius));
255 pp::Point right_bottom(std::min(image->size().width(),
256 center_x + region_of_interest_radius),
257 std::min(image->size().height(),
258 center_y + region_of_interest_radius));
259 for (int y = left_top.y(); y < right_bottom.y(); ++y) {
260 for (int x = left_top.x(); x < right_bottom.x(); ++x) {
261 if (GetDistance(x, y, center_x, center_y) < kCentralSpotRadius) {
262 *image->GetAddr32(pp::Point(x, y)) = spot_color;
268 void MouseLockInstance::DrawNeedle(pp::ImageData* image,
269 uint32_t needle_color) {
270 if (image == NULL) {
271 Log("DrawNeedle with NULL image");
272 return;
274 if (GetDistance(mouse_movement_.x(), mouse_movement_.y(), 0, 0) <=
275 kCentralSpotRadius) {
276 return;
279 int abs_mouse_x = std::abs(mouse_movement_.x());
280 int abs_mouse_y = std::abs(mouse_movement_.y());
281 int center_x = image->size().width() / 2;
282 int center_y = image->size().height() / 2;
283 pp::Point vertex(mouse_movement_.x() + center_x,
284 mouse_movement_.y() + center_y);
285 pp::Point anchor_1;
286 pp::Point anchor_2;
287 MouseDirection direction = kLeft;
289 if (abs_mouse_x >= abs_mouse_y) {
290 anchor_1.set_x(center_x);
291 anchor_1.set_y(center_y - kCentralSpotRadius);
292 anchor_2.set_x(center_x);
293 anchor_2.set_y(center_y + kCentralSpotRadius);
294 direction = (mouse_movement_.x() < 0) ? kLeft : kRight;
295 if (direction == kLeft)
296 anchor_1.swap(anchor_2);
297 } else {
298 anchor_1.set_x(center_x + kCentralSpotRadius);
299 anchor_1.set_y(center_y);
300 anchor_2.set_x(center_x - kCentralSpotRadius);
301 anchor_2.set_y(center_y);
302 direction = (mouse_movement_.y() < 0) ? kUp : kDown;
303 if (direction == kUp)
304 anchor_1.swap(anchor_2);
307 pp::Point left_top(std::max(0, center_x - abs_mouse_x),
308 std::max(0, center_y - abs_mouse_y));
309 pp::Point right_bottom(std::min(image->size().width(),
310 center_x + abs_mouse_x),
311 std::min(image->size().height(),
312 center_y + abs_mouse_y));
313 for (int y = left_top.y(); y < right_bottom.y(); ++y) {
314 for (int x = left_top.x(); x < right_bottom.x(); ++x) {
315 bool within_bound_1 =
316 ((y - anchor_1.y()) * (vertex.x() - anchor_1.x())) >
317 ((vertex.y() - anchor_1.y()) * (x - anchor_1.x()));
318 bool within_bound_2 =
319 ((y - anchor_2.y()) * (vertex.x() - anchor_2.x())) <
320 ((vertex.y() - anchor_2.y()) * (x - anchor_2.x()));
321 bool within_bound_3 =
322 (direction == kUp && y < center_y) ||
323 (direction == kDown && y > center_y) ||
324 (direction == kLeft && x < center_x) ||
325 (direction == kRight && x > center_x);
327 if (within_bound_1 && within_bound_2 && within_bound_3) {
328 *image->GetAddr32(pp::Point(x, y)) = needle_color;
335 void MouseLockInstance::Log(const char* format, ...) {
336 static PPB_Console* console = (PPB_Console*)
337 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE);
339 if (NULL == console) return;
340 va_list args;
341 va_start(args, format);
342 char buf[512];
343 vsnprintf(buf, sizeof(buf) - 1, format, args);
344 buf[sizeof(buf) - 1] = '\0';
345 va_end(args);
347 pp::Var value(buf);
348 console->Log(pp_instance(), PP_LOGLEVEL_ERROR, value.pp_var());
351 } // namespace mouselock
353 // This object is the global object representing this plugin library as long
354 // as it is loaded.
355 class MouseLockModule : public pp::Module {
356 public:
357 MouseLockModule() : pp::Module() {}
358 virtual ~MouseLockModule() {}
360 // Override CreateInstance to create your customized Instance object.
361 virtual pp::Instance* CreateInstance(PP_Instance instance) {
362 return new mouselock::MouseLockInstance(instance);
366 namespace pp {
368 // Factory function for your specialization of the Module object.
369 Module* CreateModule() {
370 return new MouseLockModule();
373 } // namespace pp