blob: 5d6f5a5eaa20a891384903f387c43019047111d9 [file] [log] [blame]
scheib@chromium.org32c154a2012-01-27 19:06:41 +00001/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26#include "PointerLockController.h"
27
28#include "Chrome.h"
29#include "ChromeClient.h"
30#include "Element.h"
abarth@webkit.org401a3792013-03-03 10:12:59 +000031#include "Event.h"
scheib@chromium.org32c154a2012-01-27 19:06:41 +000032#include "Page.h"
33#include "PlatformMouseEvent.h"
34#include "VoidCallback.h"
35
36#if ENABLE(POINTER_LOCK)
37
38namespace WebCore {
39
40PointerLockController::PointerLockController(Page* page)
41 : m_page(page)
42{
43}
44
45PassOwnPtr<PointerLockController> PointerLockController::create(Page* page)
46{
47 return adoptPtr(new PointerLockController(page));
48}
49
scheib@chromium.org03edde32012-08-02 23:58:09 +000050void PointerLockController::requestPointerLock(Element* target)
scheib@chromium.org32c154a2012-01-27 19:06:41 +000051{
scheib@chromium.org8e806a12013-01-03 19:07:17 +000052 if (!target || !target->inDocument() || m_documentOfRemovedElementWhileWaitingForUnlock) {
53 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target);
54 return;
55 }
56
akling@apple.com622b1a42013-08-30 14:30:12 +000057 if (target->document().isSandboxed(SandboxPointerLock)) {
scheib@chromium.org8e806a12013-01-03 19:07:17 +000058 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
akling@apple.com622b1a42013-08-30 14:30:12 +000059 target->document().addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked pointer lock on an element because the element's frame is sandboxed and the 'allow-pointer-lock' permission is not set.");
scheib@chromium.org50a79892012-07-10 00:08:36 +000060 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target);
61 return;
62 }
63
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +000064 if (m_element) {
akling@apple.com622b1a42013-08-30 14:30:12 +000065 if (&m_element->document() != &target->document()) {
scheib@chromium.orgf4b6c5c2012-08-01 05:10:30 +000066 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target);
67 return;
68 }
scheib@chromium.org13c96db2012-06-07 22:40:19 +000069 enqueueEvent(eventNames().webkitpointerlockchangeEvent, target);
scheib@chromium.org03edde32012-08-02 23:58:09 +000070 m_element = target;
akling@apple.comfedaa632013-08-19 10:56:27 +000071 } else if (m_page->chrome().client().requestPointerLock()) {
scheib@chromium.org575ba7c2012-09-05 17:31:32 +000072 m_lockPending = true;
scheib@chromium.org32c154a2012-01-27 19:06:41 +000073 m_element = target;
scheib@chromium.org13c96db2012-06-07 22:40:19 +000074 } else {
scheib@chromium.org13c96db2012-06-07 22:40:19 +000075 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target);
scheib@chromium.org13c96db2012-06-07 22:40:19 +000076 }
scheib@chromium.org32c154a2012-01-27 19:06:41 +000077}
78
79void PointerLockController::requestPointerUnlock()
80{
akling@apple.comfedaa632013-08-19 10:56:27 +000081 return m_page->chrome().client().requestPointerUnlock();
scheib@chromium.org32c154a2012-01-27 19:06:41 +000082}
83
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +000084void PointerLockController::elementRemoved(Element* element)
85{
86 if (m_element == element) {
akling@apple.com622b1a42013-08-30 14:30:12 +000087 m_documentOfRemovedElementWhileWaitingForUnlock = &m_element->document();
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +000088 // Set element null immediately to block any future interaction with it
89 // including mouse events received before the unlock completes.
scheib@chromium.org575ba7c2012-09-05 17:31:32 +000090 clearElement();
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +000091 requestPointerUnlock();
92 }
93}
94
95void PointerLockController::documentDetached(Document* document)
96{
akling@apple.com622b1a42013-08-30 14:30:12 +000097 if (m_element && &m_element->document() == document) {
scheib@chromium.org575ba7c2012-09-05 17:31:32 +000098 clearElement();
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +000099 requestPointerUnlock();
100 }
101}
102
scheib@chromium.org575ba7c2012-09-05 17:31:32 +0000103bool PointerLockController::lockPending() const
104{
105 return m_lockPending;
106}
107
scheib@chromium.org6ed01762012-06-12 03:02:16 +0000108Element* PointerLockController::element() const
109{
110 return m_element.get();
111}
112
scheib@chromium.org32c154a2012-01-27 19:06:41 +0000113void PointerLockController::didAcquirePointerLock()
114{
scheib@chromium.org13c96db2012-06-07 22:40:19 +0000115 enqueueEvent(eventNames().webkitpointerlockchangeEvent, m_element.get());
scheib@chromium.org575ba7c2012-09-05 17:31:32 +0000116 m_lockPending = false;
scheib@chromium.org32c154a2012-01-27 19:06:41 +0000117}
118
119void PointerLockController::didNotAcquirePointerLock()
120{
scheib@chromium.org13c96db2012-06-07 22:40:19 +0000121 enqueueEvent(eventNames().webkitpointerlockerrorEvent, m_element.get());
scheib@chromium.org575ba7c2012-09-05 17:31:32 +0000122 clearElement();
scheib@chromium.org32c154a2012-01-27 19:06:41 +0000123}
124
scheib@chromium.org03edde32012-08-02 23:58:09 +0000125void PointerLockController::didLosePointerLock()
scheib@chromium.org32c154a2012-01-27 19:06:41 +0000126{
akling@apple.com622b1a42013-08-30 14:30:12 +0000127 enqueueEvent(eventNames().webkitpointerlockchangeEvent, m_element ? &m_element->document() : m_documentOfRemovedElementWhileWaitingForUnlock.get());
scheib@chromium.org575ba7c2012-09-05 17:31:32 +0000128 clearElement();
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +0000129 m_documentOfRemovedElementWhileWaitingForUnlock = 0;
scheib@chromium.org32c154a2012-01-27 19:06:41 +0000130}
131
132void PointerLockController::dispatchLockedMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType)
133{
akling@apple.com622b1a42013-08-30 14:30:12 +0000134 if (!m_element || !m_element->document().frame())
scheib@chromium.org32c154a2012-01-27 19:06:41 +0000135 return;
136
137 m_element->dispatchMouseEvent(event, eventType, event.clickCount());
138
139 // Create click events
140 if (eventType == eventNames().mouseupEvent)
141 m_element->dispatchMouseEvent(event, eventNames().clickEvent, event.clickCount());
142}
143
scheib@chromium.org575ba7c2012-09-05 17:31:32 +0000144void PointerLockController::clearElement()
145{
146 m_lockPending = false;
147 m_element = 0;
148}
149
scheib@chromium.org13c96db2012-06-07 22:40:19 +0000150void PointerLockController::enqueueEvent(const AtomicString& type, Element* element)
151{
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +0000152 if (element)
akling@apple.com622b1a42013-08-30 14:30:12 +0000153 enqueueEvent(type, &element->document());
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +0000154}
155
156void PointerLockController::enqueueEvent(const AtomicString& type, Document* document)
157{
158 if (document)
159 document->enqueueDocumentEvent(Event::create(type, true, false));
scheib@chromium.org13c96db2012-06-07 22:40:19 +0000160}
161
scheib@chromium.org32c154a2012-01-27 19:06:41 +0000162} // namespace WebCore
163
164#endif // ENABLE(POINTER_LOCK)