| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include <cmath> | |
| 6 #include <cstdlib> | |
| 7 #include <stdarg.h> | |
| 8 #include <stdio.h> | |
| 9 #include <string.h> | |
| 10 | |
| 11 #include <algorithm> | |
| 12 | |
| 13 #include "mouselock.h" | |
| 14 | |
| 15 #ifdef WIN32 | |
| 16 #undef min | |
| 17 #undef max | |
| 18 #undef PostMessage | |
| 19 #endif | |
| 20 | |
| 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; | |
| 30 | |
| 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 | |
| 37 | |
| 38 namespace mouselock { | |
| 39 | |
| 40 MouseLockInstance::~MouseLockInstance() { | |
| 41 free(background_scanline_); | |
| 42 background_scanline_ = NULL; | |
| 43 } | |
| 44 | |
| 45 bool MouseLockInstance::Init(uint32_t argc, | |
| 46 const char* argn[], | |
| 47 const char* argv[]) { | |
| 48 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_KEYBOARD); | |
| 49 return true; | |
| 50 } | |
| 51 | |
| 52 bool MouseLockInstance::HandleInputEvent(const pp::InputEvent& event) { | |
| 53 switch (event.GetType()) { | |
| 54 case PP_INPUTEVENT_TYPE_MOUSEDOWN: { | |
| 55 if (mouse_locked_) { | |
| 56 UnlockMouse(); | |
| 57 } else { | |
| 58 LockMouse( | |
| 59 callback_factory_.NewCallback(&MouseLockInstance::DidLockMouse)); | |
| 60 } | |
| 61 return true; | |
| 62 } | |
| 63 | |
| 64 case PP_INPUTEVENT_TYPE_MOUSEMOVE: { | |
| 65 pp::MouseInputEvent mouse_event(event); | |
| 66 mouse_movement_ = mouse_event.GetMovement(); | |
| 67 Paint(); | |
| 68 return true; | |
| 69 } | |
| 70 | |
| 71 case PP_INPUTEVENT_TYPE_KEYDOWN: { | |
| 72 pp::KeyboardInputEvent key_event(event); | |
| 73 | |
| 74 // Switch in and out of fullscreen when 'Enter' is hit | |
| 75 if (key_event.GetKeyCode() == kReturnKeyCode) { | |
| 76 // Ignore switch if in transition | |
| 77 if (!is_context_bound_) | |
| 78 return true; | |
| 79 | |
| 80 if (fullscreen_.IsFullscreen()) { | |
| 81 if (!fullscreen_.SetFullscreen(false)) { | |
| 82 Log("Could not leave fullscreen mode\n"); | |
| 83 } else { | |
| 84 is_context_bound_ = false; | |
| 85 } | |
| 86 } else { | |
| 87 if (!fullscreen_.SetFullscreen(true)) { | |
| 88 Log("Could not enter fullscreen mode\n"); | |
| 89 } else { | |
| 90 is_context_bound_ = false; | |
| 91 } | |
| 92 } | |
| 93 } | |
| 94 return true; | |
| 95 } | |
| 96 | |
| 97 case PP_INPUTEVENT_TYPE_MOUSEUP: | |
| 98 case PP_INPUTEVENT_TYPE_MOUSEENTER: | |
| 99 case PP_INPUTEVENT_TYPE_MOUSELEAVE: | |
| 100 case PP_INPUTEVENT_TYPE_WHEEL: | |
| 101 case PP_INPUTEVENT_TYPE_RAWKEYDOWN: | |
| 102 case PP_INPUTEVENT_TYPE_KEYUP: | |
| 103 case PP_INPUTEVENT_TYPE_CHAR: | |
| 104 case PP_INPUTEVENT_TYPE_CONTEXTMENU: | |
| 105 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: | |
| 106 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: | |
| 107 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: | |
| 108 case PP_INPUTEVENT_TYPE_IME_TEXT: | |
| 109 case PP_INPUTEVENT_TYPE_UNDEFINED: | |
| 110 case PP_INPUTEVENT_TYPE_TOUCHSTART: | |
| 111 case PP_INPUTEVENT_TYPE_TOUCHMOVE: | |
| 112 case PP_INPUTEVENT_TYPE_TOUCHEND: | |
| 113 case PP_INPUTEVENT_TYPE_TOUCHCANCEL: | |
| 114 default: | |
| 115 return false; | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 void MouseLockInstance::DidChangeView(const pp::View& view) { | |
| 120 // DidChangeView can get called for many reasons, so we only want to | |
| 121 // rebuild the device context if we really need to. | |
| 122 | |
| 123 if ((size_ == view.GetRect().size()) && | |
| 124 (was_fullscreen_ == view.IsFullscreen()) && is_context_bound_) { | |
| 125 Log("DidChangeView SKIP %d,%d FULL=%s CTX Bound=%s", | |
| 126 view.GetRect().width(), | |
| 127 view.GetRect().height(), | |
| 128 view.IsFullscreen() ? "true" : "false", | |
| 129 is_context_bound_ ? "true" : "false"); | |
| 130 return; | |
| 131 } | |
| 132 | |
| 133 Log("DidChangeView DO %d,%d FULL=%s CTX Bound=%s", | |
| 134 view.GetRect().width(), | |
| 135 view.GetRect().height(), | |
| 136 view.IsFullscreen() ? "true" : "false", | |
| 137 is_context_bound_ ? "true" : "false"); | |
| 138 | |
| 139 size_ = view.GetRect().size(); | |
| 140 device_context_ = pp::Graphics2D(this, size_, false); | |
| 141 waiting_for_flush_completion_ = false; | |
| 142 | |
| 143 is_context_bound_ = BindGraphics(device_context_); | |
| 144 if (!is_context_bound_) { | |
| 145 Log("Could not bind to 2D context\n."); | |
| 146 return; | |
| 147 } else { | |
| 148 Log("Bound to 2D context size %d,%d.\n", size_.width(), size_.height()); | |
| 149 } | |
| 150 | |
| 151 // Create a scanline for fill. | |
| 152 delete[] background_scanline_; | |
| 153 background_scanline_ = new uint32_t[size_.width()]; | |
| 154 uint32_t* bg_pixel = background_scanline_; | |
| 155 for (int x = 0; x < size_.width(); ++x) { | |
| 156 *bg_pixel++ = kBackgroundColor; | |
| 157 } | |
| 158 | |
| 159 // Remember if we are fullscreen or not | |
| 160 was_fullscreen_ = view.IsFullscreen(); | |
| 161 | |
| 162 // Paint this context | |
| 163 Paint(); | |
| 164 } | |
| 165 | |
| 166 void MouseLockInstance::MouseLockLost() { | |
| 167 if (mouse_locked_) { | |
| 168 Log("Mouselock unlocked.\n"); | |
| 169 mouse_locked_ = false; | |
| 170 Paint(); | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 void MouseLockInstance::DidLockMouse(int32_t result) { | |
| 175 mouse_locked_ = result == PP_OK; | |
| 176 if (result != PP_OK) { | |
| 177 Log("Mouselock failed with failed with error number %d.\n", result); | |
| 178 } | |
| 179 mouse_movement_.set_x(0); | |
| 180 mouse_movement_.set_y(0); | |
| 181 Paint(); | |
| 182 } | |
| 183 | |
| 184 void MouseLockInstance::DidFlush(int32_t result) { | |
| 185 if (result != 0) | |
| 186 Log("Flushed failed with error number %d.\n", result); | |
| 187 waiting_for_flush_completion_ = false; | |
| 188 } | |
| 189 | |
| 190 void MouseLockInstance::Paint() { | |
| 191 // If we are already waiting to paint... | |
| 192 if (waiting_for_flush_completion_) { | |
| 193 return; | |
| 194 } | |
| 195 | |
| 196 pp::ImageData image = PaintImage(size_); | |
| 197 if (image.is_null()) { | |
| 198 Log("Could not create image data\n"); | |
| 199 return; | |
| 200 } | |
| 201 | |
| 202 device_context_.ReplaceContents(&image); | |
| 203 waiting_for_flush_completion_ = true; | |
| 204 device_context_.Flush( | |
| 205 callback_factory_.NewCallback(&MouseLockInstance::DidFlush)); | |
| 206 } | |
| 207 | |
| 208 pp::ImageData MouseLockInstance::PaintImage(const pp::Size& size) { | |
| 209 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false); | |
| 210 if (image.is_null() || image.data() == NULL) { | |
| 211 Log("Skipping image.\n"); | |
| 212 return image; | |
| 213 } | |
| 214 | |
| 215 ClearToBackground(&image); | |
| 216 | |
| 217 DrawCenterSpot(&image, kForegroundColor); | |
| 218 DrawNeedle(&image, kForegroundColor); | |
| 219 return image; | |
| 220 } | |
| 221 | |
| 222 void MouseLockInstance::ClearToBackground(pp::ImageData* image) { | |
| 223 if (image == NULL) { | |
| 224 Log("ClearToBackground with NULL image."); | |
| 225 return; | |
| 226 } | |
| 227 if (background_scanline_ == NULL) { | |
| 228 Log("ClearToBackground with no scanline."); | |
| 229 return; | |
| 230 } | |
| 231 int image_height = image->size().height(); | |
| 232 int image_width = image->size().width(); | |
| 233 | |
| 234 for (int y = 0; y < image_height; ++y) { | |
| 235 uint32_t* scanline = image->GetAddr32(pp::Point(0, y)); | |
| 236 memcpy(scanline, | |
| 237 background_scanline_, | |
| 238 image_width * sizeof(*background_scanline_)); | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 void MouseLockInstance::DrawCenterSpot(pp::ImageData* image, | |
| 243 uint32_t spot_color) { | |
| 244 if (image == NULL) { | |
| 245 Log("DrawCenterSpot with NULL image"); | |
| 246 return; | |
| 247 } | |
| 248 // Draw the center spot. The ROI is bounded by the size of the spot, plus | |
| 249 // one pixel. | |
| 250 int center_x = image->size().width() / 2; | |
| 251 int center_y = image->size().height() / 2; | |
| 252 int region_of_interest_radius = kCentralSpotRadius + 1; | |
| 253 | |
| 254 pp::Point left_top(std::max(0, center_x - region_of_interest_radius), | |
| 255 std::max(0, center_y - region_of_interest_radius)); | |
| 256 pp::Point right_bottom( | |
| 257 std::min(image->size().width(), center_x + region_of_interest_radius), | |
| 258 std::min(image->size().height(), 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; | |
| 263 } | |
| 264 } | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 void MouseLockInstance::DrawNeedle(pp::ImageData* image, | |
| 269 uint32_t needle_color) { | |
| 270 if (image == NULL) { | |
| 271 Log("DrawNeedle with NULL image"); | |
| 272 return; | |
| 273 } | |
| 274 if (GetDistance(mouse_movement_.x(), mouse_movement_.y(), 0, 0) <= | |
| 275 kCentralSpotRadius) { | |
| 276 return; | |
| 277 } | |
| 278 | |
| 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; | |
| 288 | |
| 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); | |
| 305 } | |
| 306 | |
| 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( | |
| 310 std::min(image->size().width(), center_x + abs_mouse_x), | |
| 311 std::min(image->size().height(), center_y + abs_mouse_y)); | |
| 312 for (int y = left_top.y(); y < right_bottom.y(); ++y) { | |
| 313 for (int x = left_top.x(); x < right_bottom.x(); ++x) { | |
| 314 bool within_bound_1 = ((y - anchor_1.y()) * (vertex.x() - anchor_1.x())) > | |
| 315 ((vertex.y() - anchor_1.y()) * (x - anchor_1.x())); | |
| 316 bool within_bound_2 = ((y - anchor_2.y()) * (vertex.x() - anchor_2.x())) < | |
| 317 ((vertex.y() - anchor_2.y()) * (x - anchor_2.x())); | |
| 318 bool within_bound_3 = (direction == kUp && y < center_y) || | |
| 319 (direction == kDown && y > center_y) || | |
| 320 (direction == kLeft && x < center_x) || | |
| 321 (direction == kRight && x > center_x); | |
| 322 | |
| 323 if (within_bound_1 && within_bound_2 && within_bound_3) { | |
| 324 *image->GetAddr32(pp::Point(x, y)) = needle_color; | |
| 325 } | |
| 326 } | |
| 327 } | |
| 328 } | |
| 329 | |
| 330 void MouseLockInstance::Log(const char* format, ...) { | |
| 331 static PPB_Console* console = | |
| 332 (PPB_Console*)pp::Module::Get()->GetBrowserInterface( | |
| 333 PPB_CONSOLE_INTERFACE); | |
| 334 | |
| 335 if (NULL == console) | |
| 336 return; | |
| 337 va_list args; | |
| 338 va_start(args, format); | |
| 339 char buf[512]; | |
| 340 vsnprintf(buf, sizeof(buf) - 1, format, args); | |
| 341 buf[sizeof(buf) - 1] = '\0'; | |
| 342 va_end(args); | |
| 343 | |
| 344 pp::Var value(buf); | |
| 345 console->Log(pp_instance(), PP_LOGLEVEL_ERROR, value.pp_var()); | |
| 346 } | |
| 347 | |
| 348 } // namespace mouselock | |
| 349 | |
| 350 // This object is the global object representing this plugin library as long | |
| 351 // as it is loaded. | |
| 352 class MouseLockModule : public pp::Module { | |
| 353 public: | |
| 354 MouseLockModule() : pp::Module() {} | |
| 355 virtual ~MouseLockModule() {} | |
| 356 | |
| 357 // Override CreateInstance to create your customized Instance object. | |
| 358 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
| 359 return new mouselock::MouseLockInstance(instance); | |
| 360 } | |
| 361 }; | |
| 362 | |
| 363 namespace pp { | |
| 364 | |
| 365 // Factory function for your specialization of the Module object. | |
| 366 Module* CreateModule() { return new MouseLockModule(); } | |
| 367 | |
| 368 } // namespace pp | |
| OLD | NEW |