1 /* 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 "core/page/PointerLockController.h" 27 28 #include "core/dom/Element.h" 29 #include "core/dom/Event.h" 30 #include "core/page/Chrome.h" 31 #include "core/page/ChromeClient.h" 32 #include "core/page/Page.h" 33 #include "core/platform/PlatformMouseEvent.h" 34 35 namespace WebCore { 36 37 PointerLockController::PointerLockController(Page* page) 38 : m_page(page) 39 { 40 } 41 42 PassOwnPtr<PointerLockController> PointerLockController::create(Page* page) 43 { 44 return adoptPtr(new PointerLockController(page)); 45 } 46 47 void PointerLockController::requestPointerLock(Element* target) 48 { 49 if (!target || !target->inDocument() || m_documentOfRemovedElementWhileWaitingForUnlock) { 50 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target); 51 return; 52 } 53 54 if (target->document()->isSandboxed(SandboxPointerLock)) { 55 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 56 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."); 57 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target); 58 return; 59 } 60 61 if (m_element) { 62 if (m_element->document() != target->document()) { 63 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target); 64 return; 65 } 66 enqueueEvent(eventNames().webkitpointerlockchangeEvent, target); 67 m_element = target; 68 } else if (m_page->chrome().client()->requestPointerLock()) { 69 m_lockPending = true; 70 m_element = target; 71 } else { 72 enqueueEvent(eventNames().webkitpointerlockerrorEvent, target); 73 } 74 } 75 76 void PointerLockController::requestPointerUnlock() 77 { 78 return m_page->chrome().client()->requestPointerUnlock(); 79 } 80 81 void PointerLockController::elementRemoved(Element* element) 82 { 83 if (m_element == element) { 84 m_documentOfRemovedElementWhileWaitingForUnlock = m_element->document(); 85 // Set element null immediately to block any future interaction with it 86 // including mouse events received before the unlock completes. 87 clearElement(); 88 requestPointerUnlock(); 89 } 90 } 91 92 void PointerLockController::documentDetached(Document* document) 93 { 94 if (m_element && m_element->document() == document) { 95 clearElement(); 96 requestPointerUnlock(); 97 } 98 } 99 100 bool PointerLockController::lockPending() const 101 { 102 return m_lockPending; 103 } 104 105 Element* PointerLockController::element() const 106 { 107 return m_element.get(); 108 } 109 110 void PointerLockController::didAcquirePointerLock() 111 { 112 enqueueEvent(eventNames().webkitpointerlockchangeEvent, m_element.get()); 113 m_lockPending = false; 114 } 115 116 void PointerLockController::didNotAcquirePointerLock() 117 { 118 enqueueEvent(eventNames().webkitpointerlockerrorEvent, m_element.get()); 119 clearElement(); 120 } 121 122 void PointerLockController::didLosePointerLock() 123 { 124 enqueueEvent(eventNames().webkitpointerlockchangeEvent, m_element ? m_element->document() : m_documentOfRemovedElementWhileWaitingForUnlock.get()); 125 clearElement(); 126 m_documentOfRemovedElementWhileWaitingForUnlock = 0; 127 } 128 129 void PointerLockController::dispatchLockedMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType) 130 { 131 if (!m_element || !m_element->document()->frame()) 132 return; 133 134 m_element->dispatchMouseEvent(event, eventType, event.clickCount()); 135 136 // Create click events 137 if (eventType == eventNames().mouseupEvent) 138 m_element->dispatchMouseEvent(event, eventNames().clickEvent, event.clickCount()); 139 } 140 141 void PointerLockController::clearElement() 142 { 143 m_lockPending = false; 144 m_element = 0; 145 } 146 147 void PointerLockController::enqueueEvent(const AtomicString& type, Element* element) 148 { 149 if (element) 150 enqueueEvent(type, element->document()); 151 } 152 153 void PointerLockController::enqueueEvent(const AtomicString& type, Document* document) 154 { 155 if (document) 156 document->enqueueDocumentEvent(Event::create(type, true, false)); 157 } 158 159 } // namespace WebCore 160