diff options
Diffstat (limited to 'dom/xbl/nsXBLEventHandler.cpp')
-rw-r--r-- | dom/xbl/nsXBLEventHandler.cpp | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/dom/xbl/nsXBLEventHandler.cpp b/dom/xbl/nsXBLEventHandler.cpp new file mode 100644 index 000000000..6a873cf3b --- /dev/null +++ b/dom/xbl/nsXBLEventHandler.cpp @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "nsCOMPtr.h" +#include "nsIAtom.h" +#include "nsIDOMEventListener.h" +#include "nsIDOMKeyEvent.h" +#include "nsIDOMMouseEvent.h" +#include "nsXBLPrototypeHandler.h" +#include "nsContentUtils.h" +#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() +#include "mozilla/dom/EventTarget.h" +#include "mozilla/TextEvents.h" + +using namespace mozilla; +using namespace mozilla::dom; + +nsXBLEventHandler::nsXBLEventHandler(nsXBLPrototypeHandler* aHandler) + : mProtoHandler(aHandler) +{ +} + +nsXBLEventHandler::~nsXBLEventHandler() +{ +} + +NS_IMPL_ISUPPORTS(nsXBLEventHandler, nsIDOMEventListener) + +NS_IMETHODIMP +nsXBLEventHandler::HandleEvent(nsIDOMEvent* aEvent) +{ + if (!mProtoHandler) + return NS_ERROR_FAILURE; + + uint8_t phase = mProtoHandler->GetPhase(); + if (phase == NS_PHASE_TARGET) { + uint16_t eventPhase; + aEvent->GetEventPhase(&eventPhase); + if (eventPhase != nsIDOMEvent::AT_TARGET) + return NS_OK; + } + + if (!EventMatched(aEvent)) + return NS_OK; + + mProtoHandler->ExecuteHandler(aEvent->InternalDOMEvent()->GetCurrentTarget(), + aEvent); + + return NS_OK; +} + +nsXBLMouseEventHandler::nsXBLMouseEventHandler(nsXBLPrototypeHandler* aHandler) + : nsXBLEventHandler(aHandler) +{ +} + +nsXBLMouseEventHandler::~nsXBLMouseEventHandler() +{ +} + +bool +nsXBLMouseEventHandler::EventMatched(nsIDOMEvent* aEvent) +{ + nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aEvent)); + return mouse && mProtoHandler->MouseEventMatched(mouse); +} + +nsXBLKeyEventHandler::nsXBLKeyEventHandler(nsIAtom* aEventType, uint8_t aPhase, + uint8_t aType) + : mEventType(aEventType), + mPhase(aPhase), + mType(aType), + mIsBoundToChrome(false), + mUsingContentXBLScope(false) +{ +} + +nsXBLKeyEventHandler::~nsXBLKeyEventHandler() +{ +} + +NS_IMPL_ISUPPORTS(nsXBLKeyEventHandler, nsIDOMEventListener) + +bool +nsXBLKeyEventHandler::ExecuteMatchedHandlers( + nsIDOMKeyEvent* aKeyEvent, + uint32_t aCharCode, + const IgnoreModifierState& aIgnoreModifierState) +{ + WidgetEvent* event = aKeyEvent->AsEvent()->WidgetEventPtr(); + nsCOMPtr<EventTarget> target = aKeyEvent->AsEvent()->InternalDOMEvent()->GetCurrentTarget(); + + bool executed = false; + for (uint32_t i = 0; i < mProtoHandlers.Length(); ++i) { + nsXBLPrototypeHandler* handler = mProtoHandlers[i]; + bool hasAllowUntrustedAttr = handler->HasAllowUntrustedAttr(); + if ((event->IsTrusted() || + (hasAllowUntrustedAttr && handler->AllowUntrustedEvents()) || + (!hasAllowUntrustedAttr && !mIsBoundToChrome && !mUsingContentXBLScope)) && + handler->KeyEventMatched(aKeyEvent, aCharCode, aIgnoreModifierState)) { + handler->ExecuteHandler(target, aKeyEvent->AsEvent()); + executed = true; + } + } +#ifdef XP_WIN + // Windows native applications ignore Windows-Logo key state when checking + // shortcut keys even if the key is pressed. Therefore, if there is no + // shortcut key which exactly matches current modifier state, we should + // retry to look for a shortcut key without the Windows-Logo key press. + if (!executed && !aIgnoreModifierState.mOS) { + WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent(); + if (keyEvent && keyEvent->IsOS()) { + IgnoreModifierState ignoreModifierState(aIgnoreModifierState); + ignoreModifierState.mOS = true; + return ExecuteMatchedHandlers(aKeyEvent, aCharCode, ignoreModifierState); + } + } +#endif + return executed; +} + +NS_IMETHODIMP +nsXBLKeyEventHandler::HandleEvent(nsIDOMEvent* aEvent) +{ + uint32_t count = mProtoHandlers.Length(); + if (count == 0) + return NS_ERROR_FAILURE; + + if (mPhase == NS_PHASE_TARGET) { + uint16_t eventPhase; + aEvent->GetEventPhase(&eventPhase); + if (eventPhase != nsIDOMEvent::AT_TARGET) + return NS_OK; + } + + nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent)); + if (!key) + return NS_OK; + + WidgetKeyboardEvent* nativeKeyboardEvent = + aEvent->WidgetEventPtr()->AsKeyboardEvent(); + MOZ_ASSERT(nativeKeyboardEvent); + AutoShortcutKeyCandidateArray shortcutKeys; + nativeKeyboardEvent->GetShortcutKeyCandidates(shortcutKeys); + + if (shortcutKeys.IsEmpty()) { + ExecuteMatchedHandlers(key, 0, IgnoreModifierState()); + return NS_OK; + } + + for (uint32_t i = 0; i < shortcutKeys.Length(); ++i) { + IgnoreModifierState ignoreModifierState; + ignoreModifierState.mShift = shortcutKeys[i].mIgnoreShift; + if (ExecuteMatchedHandlers(key, shortcutKeys[i].mCharCode, + ignoreModifierState)) { + return NS_OK; + } + } + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////////// + +already_AddRefed<nsXBLEventHandler> +NS_NewXBLEventHandler(nsXBLPrototypeHandler* aHandler, + nsIAtom* aEventType) +{ + RefPtr<nsXBLEventHandler> handler; + + switch (nsContentUtils::GetEventClassID(nsDependentAtomString(aEventType))) { + case eDragEventClass: + case eMouseEventClass: + case eMouseScrollEventClass: + case eWheelEventClass: + case eSimpleGestureEventClass: + handler = new nsXBLMouseEventHandler(aHandler); + break; + default: + handler = new nsXBLEventHandler(aHandler); + break; + } + + return handler.forget(); +} |