OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 <stdarg.h> |
| 7 #include <stdio.h> |
| 8 |
| 9 #include "ppapi/c/dev/ppb_console_dev.h" |
| 10 #include "ppapi/c/ppb_input_event.h" |
| 11 #include "ppapi/cpp/completion_callback.h" |
| 12 #include "ppapi/cpp/dev/mouse_lock_dev.h" |
| 13 #include "ppapi/cpp/graphics_2d.h" |
| 14 #include "ppapi/cpp/image_data.h" |
| 15 #include "ppapi/cpp/input_event.h" |
| 16 #include "ppapi/cpp/instance.h" |
| 17 #include "ppapi/cpp/logging.h" |
| 18 #include "ppapi/cpp/module.h" |
| 19 #include "ppapi/cpp/rect.h" |
| 20 #include "ppapi/cpp/var.h" |
| 21 |
| 22 class MyInstance : public pp::Instance, public pp::MouseLock_Dev { |
| 23 public: |
| 24 explicit MyInstance(PP_Instance instance) |
| 25 : pp::Instance(instance), |
| 26 pp::MouseLock_Dev(this), |
| 27 width_(0), |
| 28 height_(0), |
| 29 mouse_locked_(false), |
| 30 pending_paint_(false), |
| 31 waiting_for_flush_completion_(false), |
| 32 callback_factory_(this), |
| 33 console_(NULL) { |
| 34 } |
| 35 virtual ~MyInstance() {} |
| 36 |
| 37 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { |
| 38 console_ = reinterpret_cast<const PPB_Console_Dev*>( |
| 39 pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_DEV_INTERFACE)); |
| 40 if (!console_) |
| 41 return false; |
| 42 |
| 43 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | |
| 44 PP_INPUTEVENT_CLASS_KEYBOARD); |
| 45 return true; |
| 46 } |
| 47 |
| 48 virtual bool HandleInputEvent(const pp::InputEvent& event) { |
| 49 switch (event.GetType()) { |
| 50 case PP_INPUTEVENT_TYPE_MOUSEDOWN: { |
| 51 pp::MouseInputEvent mouse_event(event); |
| 52 if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT && |
| 53 !mouse_locked_) { |
| 54 LockMouse( |
| 55 callback_factory_.NewRequiredCallback(&MyInstance::DidLockMouse)); |
| 56 } else if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT && |
| 57 mouse_locked_) { |
| 58 UnlockMouse(); |
| 59 } |
| 60 return true; |
| 61 } |
| 62 case PP_INPUTEVENT_TYPE_MOUSEMOVE: { |
| 63 pp::MouseInputEvent mouse_event(event); |
| 64 mouse_movement_ = mouse_event.GetMovement(); |
| 65 static unsigned int i = 0; |
| 66 Log(PP_LOGLEVEL_LOG, "[%d] movementX: %d; movementY: %d\n", i++, |
| 67 mouse_movement_.x(), mouse_movement_.y()); |
| 68 Paint(); |
| 69 return true; |
| 70 } |
| 71 case PP_INPUTEVENT_TYPE_KEYDOWN: { |
| 72 pp::KeyboardInputEvent key_event(event); |
| 73 // Lock the mouse when the Enter key is pressed. |
| 74 if (!mouse_locked_ && key_event.GetKeyCode() == 13) { |
| 75 LockMouse( |
| 76 callback_factory_.NewRequiredCallback(&MyInstance::DidLockMouse)); |
| 77 } |
| 78 return true; |
| 79 } |
| 80 default: |
| 81 return false; |
| 82 } |
| 83 } |
| 84 |
| 85 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { |
| 86 if (position.size().width() == width_ && |
| 87 position.size().height() == height_) |
| 88 return; // We don't care about the position, only the size. |
| 89 |
| 90 width_ = position.size().width(); |
| 91 height_ = position.size().height(); |
| 92 |
| 93 device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), false); |
| 94 if (!BindGraphics(device_context_)) |
| 95 return; |
| 96 |
| 97 Paint(); |
| 98 } |
| 99 |
| 100 virtual void MouseLockLost() { |
| 101 if (mouse_locked_) { |
| 102 mouse_locked_ = false; |
| 103 Paint(); |
| 104 } else { |
| 105 PP_NOTREACHED(); |
| 106 } |
| 107 } |
| 108 |
| 109 private: |
| 110 void DidLockMouse(int32_t result) { |
| 111 mouse_locked_ = result == PP_OK; |
| 112 mouse_movement_.set_x(0); |
| 113 mouse_movement_.set_y(0); |
| 114 Paint(); |
| 115 } |
| 116 |
| 117 void DidFlush(int32_t result) { |
| 118 waiting_for_flush_completion_ = false; |
| 119 if (pending_paint_) { |
| 120 pending_paint_ = false; |
| 121 Paint(); |
| 122 } |
| 123 } |
| 124 |
| 125 void Paint() { |
| 126 if (waiting_for_flush_completion_) { |
| 127 pending_paint_ = true; |
| 128 return; |
| 129 } |
| 130 |
| 131 pp::ImageData image = PaintImage(width_, height_); |
| 132 if (!image.is_null()) { |
| 133 device_context_.ReplaceContents(&image); |
| 134 waiting_for_flush_completion_ = true; |
| 135 device_context_.Flush( |
| 136 callback_factory_.NewRequiredCallback(&MyInstance::DidFlush)); |
| 137 } |
| 138 } |
| 139 |
| 140 pp::ImageData PaintImage(int width, int height) { |
| 141 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, |
| 142 pp::Size(width, height), false); |
| 143 if (image.is_null()) |
| 144 return image; |
| 145 |
| 146 const static int kCenteralSpotRadius = 5; |
| 147 const static uint32_t kBackgroundColor = 0xfff0f0f0; |
| 148 const static uint32_t kLockedForegroundColor = 0xfff08080; |
| 149 const static uint32_t kUnlockedForegroundColor = 0xff80f080; |
| 150 |
| 151 int center_x = width / 2; |
| 152 int center_y = height / 2; |
| 153 pp::Point vertex(mouse_movement_.x() + center_x, |
| 154 mouse_movement_.y() + center_y); |
| 155 pp::Point anchor_1; |
| 156 pp::Point anchor_2; |
| 157 enum { |
| 158 LEFT = 0, |
| 159 RIGHT = 1, |
| 160 UP = 2, |
| 161 DOWN = 3 |
| 162 } direction; |
| 163 bool draw_needle = GetDistance(mouse_movement_.x(), mouse_movement_.y(), |
| 164 0, 0) > kCenteralSpotRadius; |
| 165 if (draw_needle) { |
| 166 if (abs(mouse_movement_.x()) >= abs(mouse_movement_.y())) { |
| 167 anchor_1.set_x(center_x); |
| 168 anchor_1.set_y(center_y - kCenteralSpotRadius); |
| 169 anchor_2.set_x(center_x); |
| 170 anchor_2.set_y(center_y + kCenteralSpotRadius); |
| 171 direction = (mouse_movement_.x() < 0) ? LEFT : RIGHT; |
| 172 if (direction == LEFT) |
| 173 anchor_1.swap(anchor_2); |
| 174 } else { |
| 175 anchor_1.set_x(center_x + kCenteralSpotRadius); |
| 176 anchor_1.set_y(center_y); |
| 177 anchor_2.set_x(center_x - kCenteralSpotRadius); |
| 178 anchor_2.set_y(center_y); |
| 179 direction = (mouse_movement_.y() < 0) ? UP : DOWN; |
| 180 if (direction == UP) |
| 181 anchor_1.swap(anchor_2); |
| 182 } |
| 183 } |
| 184 uint32_t foreground_color = mouse_locked_ ? kLockedForegroundColor : |
| 185 kUnlockedForegroundColor; |
| 186 for (int y = 0; y < image.size().height(); ++y) { |
| 187 for (int x = 0; x < image.size().width(); ++x) { |
| 188 if (GetDistance(x, y, center_x, center_y) < kCenteralSpotRadius) { |
| 189 *image.GetAddr32(pp::Point(x, y)) = foreground_color; |
| 190 continue; |
| 191 } |
| 192 if (draw_needle) { |
| 193 bool within_bound_1 = |
| 194 ((y - anchor_1.y()) * (vertex.x() - anchor_1.x())) > |
| 195 ((vertex.y() - anchor_1.y()) * (x - anchor_1.x())); |
| 196 bool within_bound_2 = |
| 197 ((y - anchor_2.y()) * (vertex.x() - anchor_2.x())) < |
| 198 ((vertex.y() - anchor_2.y()) * (x - anchor_2.x())); |
| 199 bool within_bound_3 = |
| 200 (direction == UP && y < center_y) || |
| 201 (direction == DOWN && y > center_y) || |
| 202 (direction == LEFT && x < center_x) || |
| 203 (direction == RIGHT && x > center_y); |
| 204 |
| 205 if (within_bound_1 && within_bound_2 && within_bound_3) { |
| 206 *image.GetAddr32(pp::Point(x, y)) = foreground_color; |
| 207 continue; |
| 208 } |
| 209 } |
| 210 *image.GetAddr32(pp::Point(x, y)) = kBackgroundColor; |
| 211 } |
| 212 } |
| 213 |
| 214 return image; |
| 215 } |
| 216 |
| 217 double GetDistance(int point_1_x, int point_1_y, |
| 218 int point_2_x, int point_2_y) { |
| 219 return sqrt(pow(static_cast<double>(point_1_x - point_2_x), 2) + |
| 220 pow(static_cast<double>(point_1_y - point_2_y), 2)); |
| 221 } |
| 222 |
| 223 void Log(PP_LogLevel_Dev level, const char* format, ...) { |
| 224 va_list args; |
| 225 va_start(args, format); |
| 226 char buf[512]; |
| 227 vsnprintf(buf, sizeof(buf) - 1, format, args); |
| 228 buf[sizeof(buf) - 1] = '\0'; |
| 229 va_end(args); |
| 230 |
| 231 pp::Var value(buf); |
| 232 console_->Log(pp_instance(), level, value.pp_var()); |
| 233 } |
| 234 |
| 235 int width_; |
| 236 int height_; |
| 237 |
| 238 bool mouse_locked_; |
| 239 pp::Point mouse_movement_; |
| 240 |
| 241 bool pending_paint_; |
| 242 bool waiting_for_flush_completion_; |
| 243 |
| 244 pp::CompletionCallbackFactory<MyInstance> callback_factory_; |
| 245 |
| 246 const PPB_Console_Dev* console_; |
| 247 |
| 248 pp::Graphics2D device_context_; |
| 249 }; |
| 250 |
| 251 // This object is the global object representing this plugin library as long |
| 252 // as it is loaded. |
| 253 class MyModule : public pp::Module { |
| 254 public: |
| 255 MyModule() : pp::Module() {} |
| 256 virtual ~MyModule() {} |
| 257 |
| 258 // Override CreateInstance to create your customized Instance object. |
| 259 virtual pp::Instance* CreateInstance(PP_Instance instance) { |
| 260 return new MyInstance(instance); |
| 261 } |
| 262 }; |
| 263 |
| 264 namespace pp { |
| 265 |
| 266 // Factory function for your specialization of the Module object. |
| 267 Module* CreateModule() { |
| 268 return new MyModule(); |
| 269 } |
| 270 |
| 271 } // namespace pp |
| 272 |
OLD | NEW |