15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include <cmath>
9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include <cstdlib>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "mouse_lock.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WIN32
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef min
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef max
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef PostMessage
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Indicate the direction of the mouse location relative to the center of the
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// view.  These values are used to determine which 2D quadrant the needle lies
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef enum {
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kLeft = 0,
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kRight = 1,
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kUp = 2,
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kDown = 3
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} MouseDirection;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCentralSpotRadius = 5;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32_t kReturnKeyCode = 13;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32_t kBackgroundColor = 0xff606060;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const uint32_t kForegroundColor = 0xfff08080;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseLockInstance::~MouseLockInstance() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  free(background_scanline_);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background_scanline_ = NULL;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MouseLockInstance::Init(uint32_t argc,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const char* argn[],
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const char* argv[]) {
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_KEYBOARD);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MouseLockInstance::HandleInputEvent(const pp::InputEvent& event) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (event.GetType()) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (mouse_locked_) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        UnlockMouse();
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LockMouse(
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            callback_factory_.NewCallback(&MouseLockInstance::DidLockMouse));
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pp::MouseInputEvent mouse_event(event);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mouse_movement_ = mouse_event.GetMovement();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Paint();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_KEYDOWN: {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pp::KeyboardInputEvent key_event(event);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Switch in and out of fullscreen when 'Enter' is hit
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (key_event.GetKeyCode() == kReturnKeyCode) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Ignore switch if in transition
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (!is_context_bound_)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return true;
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (fullscreen_.IsFullscreen()) {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (!fullscreen_.SetFullscreen(false)) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log("Could not leave fullscreen mode\n");
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          } else {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            is_context_bound_ = false;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (!fullscreen_.SetFullscreen(true)) {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log("Could not enter fullscreen mode\n");
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          } else {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            is_context_bound_ = false;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEUP:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEENTER:
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSELEAVE:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_WHEEL:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_KEYUP:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_CHAR:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_CONTEXTMENU:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_IME_TEXT:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_UNDEFINED:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_TOUCHSTART:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_TOUCHMOVE:
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_TOUCHEND:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::DidChangeView(const pp::View& view) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DidChangeView can get called for many reasons, so we only want to
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // rebuild the device context if we really need to.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((size_ == view.GetRect().size()) &&
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (was_fullscreen_ == view.IsFullscreen()) && is_context_bound_) {
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Log("DidChangeView SKIP %d,%d FULL=%s CTX Bound=%s",
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        view.GetRect().width(),
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        view.GetRect().height(),
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        view.IsFullscreen() ? "true" : "false",
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        is_context_bound_ ? "true" : "false");
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Log("DidChangeView DO %d,%d FULL=%s CTX Bound=%s",
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      view.GetRect().width(),
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      view.GetRect().height(),
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      view.IsFullscreen() ? "true" : "false",
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      is_context_bound_ ? "true" : "false");
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_ = view.GetRect().size();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  device_context_ = pp::Graphics2D(this, size_, false);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_for_flush_completion_ = false;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_context_bound_ = BindGraphics(device_context_);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_context_bound_) {
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Log("Could not bind to 2D context\n.");
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Log("Bound to 2D context size %d,%d.\n", size_.width(), size_.height());
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a scanline for fill.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete[] background_scanline_;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background_scanline_ = new uint32_t[size_.width()];
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t* bg_pixel = background_scanline_;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int x = 0; x < size_.width(); ++x) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *bg_pixel++ = kBackgroundColor;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Remember if we are fullscreen or not
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  was_fullscreen_ = view.IsFullscreen();
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Paint this context
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Paint();
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::MouseLockLost() {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mouse_locked_) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Log("Mouselock unlocked.\n");
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mouse_locked_ = false;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Paint();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::DidLockMouse(int32_t result) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_locked_ = result == PP_OK;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result != PP_OK) {
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Log("Mouselock failed with failed with error number %d.\n", result);
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_movement_.set_x(0);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mouse_movement_.set_y(0);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Paint();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::DidFlush(int32_t result) {
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (result != 0)
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Log("Flushed failed with error number %d.\n", result);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_for_flush_completion_ = false;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::Paint() {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If we are already waiting to paint...
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (waiting_for_flush_completion_) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData image = PaintImage(size_);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image.is_null()) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Log("Could not create image data\n");
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  device_context_.ReplaceContents(&image);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_for_flush_completion_ = true;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  device_context_.Flush(
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_factory_.NewCallback(&MouseLockInstance::DidFlush));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pp::ImageData MouseLockInstance::PaintImage(const pp::Size& size) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (image.is_null() || image.data() == NULL) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Log("Skipping image.\n");
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return image;
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearToBackground(&image);
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DrawCenterSpot(&image, kForegroundColor);
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DrawNeedle(&image, kForegroundColor);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return image;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::ClearToBackground(pp::ImageData* image) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image == NULL) {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Log("ClearToBackground with NULL image.");
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (background_scanline_ == NULL) {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Log("ClearToBackground with no scanline.");
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int image_height = image->size().height();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int image_width = image->size().width();
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = 0; y < image_height; ++y) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t* scanline = image->GetAddr32(pp::Point(0, y));
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(scanline,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           background_scanline_,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           image_width * sizeof(*background_scanline_));
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::DrawCenterSpot(pp::ImageData* image,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       uint32_t spot_color) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image == NULL) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Log("DrawCenterSpot with NULL image");
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw the center spot.  The ROI is bounded by the size of the spot, plus
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // one pixel.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int center_x = image->size().width() / 2;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int center_y = image->size().height() / 2;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int region_of_interest_radius = kCentralSpotRadius + 1;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Point left_top(std::max(0, center_x - region_of_interest_radius),
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     std::max(0, center_y - region_of_interest_radius));
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pp::Point right_bottom(
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::min(image->size().width(), center_x + region_of_interest_radius),
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::min(image->size().height(), center_y + region_of_interest_radius));
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = left_top.y(); y < right_bottom.y(); ++y) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int x = left_top.x(); x < right_bottom.x(); ++x) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (GetDistance(x, y, center_x, center_y) < kCentralSpotRadius) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *image->GetAddr32(pp::Point(x, y)) = spot_color;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::DrawNeedle(pp::ImageData* image,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   uint32_t needle_color) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image == NULL) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Log("DrawNeedle with NULL image");
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetDistance(mouse_movement_.x(), mouse_movement_.y(), 0, 0) <=
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kCentralSpotRadius) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int abs_mouse_x = std::abs(mouse_movement_.x());
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int abs_mouse_y = std::abs(mouse_movement_.y());
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int center_x = image->size().width() / 2;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int center_y = image->size().height() / 2;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Point vertex(mouse_movement_.x() + center_x,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   mouse_movement_.y() + center_y);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Point anchor_1;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Point anchor_2;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MouseDirection direction = kLeft;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (abs_mouse_x >= abs_mouse_y) {
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_1.set_x(center_x);
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_1.set_y(center_y - kCentralSpotRadius);
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_2.set_x(center_x);
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_2.set_y(center_y + kCentralSpotRadius);
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    direction = (mouse_movement_.x() < 0) ? kLeft : kRight;
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (direction == kLeft)
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      anchor_1.swap(anchor_2);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_1.set_x(center_x + kCentralSpotRadius);
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_1.set_y(center_y);
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_2.set_x(center_x - kCentralSpotRadius);
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    anchor_2.set_y(center_y);
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    direction = (mouse_movement_.y() < 0) ? kUp : kDown;
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (direction == kUp)
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      anchor_1.swap(anchor_2);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Point left_top(std::max(0, center_x - abs_mouse_x),
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     std::max(0, center_y - abs_mouse_y));
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pp::Point right_bottom(
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::min(image->size().width(), center_x + abs_mouse_x),
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::min(image->size().height(), center_y + abs_mouse_y));
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = left_top.y(); y < right_bottom.y(); ++y) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int x = left_top.x(); x < right_bottom.x(); ++x) {
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool within_bound_1 = ((y - anchor_1.y()) * (vertex.x() - anchor_1.x())) >
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            ((vertex.y() - anchor_1.y()) * (x - anchor_1.x()));
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool within_bound_2 = ((y - anchor_2.y()) * (vertex.x() - anchor_2.x())) <
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            ((vertex.y() - anchor_2.y()) * (x - anchor_2.x()));
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool within_bound_3 = (direction == kUp && y < center_y) ||
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            (direction == kDown && y > center_y) ||
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            (direction == kLeft && x < center_x) ||
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            (direction == kRight && x > center_x);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (within_bound_1 && within_bound_2 && within_bound_3) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *image->GetAddr32(pp::Point(x, y)) = needle_color;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MouseLockInstance::Log(const char* format, ...) {
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static PPB_Console* console =
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (PPB_Console*)pp::Module::Get()->GetBrowserInterface(
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          PPB_CONSOLE_INTERFACE);
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (NULL == console)
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_list args;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_start(args, format);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buf[512];
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  vsnprintf(buf, sizeof(buf) - 1, format, args);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buf[sizeof(buf) - 1] = '\0';
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_end(args);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Var value(buf);
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  console->Log(pp_instance(), PP_LOGLEVEL_ERROR, value.pp_var());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This object is the global object representing this plugin library as long
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// as it is loaded.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MouseLockModule : public pp::Module {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MouseLockModule() : pp::Module() {}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~MouseLockModule() {}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Override CreateInstance to create your customized Instance object.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual pp::Instance* CreateInstance(PP_Instance instance) {
355b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return new MouseLockInstance(instance);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace pp {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Factory function for your specialization of the Module object.
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Module* CreateModule() { return new MouseLockModule(); }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace pp
365