2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <Carbon/Carbon.h>
40 #endif // NACL_WINDOWS
41 #if NACL_LINUX && defined(MOZ_X11)
44 #include <X11/Intrinsic.h>
45 #include <X11/keysym.h>
46 #endif // NACL_LINUX && defined(MOZ_X11)
48 #include "native_client/tools/npapi_runtime/nacl_npapi.h"
49 #include "native_client/npapi_plugin/srpc/npapi_native.h"
50 #include "native_client/npapi_plugin/srpc/srpc.h"
51 #include "native_client/npapi_plugin/srpc/video.h"
56 class GlobalVideoMutex
{
60 void Lock() { NaClMutexLock(&mutex_
); }
61 void Unlock() { NaClMutexUnlock(&mutex_
); }
62 GlobalVideoMutex() { NaClMutexCtor(&mutex_
); }
63 ~GlobalVideoMutex() { NaClMutexDtor(&mutex_
); }
66 static GlobalVideoMutex globalVideoMutex
;
68 void VideoGlobalLock() {
69 globalVideoMutex
.Lock();
72 void VideoGlobalUnlock() {
73 globalVideoMutex
.Unlock();
77 #if NACL_LINUX && defined(MOZ_X11)
78 static int XKeysymToNaCl(KeySym xsym
) {
79 if ((xsym
& 0xFF00) == 0x0000)
82 case XK_Alt_L
: return NACL_KEY_LALT
;
83 case XK_Alt_R
: return NACL_KEY_RALT
;
84 case XK_BackSpace
: return NACL_KEY_BACKSPACE
;
85 case XK_Break
: return NACL_KEY_BREAK
;
86 case XK_Caps_Lock
: return NACL_KEY_CAPSLOCK
;
87 case XK_Clear
: return NACL_KEY_CLEAR
;
88 case XK_Control_L
: return NACL_KEY_LCTRL
;
89 case XK_Control_R
: return NACL_KEY_RCTRL
;
90 case XK_Delete
: return NACL_KEY_DELETE
;
91 case XK_Down
: return NACL_KEY_DOWN
;
92 case XK_End
: return NACL_KEY_END
;
93 case XK_Escape
: return NACL_KEY_ESCAPE
;
94 case XK_F1
: return NACL_KEY_F1
;
95 case XK_F2
: return NACL_KEY_F2
;
96 case XK_F3
: return NACL_KEY_F3
;
97 case XK_F4
: return NACL_KEY_F4
;
98 case XK_F5
: return NACL_KEY_F5
;
99 case XK_F6
: return NACL_KEY_F6
;
100 case XK_F7
: return NACL_KEY_F7
;
101 case XK_F8
: return NACL_KEY_F8
;
102 case XK_F9
: return NACL_KEY_F9
;
103 case XK_F10
: return NACL_KEY_F10
;
104 case XK_F11
: return NACL_KEY_F11
;
105 case XK_F12
: return NACL_KEY_F12
;
106 case XK_F13
: return NACL_KEY_F13
;
107 case XK_F14
: return NACL_KEY_F14
;
108 case XK_F15
: return NACL_KEY_F15
;
109 case XK_Help
: return NACL_KEY_HELP
;
110 case XK_Home
: return NACL_KEY_HOME
;
111 case XK_Hyper_R
: return NACL_KEY_MENU
;
112 case XK_Insert
: return NACL_KEY_INSERT
;
113 case XK_KP_0
: return NACL_KEY_KP0
;
114 case XK_KP_1
: return NACL_KEY_KP1
;
115 case XK_KP_2
: return NACL_KEY_KP2
;
116 case XK_KP_3
: return NACL_KEY_KP3
;
117 case XK_KP_4
: return NACL_KEY_KP4
;
118 case XK_KP_5
: return NACL_KEY_KP5
;
119 case XK_KP_6
: return NACL_KEY_KP6
;
120 case XK_KP_7
: return NACL_KEY_KP7
;
121 case XK_KP_8
: return NACL_KEY_KP8
;
122 case XK_KP_9
: return NACL_KEY_KP9
;
123 case XK_KP_Add
: return NACL_KEY_KP_PLUS
;
124 case XK_KP_Begin
: return NACL_KEY_KP5
;
125 case XK_KP_Decimal
: return NACL_KEY_KP_PERIOD
;
126 case XK_KP_Delete
: return NACL_KEY_KP_PERIOD
;
127 case XK_KP_Divide
: return NACL_KEY_KP_DIVIDE
;
128 case XK_KP_Down
: return NACL_KEY_KP2
;
129 case XK_KP_End
: return NACL_KEY_KP1
;
130 case XK_KP_Enter
: return NACL_KEY_KP_ENTER
;
131 case XK_KP_Equal
: return NACL_KEY_KP_EQUALS
;
132 case XK_KP_Home
: return NACL_KEY_KP7
;
133 case XK_KP_Insert
: return NACL_KEY_KP0
;
134 case XK_KP_Left
: return NACL_KEY_KP4
;
135 case XK_KP_Multiply
: return NACL_KEY_KP_MULTIPLY
;
136 case XK_KP_Page_Down
: return NACL_KEY_KP3
;
137 case XK_KP_Page_Up
: return NACL_KEY_KP9
;
138 case XK_KP_Right
: return NACL_KEY_KP6
;
139 case XK_KP_Subtract
: return NACL_KEY_KP_MINUS
;
140 case XK_KP_Up
: return NACL_KEY_KP8
;
141 case XK_Left
: return NACL_KEY_LEFT
;
142 case XK_Num_Lock
: return NACL_KEY_NUMLOCK
;
143 case XK_Menu
: return NACL_KEY_MENU
;
144 case XK_Meta_R
: return NACL_KEY_RMETA
;
145 case XK_Meta_L
: return NACL_KEY_LMETA
;
146 case XK_Mode_switch
: return NACL_KEY_MODE
;
147 case XK_Multi_key
: return NACL_KEY_COMPOSE
;
148 case XK_Page_Down
: return NACL_KEY_PAGEDOWN
;
149 case XK_Page_Up
: return NACL_KEY_PAGEUP
;
150 case XK_Pause
: return NACL_KEY_PAUSE
;
151 case XK_Print
: return NACL_KEY_PRINT
;
152 case XK_Return
: return NACL_KEY_RETURN
;
153 case XK_Right
: return NACL_KEY_RIGHT
;
154 case XK_Scroll_Lock
: return NACL_KEY_SCROLLOCK
;
155 case XK_Shift_R
: return NACL_KEY_RSHIFT
;
156 case XK_Shift_L
: return NACL_KEY_LSHIFT
;
157 case XK_Super_L
: return NACL_KEY_LSUPER
;
158 case XK_Super_R
: return NACL_KEY_RSUPER
;
159 case XK_Sys_Req
: return NACL_KEY_SYSREQ
;
160 case XK_Tab
: return NACL_KEY_TAB
;
161 case XK_Up
: return NACL_KEY_UP
;
163 return NACL_KEY_UNKNOWN
;
166 void VideoMap::RedrawAsync(void *platform_parm
) {
167 dprintf(("VideoMap::RedrawAsync %p\n", platform_parm
));
168 if (0 != untrusted_video_share_
->u
.h
.video_ready
) {
169 Display
*display
= reinterpret_cast<Display
*>(platform_parm
);
170 Drawable window
= reinterpret_cast<Drawable
>(window_
->window
);
171 GC gc
= XCreateGC(display
, window
, 0, NULL
);
173 memset(&image
, 0, sizeof image
);
174 image
.format
= ZPixmap
;
175 image
.data
= reinterpret_cast<char*>
176 (&untrusted_video_share_
->video_pixels
[0]);
177 image
.width
= window_
->width
;
178 image
.height
= window_
->height
;
180 image
.byte_order
= LSBFirst
;
181 image
.bitmap_bit_order
= MSBFirst
;
182 image
.bits_per_pixel
= 32;
183 image
.bytes_per_line
= 4 * window_
->width
;
184 image
.bitmap_unit
= 32;
185 image
.bitmap_pad
= 32;
187 XPutImage(display
, window
, gc
, &image
, 0, 0, 0, 0,
188 window_
->width
, window_
->height
);
189 XFreeGC(display
, gc
);
195 void VideoMap::Redraw() {
197 static_cast<NPSetWindowCallbackStruct
*>(window_
->ws_info
)->display
;
198 this->RedrawAsync(reinterpret_cast<void *>(display
));
201 void VideoMap::XEventHandler(Widget widget
,
205 VideoScopedGlobalLock video_lock
;
206 if ((NULL
== video
) || (NULL
== video
->window_
) ||
207 (NULL
== video
->untrusted_video_share_
))
209 Window xwin
= reinterpret_cast<Window
>(video
->window_
->window
);
210 NPSetWindowCallbackStruct
* wcbs
=
211 reinterpret_cast<NPSetWindowCallbackStruct
*>(video
->window_
->ws_info
);
212 Display
* dpy
= wcbs
->display
;
213 union NaClMultimediaEvent nacl_event
;
220 switch (xevent
->type
) {
222 // Exposure events come in multiples, one per rectangle uncovered.
223 // We just look at one and redraw the whole region.
224 while (XCheckTypedWindowEvent(dpy
, xwin
, Expose
, xevent
));
228 nacl_event
.type
= NACL_EVENT_KEY_DOWN
;
229 nacl_event
.key
.which
= 0;
230 nacl_event
.key
.state
= kSet
;
231 nacl_event
.key
.keysym
.scancode
= xevent
->xkey
.keycode
;
232 xsym
= XKeycodeToKeysym(dpy
, xevent
->xkey
.keycode
, 0);
233 nsym
= XKeysymToNaCl(xsym
);
234 video
->SetKeyMod(nsym
, kSet
);
235 nacl_event
.key
.keysym
.sym
= nsym
;
236 nacl_event
.key
.keysym
.mod
= video
->event_state_key_mod_
;
237 nacl_event
.key
.keysym
.unicode
= 0;
238 video
->EventQueuePut(&nacl_event
);
241 nacl_event
.type
= NACL_EVENT_KEY_UP
;
242 nacl_event
.key
.which
= 0;
243 nacl_event
.key
.state
= kClear
;
244 nacl_event
.key
.keysym
.scancode
= xevent
->xkey
.keycode
;
245 xsym
= XKeycodeToKeysym(dpy
, xevent
->xkey
.keycode
, 0);
246 nsym
= XKeysymToNaCl(xsym
);
247 video
->SetKeyMod(nsym
, kClear
);
248 nacl_event
.key
.keysym
.sym
= nsym
;
249 nacl_event
.key
.keysym
.mod
= video
->event_state_key_mod_
;
250 nacl_event
.key
.keysym
.unicode
= 0;
251 video
->EventQueuePut(&nacl_event
);
254 x
= static_cast<uint16_t>(xevent
->xmotion
.x
);
255 y
= static_cast<uint16_t>(xevent
->xmotion
.y
);
256 nacl_event
.type
= NACL_EVENT_MOUSE_MOTION
;
257 nacl_event
.motion
.which
= 0;
258 nacl_event
.motion
.state
= video
->GetButton();
259 nacl_event
.motion
.x
= x
;
260 nacl_event
.motion
.y
= y
;
261 video
->GetRelativeMotion(x
, y
,
262 &nacl_event
.motion
.xrel
,
263 &nacl_event
.motion
.yrel
);
264 video
->SetMotion(xevent
->xmotion
.x
, xevent
->xmotion
.y
, 1);
265 video
->EventQueuePut(&nacl_event
);
268 button
= xevent
->xbutton
.button
;
269 nacl_event
.type
= NACL_EVENT_MOUSE_BUTTON_DOWN
;
270 nacl_event
.button
.which
= 0;
271 nacl_event
.button
.button
= button
;
272 nacl_event
.button
.state
= kSet
;
273 video
->GetMotion(&nacl_event
.button
.x
, &nacl_event
.button
.y
);
274 video
->SetButton(button
, 1);
275 video
->EventQueuePut(&nacl_event
);
278 button
= xevent
->xbutton
.button
;
279 nacl_event
.type
= NACL_EVENT_MOUSE_BUTTON_UP
;
280 nacl_event
.button
.which
= 0;
281 nacl_event
.button
.button
= button
;
282 nacl_event
.button
.state
= kClear
;
283 video
->GetMotion(&nacl_event
.button
.x
, &nacl_event
.button
.y
);
284 video
->SetButton(button
, 0);
285 video
->EventQueuePut(&nacl_event
);
288 nacl_event
.type
= NACL_EVENT_ACTIVE
;
289 nacl_event
.active
.state
= kClear
;
290 video
->EventQueuePut(&nacl_event
);
293 nacl_event
.type
= NACL_EVENT_ACTIVE
;
294 nacl_event
.active
.state
= kSet
;
295 video
->SetMotion(0, 0, 0);
296 video
->EventQueuePut(&nacl_event
);
299 // Other types of events should be handled here.
300 dprintf(("VideoMap::XEventHandler() Other\n"));
304 #endif // NACL_LINUX && defined(MOZ_X11)
307 // convert global mouse coordinate to local space
308 // TODO: why do these only work in the paint event?
309 static void GlobalToLocalHelper(NPWindow
* window
, Point
*point
) {
310 NP_Port
* npport
= static_cast<NP_Port
*>(window
->window
);
311 CGrafPtr our_port
= npport
->port
;
314 SetPort(reinterpret_cast<GrafPtr
>(our_port
));
315 GlobalToLocal(point
);
316 dprintf(("mouse local pos %d %d\n", point
->h
, point
->v
));
320 // looks for first changed key
321 static bool FindChangedKey(uint32_t *keys
, uint32_t *previous
,
322 int *which
, int *state
) {
323 if ((keys
[0] != previous
[0]) ||
324 (keys
[1] != previous
[1]) ||
325 (keys
[2] != previous
[2]) ||
326 (keys
[3] != previous
[3])) {
327 for (int i
= 0; i
< 128; ++i
) {
329 int bit
= (1 << (i
& 31));
330 int keys_bit
= ((keys
[idx
] & bit
) != 0);
331 int previous_bit
= ((previous
[idx
] & bit
) != 0);
332 if (keys_bit
!= previous_bit
) {
334 *state
= keys_bit
? kSet
: kClear
;
335 previous
[idx
] = keys
[idx
];
343 // converts mac raw key to nacl key
344 static int MacKeyToNaCl(int mk
) {
346 case 0x00: return NACL_KEY_a
;
347 case 0x0B: return NACL_KEY_b
;
348 case 0x08: return NACL_KEY_c
;
349 case 0x02: return NACL_KEY_d
;
350 case 0x0E: return NACL_KEY_e
;
351 case 0x03: return NACL_KEY_f
;
352 case 0x05: return NACL_KEY_g
;
353 case 0x04: return NACL_KEY_h
;
354 case 0x22: return NACL_KEY_i
;
355 case 0x26: return NACL_KEY_j
;
356 case 0x28: return NACL_KEY_k
;
357 case 0x25: return NACL_KEY_l
;
358 case 0x2E: return NACL_KEY_m
;
359 case 0x2D: return NACL_KEY_n
;
360 case 0x1F: return NACL_KEY_o
;
361 case 0x23: return NACL_KEY_p
;
362 case 0x0C: return NACL_KEY_q
;
363 case 0x0F: return NACL_KEY_r
;
364 case 0x01: return NACL_KEY_s
;
365 case 0x11: return NACL_KEY_t
;
366 case 0x20: return NACL_KEY_u
;
367 case 0x09: return NACL_KEY_v
;
368 case 0x0D: return NACL_KEY_w
;
369 case 0x07: return NACL_KEY_x
;
370 case 0x10: return NACL_KEY_y
;
371 case 0x06: return NACL_KEY_z
;
372 case 0x12: return NACL_KEY_1
;
373 case 0x13: return NACL_KEY_2
;
374 case 0x14: return NACL_KEY_3
;
375 case 0x15: return NACL_KEY_4
;
376 case 0x17: return NACL_KEY_5
;
377 case 0x16: return NACL_KEY_6
;
378 case 0x1A: return NACL_KEY_7
;
379 case 0x1C: return NACL_KEY_8
;
380 case 0x19: return NACL_KEY_9
;
381 case 0x1D: return NACL_KEY_0
;
382 case 0x32: return NACL_KEY_BACKQUOTE
;
383 case 0x2A: return NACL_KEY_BACKSLASH
;
384 case 0x33: return NACL_KEY_BACKSPACE
;
385 case 0x39: return NACL_KEY_CAPSLOCK
;
386 case 0x2B: return NACL_KEY_COMMA
;
387 case 0x75: return NACL_KEY_DELETE
;
388 case 0x7D: return NACL_KEY_DOWN
;
389 case 0x77: return NACL_KEY_END
;
390 case 0x18: return NACL_KEY_EQUALS
;
391 case 0x35: return NACL_KEY_ESCAPE
;
392 case 0x73: return NACL_KEY_HOME
;
393 case 0x72: return NACL_KEY_INSERT
;
394 case 0x52: return NACL_KEY_KP0
;
395 case 0x53: return NACL_KEY_KP1
;
396 case 0x54: return NACL_KEY_KP2
;
397 case 0x55: return NACL_KEY_KP3
;
398 case 0x56: return NACL_KEY_KP4
;
399 case 0x57: return NACL_KEY_KP5
;
400 case 0x58: return NACL_KEY_KP6
;
401 case 0x59: return NACL_KEY_KP7
;
402 case 0x5B: return NACL_KEY_KP8
;
403 case 0x5C: return NACL_KEY_KP9
;
404 case 0x4B: return NACL_KEY_KP_DIVIDE
;
405 case 0x34: return NACL_KEY_KP_ENTER
;
406 case 0x4C: return NACL_KEY_KP_ENTER
;
407 case 0x51: return NACL_KEY_KP_EQUALS
;
408 case 0x4E: return NACL_KEY_KP_MINUS
;
409 case 0x43: return NACL_KEY_KP_MULTIPLY
;
410 case 0x41: return NACL_KEY_KP_PERIOD
;
411 case 0x45: return NACL_KEY_KP_PLUS
;
412 case 0x3A: return NACL_KEY_LALT
;
413 case 0x3B: return NACL_KEY_LCTRL
;
414 case 0x7B: return NACL_KEY_LEFT
;
415 case 0x21: return NACL_KEY_LEFTBRACKET
;
416 case 0x37: return NACL_KEY_LMETA
;
417 case 0x38: return NACL_KEY_LSHIFT
;
418 case 0x1B: return NACL_KEY_MINUS
;
419 case 0x47: return NACL_KEY_NUMLOCK
;
420 case 0x79: return NACL_KEY_PAGEDOWN
;
421 case 0x74: return NACL_KEY_PAGEUP
;
422 case 0x71: return NACL_KEY_PAUSE
;
423 case 0x2F: return NACL_KEY_PERIOD
;
424 case 0x69: return NACL_KEY_PRINT
;
425 case 0x27: return NACL_KEY_QUOTE
;
426 case 0x3D: return NACL_KEY_RALT
;
427 case 0x3E: return NACL_KEY_RCTRL
;
428 case 0x24: return NACL_KEY_RETURN
;
429 case 0x7C: return NACL_KEY_RIGHT
;
430 case 0x1E: return NACL_KEY_RIGHTBRACKET
;
431 case 0x36: return NACL_KEY_RMETA
;
432 case 0x3C: return NACL_KEY_RSHIFT
;
433 case 0x6B: return NACL_KEY_SCROLLOCK
;
434 case 0x29: return NACL_KEY_SEMICOLON
;
435 case 0x30: return NACL_KEY_TAB
;
436 case 0x2C: return NACL_KEY_SLASH
;
437 case 0x31: return NACL_KEY_SPACE
;
438 case 0x7E: return NACL_KEY_UP
;
440 return NACL_KEY_UNKNOWN
;
443 int16_t VideoMap::HandleEvent(void *param
) {
444 dprintf(("VideoMap::HandleEvent(%p, %p)\n", this, param
));
449 const int rightMouseButtonMod
= 4096;
450 VideoScopedGlobalLock video_lock
;
451 if ((NULL
== window_
) || (NULL
== untrusted_video_share_
))
454 // MacOS delivers its events through the NPAPI HandleEvent API.
455 // TODO: switch this to a carbon event handler
456 EventRecord
* event
= static_cast<EventRecord
*>(param
);
457 NaClMultimediaEvent nacl_event
;
462 dprintf(("Event type %d\n", event
->what
));
464 // poll the mouse and see if it moved within our window
465 // TODO: only mouse events during updateEvt seem to
466 // TODO: provide good local coordinates.
467 // TODO: hmm... osEvt+18 works much better in FF3
468 // osEvt + 18 is NPAPIs mousemove event
469 const int mouseMoveBoundToEvent
= osEvt
+ 18;
470 if (event
->what
== mouseMoveBoundToEvent
) {
471 Point mouse_position
;
472 Point global_mouse_position
;
473 GetGlobalMouse(&global_mouse_position
);
474 mouse_position
= global_mouse_position
;
475 if (NULL
!= window_
) {
476 GlobalToLocalHelper(window_
, &mouse_position
);
477 if ((mouse_position
.h
>= 0) && (mouse_position
.v
>= 0) &&
478 (mouse_position
.h
< window_
->width
) &&
479 (mouse_position
.v
< window_
->height
)) {
480 uint16_t last_x
, last_y
;
481 x
= static_cast<uint16_t>(mouse_position
.h
);
482 y
= static_cast<uint16_t>(mouse_position
.v
);
483 GetMotion(&last_x
, &last_y
);
486 dprintf(("The mouse moved %d %d (event %d)\n",
487 (int)x
, (int)y
, event
->what
));
488 nacl_event
.type
= NACL_EVENT_MOUSE_MOTION
;
489 nacl_event
.motion
.which
= 0;
490 nacl_event
.motion
.state
= GetButton();
491 nacl_event
.motion
.x
= x
;
492 nacl_event
.motion
.y
= y
;
493 GetRelativeMotion(x
, y
,
494 &nacl_event
.motion
.xrel
, &nacl_event
.motion
.yrel
);
496 EventQueuePut(&nacl_event
);
503 #if defined(FIREFOX2)
504 // Firefox2's keyDown keyUp events don't seem to report
505 // ctrl/alt/meta/shift keypresses, so we need to
506 // poll the keyboard CTRL, SHIFT, ALT keys
507 // Unfortunately, this is a global poll, which is bad
508 // because it can see these presses even without focus.
509 // TODO: look into getting a better solution for FF2
511 static uint32_t previous_keys
[4] = {0, 0, 0, 0};
512 uint32_t *keys
= reinterpret_cast<uint32_t*>(keymap
);
516 if (FindChangedKey(keys
, previous_keys
, &which_key
, &key_state
)) {
517 int nsym
= MacKeyToNaCl(which_key
);
519 (nsym
== NACL_KEY_LCTRL
) ||
520 (nsym
== NACL_KEY_LALT
) ||
521 (nsym
== NACL_KEY_LSHIFT
);
523 nacl_event
.type
= key_state
? NACL_EVENT_KEY_DOWN
: NACL_EVENT_KEY_UP
;
524 nacl_event
.key
.which
= 0;
525 nacl_event
.key
.state
= key_state
;
526 nacl_event
.key
.keysym
.scancode
= which_key
;
527 SetKeyMod(nsym
, kSet
);
528 nacl_event
.key
.keysym
.sym
= nsym
;
529 nacl_event
.key
.keysym
.mod
= vs
->event_state_key_mod
;
530 nacl_event
.key
.keysym
.unicode
= 0;
531 EventQueuePut(&nacl_event
);
532 dprintf(("A special key has changed scancode: %d sym: %d state: %d\n",
533 which_key
, nsym
, key_state
));
538 if ((event
->what
!= 0) && (event
->what
!= updateEvt
))
539 dprintf(("an event happened %d\n", event
->what
));
540 switch (event
->what
) {
541 case (osEvt
+ 16): // NPAPI getFocusEvent:
542 nacl_event
.type
= NACL_EVENT_ACTIVE
;
543 nacl_event
.active
.state
= kSet
;
544 EventQueuePut(&nacl_event
);
545 dprintf(("Focus gained\n"));
547 case (osEvt
+ 17): // NPAPI loseFocusEvent:
548 nacl_event
.type
= NACL_EVENT_ACTIVE
;
549 nacl_event
.active
.state
= kClear
;
550 EventQueuePut(&nacl_event
);
551 dprintf(("Focus lost\n"));
555 int scancode
= (event
->message
& keyCodeMask
) >> 8;
556 int nsym
= MacKeyToNaCl(scancode
);
557 if (keyDown
== event
->what
) {
558 nacl_event
.type
= NACL_EVENT_KEY_DOWN
;
559 nacl_event
.key
.state
= kSet
;
561 nacl_event
.type
= NACL_EVENT_KEY_UP
;
562 nacl_event
.key
.state
= kClear
;
564 nacl_event
.key
.which
= 0;
565 nacl_event
.key
.keysym
.scancode
= scancode
;
566 SetKeyMod(nsym
, nacl_event
.key
.state
);
567 nacl_event
.key
.keysym
.sym
= nsym
;
568 nacl_event
.key
.keysym
.mod
= event_state_key_mod_
;
569 nacl_event
.key
.keysym
.unicode
= 0;
570 EventQueuePut(&nacl_event
);
571 dprintf(("A key press (scan: %d sym: %d state: %d)\n",
572 scancode
, nsym
, nacl_event
.key
.state
));
575 dprintf(("A mouse down happened\n"));
577 if (event
->modifiers
& rightMouseButtonMod
) {
580 nacl_event
.type
= NACL_EVENT_MOUSE_BUTTON_DOWN
;
581 nacl_event
.button
.which
= 0;
582 nacl_event
.button
.button
= button
;
583 nacl_event
.button
.state
= kSet
;
584 GetMotion(&nacl_event
.button
.x
, &nacl_event
.button
.y
);
585 SetButton(button
, kSet
);
586 EventQueuePut(&nacl_event
);
589 dprintf(("A mouse up happened\n"));
591 if (event
->modifiers
& rightMouseButtonMod
) {
594 nacl_event
.type
= NACL_EVENT_MOUSE_BUTTON_UP
;
595 nacl_event
.button
.which
= 0;
596 nacl_event
.button
.button
= button
;
597 nacl_event
.button
.state
= kClear
;
598 GetMotion(&nacl_event
.button
.x
, &nacl_event
.button
.y
);
599 SetButton(button
, kClear
);
600 EventQueuePut(&nacl_event
);
603 // Null events are set up by the browser to occur every ~16ms.
604 // We use this to redraw whenever an upcall has requested one.
605 if (request_redraw_
&& (NULL
!= window_
)) {
606 request_redraw_
= false;
607 // invalidate rect to generate an updateEvt
615 // we didn't handle this event...
621 void VideoMap::RedrawAsync(void *platform_parm
) {
622 dprintf(("VideoMap::RedrawAsync(%p)\n", platform_parm
));
623 if (NULL
!= platform_parm
) {
624 if (!window_
|| !window_
->window
|| !untrusted_video_share_
||
625 window_
->clipRect
.right
<= window_
->clipRect
.left
) {
629 RgnHandle saved_clip
= NewRgn();
635 short saved_port_top
;
636 short saved_port_left
;
638 NP_Port
* npport
= static_cast<NP_Port
*>(window_
->window
);
639 CGrafPtr our_port
= npport
->port
;
640 GetPort(&saved_port
);
641 SetPort(reinterpret_cast<GrafPtr
>(our_port
));
644 GetPortBounds(our_port
, &port_rect
);
645 saved_port_top
= port_rect
.top
;
646 saved_port_left
= port_rect
.left
;
649 revealed_rect
.top
= window_
->clipRect
.top
+ npport
->porty
;
650 revealed_rect
.left
= window_
->clipRect
.left
+ npport
->portx
;
651 revealed_rect
.bottom
= window_
->clipRect
.bottom
+ npport
->porty
;
652 revealed_rect
.right
= window_
->clipRect
.right
+ npport
->portx
;
653 SetOrigin(npport
->portx
, npport
->porty
);
654 ClipRect(&revealed_rect
);
657 // NB: the asymmetry in bounding box sizes is due to the fact that a pixmap
658 // appears not to contain its last row value. Hence we need one more
659 // in height than in width.
660 // TODO: get to the bottom of this
661 SetRect(&bounds
, 0, 0, window_
->width
- 1, window_
->height
);
663 OSErr result
= NewGWorld(&gworld
, 32, &bounds
, 0, 0, 0);
664 if (result
== noErr
) {
666 pixmap
= GetGWorldPixMap(gworld
);
667 if (LockPixels(pixmap
)) {
668 // TODO: Find a way to avoid bitmap copy and conversion
669 // (ARGB to RGBA) operations.
670 uint32_t* dst
= reinterpret_cast<uint32_t*>(GetPixBaseAddr(pixmap
));
671 uint32_t* src
= reinterpret_cast<uint32_t*>
672 (&untrusted_video_share_
->video_pixels
[0]);
673 for (unsigned int n
= 0; n
< window_
->width
* window_
->height
; ++n
) {
674 // Convert from ARGB to RGBA.
675 uint32_t color
= *src
++;
676 color
= (0x000000ff & (color
>> 24) |
677 (0x0000ff00 & (color
>> 8)) |
678 (0x00ff0000 & (color
<< 8)) |
679 (0xff000000 & (color
<< 24)));
682 UnlockPixels(pixmap
);
684 LockPortBits(gworld
);
685 CopyBits(GetPortBitMapForCopyBits(gworld
),
686 GetPortBitMapForCopyBits(our_port
),
691 UnlockPortBits(gworld
);
692 DisposeGWorld(gworld
);
695 SetOrigin(saved_port_left
, saved_port_top
);
698 DisposeRgn(saved_clip
);
702 void VideoMap::Redraw() {
704 // non-null to tell it we're from npapi thread
705 // TODO: figure out a thread safe way to render on mac
706 this->RedrawAsync(&i
);
711 static int WinKeyToNacl(int vk
) {
713 case VK_ADD
: return NACL_KEY_KP_PLUS
;
714 case VK_BACK
: return NACL_KEY_BACKSPACE
;
715 case VK_CAPITAL
: return NACL_KEY_CAPSLOCK
;
716 case VK_CLEAR
: return NACL_KEY_CLEAR
;
717 case VK_DECIMAL
: return NACL_KEY_KP_PERIOD
;
718 case VK_DELETE
: return NACL_KEY_DELETE
;
719 case VK_DIVIDE
: return NACL_KEY_KP_DIVIDE
;
720 case VK_DOWN
: return NACL_KEY_DOWN
;
721 case VK_END
: return NACL_KEY_END
;
722 case VK_ESCAPE
: return NACL_KEY_ESCAPE
;
723 case VK_F1
: return NACL_KEY_F1
;
724 case VK_F2
: return NACL_KEY_F2
;
725 case VK_F3
: return NACL_KEY_F3
;
726 case VK_F4
: return NACL_KEY_F4
;
727 case VK_F5
: return NACL_KEY_F5
;
728 case VK_F6
: return NACL_KEY_F6
;
729 case VK_F7
: return NACL_KEY_F7
;
730 case VK_F8
: return NACL_KEY_F8
;
731 case VK_F9
: return NACL_KEY_F9
;
732 case VK_F10
: return NACL_KEY_F10
;
733 case VK_F11
: return NACL_KEY_F11
;
734 case VK_F12
: return NACL_KEY_F12
;
735 case VK_F13
: return NACL_KEY_F13
;
736 case VK_F14
: return NACL_KEY_F14
;
737 case VK_F15
: return NACL_KEY_F15
;
738 case VK_HELP
: return NACL_KEY_HELP
;
739 case VK_HOME
: return NACL_KEY_HOME
;
740 case VK_INSERT
: return NACL_KEY_INSERT
;
741 case VK_LCONTROL
: return NACL_KEY_LCTRL
;
742 case VK_LEFT
: return NACL_KEY_LEFT
;
743 case VK_LMENU
: return NACL_KEY_LALT
;
744 case VK_LSHIFT
: return NACL_KEY_LSHIFT
;
745 case VK_MULTIPLY
: return NACL_KEY_KP_MULTIPLY
;
746 case VK_NEXT
: return NACL_KEY_PAGEDOWN
;
747 case VK_NUMLOCK
: return NACL_KEY_NUMLOCK
;
748 case VK_NUMPAD0
: return NACL_KEY_KP0
;
749 case VK_NUMPAD1
: return NACL_KEY_KP1
;
750 case VK_NUMPAD2
: return NACL_KEY_KP2
;
751 case VK_NUMPAD3
: return NACL_KEY_KP3
;
752 case VK_NUMPAD4
: return NACL_KEY_KP4
;
753 case VK_NUMPAD5
: return NACL_KEY_KP5
;
754 case VK_NUMPAD6
: return NACL_KEY_KP6
;
755 case VK_NUMPAD7
: return NACL_KEY_KP7
;
756 case VK_NUMPAD8
: return NACL_KEY_KP8
;
757 case VK_NUMPAD9
: return NACL_KEY_KP9
;
758 case VK_OEM_1
: return NACL_KEY_SEMICOLON
;
759 case VK_OEM_2
: return NACL_KEY_SLASH
;
760 case VK_OEM_3
: return NACL_KEY_BACKQUOTE
;
761 case VK_OEM_4
: return NACL_KEY_LEFTBRACKET
;
762 case VK_OEM_5
: return NACL_KEY_BACKSLASH
;
763 case VK_OEM_6
: return NACL_KEY_RIGHTBRACKET
;
764 case VK_OEM_7
: return NACL_KEY_QUOTE
;
765 case VK_OEM_8
: return NACL_KEY_BACKQUOTE
;
766 case VK_OEM_COMMA
: return NACL_KEY_COMMA
;
767 case VK_OEM_MINUS
: return NACL_KEY_MINUS
;
768 case VK_OEM_PERIOD
: return NACL_KEY_PERIOD
;
769 case VK_OEM_PLUS
: return NACL_KEY_EQUALS
;
770 case VK_OEM_102
: return NACL_KEY_LESS
;
771 case VK_PAUSE
: return NACL_KEY_PAUSE
;
772 case VK_PRIOR
: return NACL_KEY_PAGEUP
;
773 case VK_RCONTROL
: return NACL_KEY_RCTRL
;
774 case VK_RETURN
: return NACL_KEY_RETURN
;
775 case VK_RIGHT
: return NACL_KEY_RIGHT
;
776 case VK_RMENU
: return NACL_KEY_RALT
;
777 case VK_RSHIFT
: return NACL_KEY_RSHIFT
;
778 case VK_SCROLL
: return NACL_KEY_SCROLLOCK
;
779 case VK_SPACE
: return NACL_KEY_SPACE
;
780 case VK_SUBTRACT
: return NACL_KEY_KP_MINUS
;
781 case VK_TAB
: return NACL_KEY_TAB
;
782 case VK_UP
: return NACL_KEY_UP
;
783 case '0': return NACL_KEY_0
;
784 case '1': return NACL_KEY_1
;
785 case '2': return NACL_KEY_2
;
786 case '3': return NACL_KEY_3
;
787 case '4': return NACL_KEY_4
;
788 case '5': return NACL_KEY_5
;
789 case '6': return NACL_KEY_6
;
790 case '7': return NACL_KEY_7
;
791 case '8': return NACL_KEY_8
;
792 case '9': return NACL_KEY_9
;
793 case 'A': return NACL_KEY_a
;
794 case 'B': return NACL_KEY_b
;
795 case 'C': return NACL_KEY_c
;
796 case 'D': return NACL_KEY_d
;
797 case 'E': return NACL_KEY_e
;
798 case 'F': return NACL_KEY_f
;
799 case 'G': return NACL_KEY_g
;
800 case 'H': return NACL_KEY_h
;
801 case 'I': return NACL_KEY_i
;
802 case 'J': return NACL_KEY_j
;
803 case 'K': return NACL_KEY_k
;
804 case 'L': return NACL_KEY_l
;
805 case 'M': return NACL_KEY_m
;
806 case 'N': return NACL_KEY_n
;
807 case 'O': return NACL_KEY_o
;
808 case 'P': return NACL_KEY_p
;
809 case 'Q': return NACL_KEY_q
;
810 case 'R': return NACL_KEY_r
;
811 case 'S': return NACL_KEY_s
;
812 case 'T': return NACL_KEY_t
;
813 case 'U': return NACL_KEY_u
;
814 case 'V': return NACL_KEY_v
;
815 case 'W': return NACL_KEY_w
;
816 case 'X': return NACL_KEY_x
;
817 case 'Y': return NACL_KEY_y
;
818 case 'Z': return NACL_KEY_z
;
820 return NACL_KEY_UNKNOWN
;
823 LRESULT CALLBACK
VideoMap::WindowProcedure(HWND hwnd
,
827 dprintf(("VideoMap::VideoWindowProcedure()\n"));
828 VideoScopedGlobalLock video_lock
;
832 union NaClMultimediaEvent nacl_event
;
834 const int KEY_REPEAT_BIT
= (1 << 30);
835 const int KEY_EXTENDED_BIT
= (1 << 24);
836 VideoMap
*video
= reinterpret_cast<VideoMap
*>(
837 GetWindowLong(hwnd
, GWL_USERDATA
));
838 if ((NULL
== video
) || (NULL
== video
->untrusted_video_share_
)) {
839 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
844 // return non-zero value to indicate no further erasing is required
848 HDC hdc
= BeginPaint(hwnd
, &ps
);
849 if (NULL
!= video
->untrusted_video_share_
) {
850 uint32_t* pixel_bits
= reinterpret_cast<uint32_t*>
851 (&video
->untrusted_video_share_
->video_pixels
[0]);
853 bmp_info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
854 bmp_info
.bmiHeader
.biWidth
= video
->window_
->width
;
855 bmp_info
.bmiHeader
.biHeight
=
856 -static_cast<LONG
>(video
->window_
->height
); // top-down
857 bmp_info
.bmiHeader
.biPlanes
= 1;
858 bmp_info
.bmiHeader
.biBitCount
= 32;
859 bmp_info
.bmiHeader
.biCompression
= BI_RGB
;
860 bmp_info
.bmiHeader
.biSizeImage
= 0;
861 bmp_info
.bmiHeader
.biXPelsPerMeter
= 0;
862 bmp_info
.bmiHeader
.biYPelsPerMeter
= 0;
863 bmp_info
.bmiHeader
.biClrUsed
= 0;
864 bmp_info
.bmiHeader
.biClrImportant
= 0;
865 SetDIBitsToDevice(hdc
,
868 video
->window_
->width
,
869 video
->window_
->height
,
873 video
->window_
->height
,
882 x
= static_cast<uint16_t>(LOWORD(lparam
));
883 y
= static_cast<uint16_t>(HIWORD(lparam
));
884 nacl_event
.type
= NACL_EVENT_MOUSE_MOTION
;
885 nacl_event
.motion
.which
= 0;
886 nacl_event
.motion
.state
= video
->GetButton();
887 nacl_event
.motion
.x
= x
;
888 nacl_event
.motion
.y
= y
;
889 video
->GetRelativeMotion(x
, y
,
890 &nacl_event
.motion
.xrel
, &nacl_event
.motion
.yrel
);
891 video
->SetMotion(x
, y
, 1);
892 video
->EventQueuePut(&nacl_event
);
895 case WM_LBUTTONDBLCLK
:
897 case WM_RBUTTONDBLCLK
:
899 case WM_MBUTTONDBLCLK
:
903 case WM_LBUTTONDBLCLK
:
907 case WM_MBUTTONDBLCLK
:
911 case WM_RBUTTONDBLCLK
:
918 nacl_event
.type
= NACL_EVENT_MOUSE_BUTTON_DOWN
;
919 nacl_event
.button
.which
= 0;
920 nacl_event
.button
.button
= button
;
921 nacl_event
.button
.state
= kSet
;
922 video
->GetMotion(&nacl_event
.button
.x
, &nacl_event
.button
.y
);
923 video
->SetButton(button
, 1);
924 video
->EventQueuePut(&nacl_event
);
943 nacl_event
.type
= NACL_EVENT_MOUSE_BUTTON_UP
;
944 nacl_event
.button
.which
= 0;
945 nacl_event
.button
.button
= button
;
946 nacl_event
.button
.state
= kClear
;
947 video
->GetMotion(&nacl_event
.button
.x
, &nacl_event
.button
.y
);
948 video
->SetButton(button
, 0);
949 video
->EventQueuePut(&nacl_event
);
953 if (wparam
== VK_CONTROL
) {
954 if (lparam
& KEY_EXTENDED_BIT
) {
955 wparam
= VK_RCONTROL
;
957 wparam
= VK_LCONTROL
;
960 if (msg
== WM_KEYDOWN
) {
961 if (lparam
& KEY_REPEAT_BIT
) return 0; // disable repeat
962 nacl_event
.type
= NACL_EVENT_KEY_DOWN
;
963 nacl_event
.key
.state
= kSet
;
965 nacl_event
.type
= NACL_EVENT_KEY_UP
;
966 nacl_event
.key
.state
= kClear
;
968 nacl_event
.key
.which
= 0;
969 nacl_event
.key
.keysym
.scancode
= HIWORD(lparam
) & 0x1FF;
970 nsym
= WinKeyToNacl(wparam
);
971 nacl_event
.key
.keysym
.sym
= nsym
;
972 nacl_event
.key
.keysym
.mod
= video
->event_state_key_mod_
;
973 nacl_event
.key
.keysym
.unicode
= 0;
974 video
->EventQueuePut(&nacl_event
);
980 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
983 void VideoMap::RedrawAsync(void *platform_parm
) {
984 dprintf(("VideoMap::RedrawAsync()\n"));
985 HWND hwnd
= static_cast<HWND
>(window_
->window
);
986 HDC hdc
= GetDC(hwnd
);
987 VideoMap
*video
= reinterpret_cast<VideoMap
*>(
988 GetWindowLong(hwnd
, GWL_USERDATA
));
989 if ((NULL
== video
) || (NULL
== video
->untrusted_video_share_
)) {
993 uint32_t* pixel_bits
= reinterpret_cast<uint32_t*>
994 (&video
->untrusted_video_share_
->video_pixels
[0]);
996 bmp_info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
997 bmp_info
.bmiHeader
.biWidth
= video
->window_
->width
;
998 bmp_info
.bmiHeader
.biHeight
=
999 -static_cast<LONG
>(video
->window_
->height
); // top-down
1000 bmp_info
.bmiHeader
.biPlanes
= 1;
1001 bmp_info
.bmiHeader
.biBitCount
= 32;
1002 bmp_info
.bmiHeader
.biCompression
= BI_RGB
;
1003 bmp_info
.bmiHeader
.biSizeImage
= 0;
1004 bmp_info
.bmiHeader
.biXPelsPerMeter
= 0;
1005 bmp_info
.bmiHeader
.biYPelsPerMeter
= 0;
1006 bmp_info
.bmiHeader
.biClrUsed
= 0;
1007 bmp_info
.bmiHeader
.biClrImportant
= 0;
1008 SetDIBitsToDevice(hdc
,
1011 video
->window_
->width
,
1012 video
->window_
->height
,
1016 video
->window_
->height
,
1020 ReleaseDC(hwnd
, hdc
);
1023 void VideoMap::Redraw() {
1024 this->RedrawAsync(NULL
);
1026 #endif // NACL_WINDOWS
1028 // assumes event is already normalized to NaClMultimediaEvent
1029 int VideoMap::EventQueuePut(union NaClMultimediaEvent
*event
) {
1031 if (EventQueueIsFull()) {
1034 // apply mask to untrusted event_write_index
1035 windex
= (untrusted_video_share_
->u
.h
.event_write_index
&
1036 (NACL_EVENT_RING_BUFFER_SIZE
- 1));
1037 untrusted_video_share_
->u
.h
.event_queue
[windex
] = *event
;
1038 windex
= (windex
+ 1) & (NACL_EVENT_RING_BUFFER_SIZE
- 1);
1039 untrusted_video_share_
->u
.h
.event_write_index
= windex
;
1043 // tests event queue to see if it is full
1044 int VideoMap::EventQueueIsFull() {
1046 windex
= untrusted_video_share_
->u
.h
.event_write_index
;
1047 windex
= (windex
+ 1) & (NACL_EVENT_RING_BUFFER_SIZE
- 1);
1048 return (windex
== untrusted_video_share_
->u
.h
.event_read_index
);
1051 // Gets the last recorded mouse motion (position)
1052 // note: outputs normalized for NaCl events
1053 void VideoMap::GetMotion(uint16_t *x
, uint16_t *y
) {
1054 *x
= event_state_motion_last_x_
;
1055 *y
= event_state_motion_last_y_
;
1058 // Sets the mouse motion (position)
1059 // note: the inputs must be normalized for NaCl events
1060 void VideoMap::SetMotion(uint16_t x
, uint16_t y
, int last_valid
) {
1061 event_state_motion_last_x_
= x
;
1062 event_state_motion_last_y_
= y
;
1063 event_state_motion_last_valid_
= last_valid
;
1066 // Gets the relative mouse motion and updates position
1067 // note: the inputs must be normalized for NaCl events
1068 void VideoMap::GetRelativeMotion(uint16_t x
, uint16_t y
,
1069 int16_t *rel_x
, int16_t *rel_y
) {
1070 if (event_state_motion_last_valid_
) {
1071 *rel_x
= x
- event_state_motion_last_x_
;
1072 *rel_y
= y
- event_state_motion_last_y_
;
1073 event_state_motion_last_x_
= x
;
1074 event_state_motion_last_y_
= y
;
1075 event_state_motion_last_valid_
= 1;
1082 // Gets the current mouse button state
1083 // note: output is normalized for NaCl events
1084 int VideoMap::GetButton() {
1085 return event_state_button_
;
1088 // Modifies the mouse button state
1089 // note: input must be normalized for NaCl events
1090 void VideoMap::SetButton(int button
, int state
) {
1091 if (kClear
== state
) {
1092 event_state_button_
&= ~(1 << button
);
1094 event_state_button_
|= (1 << button
);
1098 // Modifies the keyboard modifier state (shift, ctrl, alt, etc)
1099 // note: input must be normalized for NaCl events
1100 void VideoMap::SetKeyMod(int nsym
, int state
) {
1103 // fill in with actual key modifiers
1104 case NACL_KEY_LCTRL
: mask
= NACL_KEYMOD_LCTRL
; break;
1105 case NACL_KEY_RCTRL
: mask
= NACL_KEYMOD_RCTRL
; break;
1106 case NACL_KEY_LSHIFT
: mask
= NACL_KEYMOD_LSHIFT
; break;
1107 case NACL_KEY_RSHIFT
: mask
= NACL_KEYMOD_RSHIFT
; break;
1108 case NACL_KEY_LALT
: mask
= NACL_KEYMOD_LALT
; break;
1109 case NACL_KEY_RALT
: mask
= NACL_KEYMOD_RALT
; break;
1110 default: mask
= NACL_KEYMOD_NONE
; break;
1112 if (kClear
== state
) {
1113 event_state_key_mod_
&= ~(mask
);
1115 event_state_key_mod_
|= (mask
);
1119 // Gets the current keyboard modifier state
1120 // note: output is normalized for NaCl Events
1121 int VideoMap::GetKeyMod() {
1122 return event_state_key_mod_
;
1125 // handle video map specific NPAPI SetWindow
1126 NPError
VideoMap::SetWindow(NPWindow
*window
) {
1127 dprintf(("VideoMap::SetWindow(%p)\n", window
));
1128 // first check window->width & window->height...
1129 if ((NULL
== window_
) && (window
->window
) &&
1130 (window
->width
> 0) && (window
->height
> 0)) {
1133 // then check width & height properties... (needed for Safari)
1134 nacl_srpc::Plugin
*plugin
= srpc_plugin_
->plugin();
1135 if (nacl_srpc::Plugin::GetProperty(plugin
,
1136 nacl_srpc::Plugin::kWidthIdent
, &variant
) == false) {
1137 return NPERR_NO_ERROR
;
1139 if (!nacl_srpc::NPVariantToScalar(&variant
, &width
)) {
1140 return NPERR_NO_ERROR
;
1142 if (nacl_srpc::Plugin::GetProperty(plugin
,
1143 nacl_srpc::Plugin::kWidthIdent
, &variant
) == false) {
1144 return NPERR_NO_ERROR
;
1146 if (!nacl_srpc::NPVariantToScalar(&variant
, &height
)) {
1147 return NPERR_NO_ERROR
;
1149 if ((width
> 0) && (height
> 0)) {
1150 dprintf(("VideoMap::SetWindow calling Initialize(%p)\n", window
));
1151 // don't allow invalid window sizes
1152 if ((width
< kNaClVideoMinWindowSize
) ||
1153 (width
> kNaClVideoMaxWindowSize
) ||
1154 (height
< kNaClVideoMinWindowSize
) ||
1155 (height
> kNaClVideoMaxWindowSize
)) {
1156 dprintf(("VideoMap::SetWindow got invalid window size (%d, %d)\n",
1158 return NPERR_GENERIC_ERROR
;
1160 if (-1 == InitializeSharedMemory(window
)) {
1161 return NPERR_GENERIC_ERROR
;
1164 dprintf(("VideoMap::SetWindow adding Windows event listener\n"));
1165 HWND hwnd
= static_cast<HWND
>(window
->window
);
1166 original_window_procedure_
= SubclassWindow(hwnd
,
1167 reinterpret_cast<WNDPROC
>(VideoMap::WindowProcedure
));
1168 SetWindowLong(hwnd
, GWL_USERDATA
, reinterpret_cast<LONG
>(this));
1169 #endif // NACL_WINDOWS
1170 #if NACL_LINUX && defined(MOZ_X11)
1171 // open X11 display, add X11 event listener
1172 dprintf(("VideoMap::SetWindow adding X11 display\n"));
1173 set_platform_specific(XOpenDisplay(NULL
));
1174 dprintf(("VideoMap::SetWindow adding X11 event listener\n"));
1175 Window xwin
= reinterpret_cast<Window
>(window
->window
);
1176 NPSetWindowCallbackStruct
* npsw
=
1177 reinterpret_cast<NPSetWindowCallbackStruct
*>(window
->ws_info
);
1178 Widget widget
= XtWindowToWidget(npsw
->display
, xwin
);
1180 long event_mask
= StructureNotifyMask
| KeyPressMask
|
1181 KeyReleaseMask
| ExposureMask
| PointerMotionMask
|
1182 ButtonPressMask
| ButtonReleaseMask
|
1183 LeaveWindowMask
| EnterWindowMask
;
1184 XSelectInput(npsw
->display
, xwin
, event_mask
);
1185 XtAddEventHandler(widget
, event_mask
, False
,
1186 reinterpret_cast<XtEventHandler
>(&VideoMap::XEventHandler
), this);
1188 #endif // NACL_LINUX && defined(MOZ_X11)
1191 return NPERR_NO_ERROR
;
1195 int16_t VideoMap::HandleEvent(void *param
) {
1196 dprintf(("VideoMap::HandleEvent(%p, %p)\n", this, param
));
1201 nacl_srpc::SharedMemory
* VideoMap::VideoSharedMemorySetup() {
1202 dprintf(("VideoMap::VideoSharedMemorySetup(%p, %p, %p)\n",
1203 this, video_shared_memory_
, video_handle_
));
1204 if (NULL
== video_shared_memory_
) {
1205 if (kInvalidHtpHandle
== video_handle_
) {
1206 // The plugin has not set up a shared memory object for the display.
1207 // This indicates either the plugin was set to be invisible, or had
1208 // an error when SetWindow was invoked. In either case, it is an
1209 // error to get the shared memory object.
1210 dprintf(("VideoMap::VideoSharedMemorySetup returning NULL\n"));
1213 // Create a SharedMemory object that the script can get at.
1214 // SRPC_Plugin initially takes exclusive ownership
1215 dprintf(("VideoMap::VideoSharedMemorySetup srpc_plugin_ (%p)\n",
1217 dprintf(("VideoMap::VideoSharedMemorySetup plugin (%p)\n",
1218 srpc_plugin_
->plugin()));
1219 video_shared_memory_
= nacl_srpc::SharedMemory::
1220 New(srpc_plugin_
->plugin(), video_handle_
);
1223 dprintf(("VideoMap::VideoSharedMemorySetup returns %p\n",
1224 video_shared_memory_
));
1225 // Anyone requesting video_shared_memory_ begins sharing ownership.
1226 NPN_RetainObject(video_shared_memory_
);
1227 return video_shared_memory_
;
1230 // Note: Graphics functionality similar to npapi_bridge.
1231 // TODO: Make only one copy of the graphics code.
1232 void VideoMap::Invalidate() {
1233 if (window_
&& window_
->window
) {
1235 HWND hwnd
= static_cast<HWND
>(window_
->window
);
1239 rect
.right
= window_
->width
;
1240 rect
.bottom
= window_
->height
;
1241 ::InvalidateRect(hwnd
, &rect
, FALSE
);
1247 rect
.right
= window_
->width
;
1248 rect
.bottom
= window_
->height
;
1249 ::NPN_InvalidateRect(srpc_plugin_
->GetNPP(), const_cast<NPRect
*>(&rect
));
1254 VideoCallbackData
* VideoMap::InitCallbackData(NaClHandle h
,
1256 nacl_srpc::MultimediaSocket
*msp
) {
1257 // initialize with refcount set to 2
1258 video_callback_data_
= new(std::nothrow
) VideoCallbackData(h
, p
, 2, msp
);
1259 return video_callback_data_
;
1263 VideoCallbackData
* VideoMap::ReleaseCallbackData(VideoCallbackData
* vcd
) {
1264 dprintf(("VideoMap::ReleaseCallbackData (%p), refcount was %d\n",
1265 vcd
, vcd
->refcount
));
1267 if (0 == vcd
->refcount
) {
1275 // normally, the Release version is preferred, which reference counts.
1276 // in some cases we may just need to forcefully delete the callback data,
1277 // and ignore the refcount.
1278 void VideoMap::ForceDeleteCallbackData(VideoCallbackData
* vcd
) {
1279 dprintf(("VideoMap::ForceDeleteCallbackData (%p)\n", vcd
));
1283 // opens shared memory map into untrusted space
1284 // returns 0 success, -1 failure
1285 int VideoMap::InitializeSharedMemory(NPWindow
*window
) {
1286 int width
= window
->width
;
1287 int height
= window
->height
;
1288 const int bytes_per_pixel
= 4;
1289 int image_size
= width
* height
* bytes_per_pixel
;
1290 int vps_size
= sizeof(struct NaClVideoShare
) + image_size
;
1292 dprintf(("VideoMap::Initialize(%p) this: %p\n", window
, this));
1293 dprintf(("VideoMap::Initialize width, height: %d, %d\n", width
, height
));
1294 if (NULL
== window_
) {
1295 // verify event struct size
1296 if (sizeof(union NaClMultimediaEvent
) >
1297 sizeof(struct NaClMultimediaPadEvent
)) {
1298 dprintf(("VideoMap::Initialize event struct size failed\n"));
1301 // verify header size
1302 if ((NACL_VIDEO_SHARE_HEADER_SIZE
+ NACL_VIDEO_SHARE_PIXEL_PAD
) !=
1303 sizeof(struct NaClVideoShare
)) {
1304 dprintf(("VideoMap::Initialize video share size failed\n"));
1307 dprintf(("VideoMap::Initialize assigning window to this(%p)\n", this));
1308 // map video & event shared memory structure between trusted & untrusted
1310 vps_size
= NaClRoundAllocPage(vps_size
);
1311 video_size_
= vps_size
;
1312 video_handle_
= CreateShmDesc(CreateMemoryObject(video_size_
),
1314 if (kInvalidHtpHandle
== video_handle_
) {
1318 dprintf(("VideoMap::Initialize about to Map...\n"));
1319 untrusted_video_share_
= (NaClVideoShare
*)Map(NULL
,
1321 kProtRead
| kProtWrite
,
1325 if (kMapFailed
== untrusted_video_share_
) {
1326 untrusted_video_share_
= NULL
;
1327 nacl::Close(video_handle_
);
1328 untrusted_video_share_
= NULL
;
1334 // clear entire untrusted memory window
1335 memset(untrusted_video_share_
, 0, video_size_
);
1337 // pass some information to untrusted code via the shared memory window
1338 // note: everything untrusted_video_share_ points to is untrusted, and could
1339 // be maliciously modified at any time.
1340 untrusted_video_share_
->u
.h
.map_size
= video_size_
;
1341 untrusted_video_share_
->u
.h
.video_width
= width
;
1342 untrusted_video_share_
->u
.h
.video_height
= height
;
1343 untrusted_video_share_
->u
.h
.video_size
= image_size
;
1345 // explicitly init states
1346 event_state_button_
= kClear
;
1347 event_state_key_mod_
= kClear
;
1348 event_state_motion_last_x_
= 0;
1349 event_state_motion_last_y_
= 0;
1350 event_state_motion_last_valid_
= 0;
1355 // this is the draw method the upcall thread should invoke
1356 void VideoMap::RequestRedraw() {
1360 // TODO: based on video_update_ member variable,
1361 // either render from the paint/expose event, or asynchronously
1362 // (at the moment, MacOSX always renders from paint event, but the
1363 // other platforms always render asynchronously)
1365 request_redraw_
= true;
1367 RedrawAsync(platform_specific());
1371 VideoMap::VideoMap(SRPC_Plugin
*srpc_plugin
) :
1372 event_state_button_(kClear
),
1373 event_state_key_mod_(kClear
),
1374 event_state_motion_last_x_(0),
1375 event_state_motion_last_y_(0),
1376 event_state_motion_last_valid_(0),
1377 platform_specific_(NULL
),
1378 request_redraw_(false),
1379 untrusted_video_share_(NULL
),
1380 video_handle_(kInvalidHtpHandle
),
1382 video_enabled_(false),
1383 video_callback_data_(NULL
),
1384 video_shared_memory_(NULL
),
1385 video_update_mode_(0) {
1386 srpc_plugin_
= srpc_plugin
;
1388 // retrieve update property from plugin
1389 if (NULL
!= srpc_plugin_
) {
1390 nacl_srpc::Plugin
*plugin
= srpc_plugin_
->plugin();
1391 if (NULL
!= plugin
) {
1393 nacl_srpc::Plugin::GetProperty(plugin
,
1394 nacl_srpc::Plugin::kVideoUpdateModeIdent
, &variant
);
1395 if (!nacl_srpc::NPVariantToScalar(&variant
, &video_update_mode_
)) {
1396 // BUG: unhandled type error in the constructor.
1397 // TODO: Break the constructor to handle errors.
1403 VideoMap::~VideoMap() {
1405 dprintf(("VideoMap::~VideoMap() releasing video_callback_data_ (%p)\n",
1406 video_callback_data_
));
1407 if (NULL
!= video_callback_data_
) {
1408 video_callback_data_
->srpc_plugin
= NULL
;
1409 video_callback_data_
= ReleaseCallbackData(video_callback_data_
);
1411 if (NULL
!= platform_specific()) {
1413 XCloseDisplay(static_cast<Display
*>(platform_specific()));
1415 set_platform_specific(NULL
);
1418 if (window_
&& window_
->window
) {
1419 SubclassWindow(reinterpret_cast<HWND
>(window_
->window
),
1420 original_window_procedure_
);
1422 #endif // NACL_WINDOWS