diff options
Diffstat (limited to 'layout/printing/nsPrintPreviewListener.cpp')
-rw-r--r-- | layout/printing/nsPrintPreviewListener.cpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/layout/printing/nsPrintPreviewListener.cpp b/layout/printing/nsPrintPreviewListener.cpp new file mode 100644 index 000000000..000aad7b9 --- /dev/null +++ b/layout/printing/nsPrintPreviewListener.cpp @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPrintPreviewListener.h" + +#include "mozilla/dom/Element.h" +#include "nsDOMEvent.h" +#include "nsIDOMWindow.h" +#include "nsPIDOMWindow.h" +#include "nsIDOMElement.h" +#include "nsIDOMKeyEvent.h" +#include "nsIDOMEvent.h" +#include "nsIDocument.h" +#include "nsIDocShell.h" +#include "nsPresContext.h" +#include "nsFocusManager.h" +#include "nsLiteralString.h" + +using namespace mozilla; +using namespace mozilla::dom; + +NS_IMPL_ISUPPORTS1(nsPrintPreviewListener, nsIDOMEventListener) + + +// +// nsPrintPreviewListener ctor +// +nsPrintPreviewListener::nsPrintPreviewListener(EventTarget* aTarget) + : mEventTarget(aTarget) +{ + NS_ADDREF_THIS(); +} // ctor + + +//------------------------------------------------------- +// +// AddListeners +// +// Subscribe to the events that will allow us to track various events. +// +nsresult +nsPrintPreviewListener::AddListeners() +{ + if (mEventTarget) { + mEventTarget->AddEventListener(NS_LITERAL_STRING("click"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("keypress"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("keyup"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true); + mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true); + } + + return NS_OK; +} + + +//------------------------------------------------------- +// +// RemoveListeners +// +// Unsubscribe from all the various events that we were listening to. +// +nsresult +nsPrintPreviewListener::RemoveListeners() +{ + if (mEventTarget) { + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("click"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, true); + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true); + } + + return NS_OK; +} + +//------------------------------------------------------- +// +// GetActionForEvent +// +// Helper function to let certain key events through +// +enum eEventAction { + eEventAction_Tab, eEventAction_ShiftTab, + eEventAction_Propagate, eEventAction_Suppress +}; + +static eEventAction +GetActionForEvent(nsIDOMEvent* aEvent) +{ + static const uint32_t kOKKeyCodes[] = { + nsIDOMKeyEvent::DOM_VK_PAGE_UP, nsIDOMKeyEvent::DOM_VK_PAGE_DOWN, + nsIDOMKeyEvent::DOM_VK_UP, nsIDOMKeyEvent::DOM_VK_DOWN, + nsIDOMKeyEvent::DOM_VK_HOME, nsIDOMKeyEvent::DOM_VK_END + }; + + nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent)); + if (keyEvent) { + bool b; + keyEvent->GetAltKey(&b); + if (b) return eEventAction_Suppress; + keyEvent->GetCtrlKey(&b); + if (b) return eEventAction_Suppress; + + keyEvent->GetShiftKey(&b); + + uint32_t keyCode; + keyEvent->GetKeyCode(&keyCode); + if (keyCode == nsIDOMKeyEvent::DOM_VK_TAB) + return b ? eEventAction_ShiftTab : eEventAction_Tab; + + uint32_t charCode; + keyEvent->GetCharCode(&charCode); + if (charCode == ' ' || keyCode == nsIDOMKeyEvent::DOM_VK_SPACE) + return eEventAction_Propagate; + + if (b) return eEventAction_Suppress; + + for (uint32_t i = 0; i < sizeof(kOKKeyCodes)/sizeof(kOKKeyCodes[0]); ++i) { + if (keyCode == kOKKeyCodes[i]) { + return eEventAction_Propagate; + } + } + } + return eEventAction_Suppress; +} + +NS_IMETHODIMP +nsPrintPreviewListener::HandleEvent(nsIDOMEvent* aEvent) +{ + nsCOMPtr<nsIContent> content = do_QueryInterface( + aEvent ? aEvent->InternalDOMEvent()->GetOriginalTarget() : nullptr); + if (content && !content->IsXUL()) { + eEventAction action = ::GetActionForEvent(aEvent); + switch (action) { + case eEventAction_Tab: + case eEventAction_ShiftTab: + { + nsAutoString eventString; + aEvent->GetType(eventString); + if (eventString == NS_LITERAL_STRING("keydown")) { + // Handle tabbing explicitly here since we don't want focus ending up + // inside the content document, bug 244128. + nsIDocument* doc = content->GetCurrentDoc(); + NS_ASSERTION(doc, "no document"); + + nsIDocument* parentDoc = doc->GetParentDocument(); + NS_ASSERTION(parentDoc, "no parent document"); + + nsCOMPtr<nsIDOMWindow> win = do_QueryInterface(parentDoc->GetWindow()); + + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); + if (fm && win) { + dom::Element* fromElement = parentDoc->FindContentForSubDocument(doc); + nsCOMPtr<nsIDOMElement> from = do_QueryInterface(fromElement); + + bool forward = (action == eEventAction_Tab); + nsCOMPtr<nsIDOMElement> result; + fm->MoveFocus(win, from, + forward ? nsIFocusManager::MOVEFOCUS_FORWARD : + nsIFocusManager::MOVEFOCUS_BACKWARD, + nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result)); + } + } + } + // fall-through + case eEventAction_Suppress: + aEvent->StopPropagation(); + aEvent->PreventDefault(); + break; + case eEventAction_Propagate: + // intentionally empty + break; + } + } + return NS_OK; +} |