Home | History | Annotate | Download | only in page
      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