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