1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/printing/nsPrintPreviewListener.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,212 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsPrintPreviewListener.h" 1.11 + 1.12 +#include "mozilla/TextEvents.h" 1.13 +#include "mozilla/dom/Element.h" 1.14 +#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() 1.15 +#include "nsIDOMWindow.h" 1.16 +#include "nsPIDOMWindow.h" 1.17 +#include "nsIDOMElement.h" 1.18 +#include "nsIDOMKeyEvent.h" 1.19 +#include "nsIDOMEvent.h" 1.20 +#include "nsIDocument.h" 1.21 +#include "nsIDocShell.h" 1.22 +#include "nsPresContext.h" 1.23 +#include "nsFocusManager.h" 1.24 +#include "nsLiteralString.h" 1.25 + 1.26 +using namespace mozilla; 1.27 +using namespace mozilla::dom; 1.28 + 1.29 +NS_IMPL_ISUPPORTS(nsPrintPreviewListener, nsIDOMEventListener) 1.30 + 1.31 + 1.32 +// 1.33 +// nsPrintPreviewListener ctor 1.34 +// 1.35 +nsPrintPreviewListener::nsPrintPreviewListener(EventTarget* aTarget) 1.36 + : mEventTarget(aTarget) 1.37 +{ 1.38 + NS_ADDREF_THIS(); 1.39 +} // ctor 1.40 + 1.41 +nsPrintPreviewListener::~nsPrintPreviewListener() 1.42 +{ 1.43 +} 1.44 + 1.45 +//------------------------------------------------------- 1.46 +// 1.47 +// AddListeners 1.48 +// 1.49 +// Subscribe to the events that will allow us to track various events. 1.50 +// 1.51 +nsresult 1.52 +nsPrintPreviewListener::AddListeners() 1.53 +{ 1.54 + if (mEventTarget) { 1.55 + mEventTarget->AddEventListener(NS_LITERAL_STRING("click"), this, true); 1.56 + mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true); 1.57 + mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"), this, true); 1.58 + mEventTarget->AddEventListener(NS_LITERAL_STRING("keypress"), this, true); 1.59 + mEventTarget->AddEventListener(NS_LITERAL_STRING("keyup"), this, true); 1.60 + mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true); 1.61 + mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this, true); 1.62 + mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true); 1.63 + mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true); 1.64 + mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true); 1.65 + 1.66 + mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("keydown"), 1.67 + this, true); 1.68 + } 1.69 + 1.70 + return NS_OK; 1.71 +} 1.72 + 1.73 + 1.74 +//------------------------------------------------------- 1.75 +// 1.76 +// RemoveListeners 1.77 +// 1.78 +// Unsubscribe from all the various events that we were listening to. 1.79 +// 1.80 +nsresult 1.81 +nsPrintPreviewListener::RemoveListeners() 1.82 +{ 1.83 + if (mEventTarget) { 1.84 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("click"), this, true); 1.85 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true); 1.86 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true); 1.87 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true); 1.88 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true); 1.89 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true); 1.90 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, true); 1.91 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, true); 1.92 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, true); 1.93 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true); 1.94 + 1.95 + mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), 1.96 + this, true); 1.97 + } 1.98 + 1.99 + return NS_OK; 1.100 +} 1.101 + 1.102 +//------------------------------------------------------- 1.103 +// 1.104 +// GetActionForEvent 1.105 +// 1.106 +// Helper function to let certain key events through 1.107 +// 1.108 +enum eEventAction { 1.109 + eEventAction_Tab, eEventAction_ShiftTab, 1.110 + eEventAction_Propagate, eEventAction_Suppress, 1.111 + eEventAction_StopPropagation 1.112 +}; 1.113 + 1.114 +static eEventAction 1.115 +GetActionForEvent(nsIDOMEvent* aEvent) 1.116 +{ 1.117 + WidgetKeyboardEvent* keyEvent = 1.118 + aEvent->GetInternalNSEvent()->AsKeyboardEvent(); 1.119 + if (!keyEvent) { 1.120 + return eEventAction_Suppress; 1.121 + } 1.122 + 1.123 + if (keyEvent->mFlags.mInSystemGroup) { 1.124 + NS_ASSERTION(keyEvent->message == NS_KEY_DOWN, 1.125 + "Assuming we're listening only keydown event in system group"); 1.126 + return eEventAction_StopPropagation; 1.127 + } 1.128 + 1.129 + if (keyEvent->IsAlt() || keyEvent->IsControl() || keyEvent->IsMeta()) { 1.130 + // Don't consume keydown event because following keypress event may be 1.131 + // handled as access key or shortcut key. 1.132 + return (keyEvent->message == NS_KEY_DOWN) ? eEventAction_StopPropagation : 1.133 + eEventAction_Suppress; 1.134 + } 1.135 + 1.136 + static const uint32_t kOKKeyCodes[] = { 1.137 + nsIDOMKeyEvent::DOM_VK_PAGE_UP, nsIDOMKeyEvent::DOM_VK_PAGE_DOWN, 1.138 + nsIDOMKeyEvent::DOM_VK_UP, nsIDOMKeyEvent::DOM_VK_DOWN, 1.139 + nsIDOMKeyEvent::DOM_VK_HOME, nsIDOMKeyEvent::DOM_VK_END 1.140 + }; 1.141 + 1.142 + if (keyEvent->keyCode == nsIDOMKeyEvent::DOM_VK_TAB) { 1.143 + return keyEvent->IsShift() ? eEventAction_ShiftTab : eEventAction_Tab; 1.144 + } 1.145 + 1.146 + if (keyEvent->charCode == ' ' || keyEvent->keyCode == NS_VK_SPACE) { 1.147 + return eEventAction_Propagate; 1.148 + } 1.149 + 1.150 + if (keyEvent->IsShift()) { 1.151 + return eEventAction_Suppress; 1.152 + } 1.153 + 1.154 + for (uint32_t i = 0; i < ArrayLength(kOKKeyCodes); ++i) { 1.155 + if (keyEvent->keyCode == kOKKeyCodes[i]) { 1.156 + return eEventAction_Propagate; 1.157 + } 1.158 + } 1.159 + 1.160 + return eEventAction_Suppress; 1.161 +} 1.162 + 1.163 +NS_IMETHODIMP 1.164 +nsPrintPreviewListener::HandleEvent(nsIDOMEvent* aEvent) 1.165 +{ 1.166 + nsCOMPtr<nsIContent> content = do_QueryInterface( 1.167 + aEvent ? aEvent->InternalDOMEvent()->GetOriginalTarget() : nullptr); 1.168 + if (content && !content->IsXUL()) { 1.169 + eEventAction action = ::GetActionForEvent(aEvent); 1.170 + switch (action) { 1.171 + case eEventAction_Tab: 1.172 + case eEventAction_ShiftTab: 1.173 + { 1.174 + nsAutoString eventString; 1.175 + aEvent->GetType(eventString); 1.176 + if (eventString == NS_LITERAL_STRING("keydown")) { 1.177 + // Handle tabbing explicitly here since we don't want focus ending up 1.178 + // inside the content document, bug 244128. 1.179 + nsIDocument* doc = content->GetCurrentDoc(); 1.180 + NS_ASSERTION(doc, "no document"); 1.181 + 1.182 + nsIDocument* parentDoc = doc->GetParentDocument(); 1.183 + NS_ASSERTION(parentDoc, "no parent document"); 1.184 + 1.185 + nsCOMPtr<nsIDOMWindow> win = do_QueryInterface(parentDoc->GetWindow()); 1.186 + 1.187 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.188 + if (fm && win) { 1.189 + dom::Element* fromElement = parentDoc->FindContentForSubDocument(doc); 1.190 + nsCOMPtr<nsIDOMElement> from = do_QueryInterface(fromElement); 1.191 + 1.192 + bool forward = (action == eEventAction_Tab); 1.193 + nsCOMPtr<nsIDOMElement> result; 1.194 + fm->MoveFocus(win, from, 1.195 + forward ? nsIFocusManager::MOVEFOCUS_FORWARD : 1.196 + nsIFocusManager::MOVEFOCUS_BACKWARD, 1.197 + nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result)); 1.198 + } 1.199 + } 1.200 + } 1.201 + // fall-through 1.202 + case eEventAction_Suppress: 1.203 + aEvent->StopPropagation(); 1.204 + aEvent->PreventDefault(); 1.205 + break; 1.206 + case eEventAction_StopPropagation: 1.207 + aEvent->StopPropagation(); 1.208 + break; 1.209 + case eEventAction_Propagate: 1.210 + // intentionally empty 1.211 + break; 1.212 + } 1.213 + } 1.214 + return NS_OK; 1.215 +}