Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsPrintPreviewListener.h"
8 :
9 : #include "mozilla/TextEvents.h"
10 : #include "mozilla/dom/Element.h"
11 : #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
12 : #include "nsIDOMWindow.h"
13 : #include "nsPIDOMWindow.h"
14 : #include "nsIDOMElement.h"
15 : #include "nsIDOMKeyEvent.h"
16 : #include "nsIDOMEvent.h"
17 : #include "nsIDocument.h"
18 : #include "nsIDocShell.h"
19 : #include "nsPresContext.h"
20 : #include "nsFocusManager.h"
21 : #include "nsLiteralString.h"
22 :
23 : using namespace mozilla;
24 : using namespace mozilla::dom;
25 :
26 0 : NS_IMPL_ISUPPORTS(nsPrintPreviewListener, nsIDOMEventListener)
27 :
28 :
29 : //
30 : // nsPrintPreviewListener ctor
31 : //
32 0 : nsPrintPreviewListener::nsPrintPreviewListener(EventTarget* aTarget)
33 0 : : mEventTarget(aTarget)
34 : {
35 0 : NS_ADDREF_THIS();
36 0 : } // ctor
37 :
38 0 : nsPrintPreviewListener::~nsPrintPreviewListener()
39 : {
40 0 : }
41 :
42 : //-------------------------------------------------------
43 : //
44 : // AddListeners
45 : //
46 : // Subscribe to the events that will allow us to track various events.
47 : //
48 : nsresult
49 0 : nsPrintPreviewListener::AddListeners()
50 : {
51 0 : if (mEventTarget) {
52 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("click"), this, true);
53 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
54 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"), this, true);
55 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("keypress"), this, true);
56 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("keyup"), this, true);
57 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true);
58 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this, true);
59 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true);
60 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true);
61 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true);
62 :
63 0 : mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("keydown"),
64 0 : this, true);
65 : }
66 :
67 0 : return NS_OK;
68 : }
69 :
70 :
71 : //-------------------------------------------------------
72 : //
73 : // RemoveListeners
74 : //
75 : // Unsubscribe from all the various events that we were listening to.
76 : //
77 : nsresult
78 0 : nsPrintPreviewListener::RemoveListeners()
79 : {
80 0 : if (mEventTarget) {
81 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("click"), this, true);
82 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
83 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true);
84 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true);
85 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
86 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true);
87 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, true);
88 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, true);
89 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, true);
90 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true);
91 :
92 0 : mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"),
93 0 : this, true);
94 : }
95 :
96 0 : return NS_OK;
97 : }
98 :
99 : //-------------------------------------------------------
100 : //
101 : // GetActionForEvent
102 : //
103 : // Helper function to let certain key events through
104 : //
105 : enum eEventAction {
106 : eEventAction_Tab, eEventAction_ShiftTab,
107 : eEventAction_Propagate, eEventAction_Suppress,
108 : eEventAction_StopPropagation
109 : };
110 :
111 : static eEventAction
112 0 : GetActionForEvent(nsIDOMEvent* aEvent)
113 : {
114 : WidgetKeyboardEvent* keyEvent =
115 0 : aEvent->WidgetEventPtr()->AsKeyboardEvent();
116 0 : if (!keyEvent) {
117 0 : return eEventAction_Suppress;
118 : }
119 :
120 0 : if (keyEvent->mFlags.mInSystemGroup) {
121 0 : NS_ASSERTION(keyEvent->mMessage == eKeyDown,
122 : "Assuming we're listening only keydown event in system group");
123 0 : return eEventAction_StopPropagation;
124 : }
125 :
126 0 : if (keyEvent->IsAlt() || keyEvent->IsControl() || keyEvent->IsMeta()) {
127 : // Don't consume keydown event because following keypress event may be
128 : // handled as access key or shortcut key.
129 0 : return (keyEvent->mMessage == eKeyDown) ? eEventAction_StopPropagation :
130 0 : eEventAction_Suppress;
131 : }
132 :
133 : static const uint32_t kOKKeyCodes[] = {
134 : NS_VK_PAGE_UP, NS_VK_PAGE_DOWN,
135 : NS_VK_UP, NS_VK_DOWN,
136 : NS_VK_HOME, NS_VK_END
137 : };
138 :
139 0 : if (keyEvent->mKeyCode == NS_VK_TAB) {
140 0 : return keyEvent->IsShift() ? eEventAction_ShiftTab : eEventAction_Tab;
141 : }
142 :
143 0 : if (keyEvent->mCharCode == ' ' || keyEvent->mKeyCode == NS_VK_SPACE) {
144 0 : return eEventAction_Propagate;
145 : }
146 :
147 0 : if (keyEvent->IsShift()) {
148 0 : return eEventAction_Suppress;
149 : }
150 :
151 0 : for (uint32_t i = 0; i < ArrayLength(kOKKeyCodes); ++i) {
152 0 : if (keyEvent->mKeyCode == kOKKeyCodes[i]) {
153 0 : return eEventAction_Propagate;
154 : }
155 : }
156 :
157 0 : return eEventAction_Suppress;
158 : }
159 :
160 : NS_IMETHODIMP
161 0 : nsPrintPreviewListener::HandleEvent(nsIDOMEvent* aEvent)
162 : {
163 : nsCOMPtr<nsIContent> content = do_QueryInterface(
164 0 : aEvent ? aEvent->InternalDOMEvent()->GetOriginalTarget() : nullptr);
165 0 : if (content && !content->IsXULElement()) {
166 0 : eEventAction action = ::GetActionForEvent(aEvent);
167 0 : switch (action) {
168 : case eEventAction_Tab:
169 : case eEventAction_ShiftTab:
170 : {
171 0 : nsAutoString eventString;
172 0 : aEvent->GetType(eventString);
173 0 : if (eventString.EqualsLiteral("keydown")) {
174 : // Handle tabbing explicitly here since we don't want focus ending up
175 : // inside the content document, bug 244128.
176 0 : nsIDocument* doc = content->GetUncomposedDoc();
177 0 : NS_ASSERTION(doc, "no document");
178 :
179 0 : nsIDocument* parentDoc = doc->GetParentDocument();
180 0 : NS_ASSERTION(parentDoc, "no parent document");
181 :
182 0 : nsCOMPtr<nsPIDOMWindowOuter> win = parentDoc->GetWindow();
183 :
184 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
185 0 : if (fm && win) {
186 0 : dom::Element* fromElement = parentDoc->FindContentForSubDocument(doc);
187 0 : nsCOMPtr<nsIDOMElement> from = do_QueryInterface(fromElement);
188 :
189 0 : bool forward = (action == eEventAction_Tab);
190 0 : nsCOMPtr<nsIDOMElement> result;
191 0 : fm->MoveFocus(win, from,
192 : forward ? nsIFocusManager::MOVEFOCUS_FORWARD :
193 : nsIFocusManager::MOVEFOCUS_BACKWARD,
194 0 : nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
195 : }
196 : }
197 : }
198 : MOZ_FALLTHROUGH;
199 : case eEventAction_Suppress:
200 0 : aEvent->StopPropagation();
201 0 : aEvent->PreventDefault();
202 0 : break;
203 : case eEventAction_StopPropagation:
204 0 : aEvent->StopPropagation();
205 0 : break;
206 : case eEventAction_Propagate:
207 : // intentionally empty
208 0 : break;
209 : }
210 : }
211 0 : return NS_OK;
212 : }
|