Bug 731878 part.1 Implement D3E initMouseEvent() and getModifierState() but they shouldn't be public r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 25 Apr 2012 12:00:01 +0900
changeset 96433 ac852666763d0a4e441d82e8a448a4e51262cdd3
parent 96432 2cb86715d29af8163af509f83b71ebd92da312c0
child 96434 392cb8e0876ffe17d92184b020e4e6666fa9e3ee
push id1116
push userlsblakk@mozilla.com
push dateMon, 16 Jul 2012 19:38:18 +0000
treeherdermozilla-beta@95f959a8b4dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs731878
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 731878 part.1 Implement D3E initMouseEvent() and getModifierState() but they shouldn't be public r=smaug
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMMouseEvent.cpp
content/events/src/nsDOMMouseEvent.h
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
layout/base/nsPresShell.cpp
widget/nsEvent.h
widget/nsGUIEvent.h
widget/nsGUIEventIPC.h
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -690,16 +690,17 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
         new nsMouseEvent(false, msg, nsnull, oldMouseEvent->reason);
       NS_ENSURE_TRUE(mouseEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
       mouseEvent->clickCount = oldMouseEvent->clickCount;
       mouseEvent->acceptActivation = oldMouseEvent->acceptActivation;
       mouseEvent->context = oldMouseEvent->context;
       mouseEvent->relatedTarget = oldMouseEvent->relatedTarget;
       mouseEvent->button = oldMouseEvent->button;
+      mouseEvent->modifiers = oldMouseEvent->modifiers;
       mouseEvent->pressure = oldMouseEvent->pressure;
       mouseEvent->inputSource = oldMouseEvent->inputSource;
       newEvent = mouseEvent;
       break;
     }
     case NS_DRAG_EVENT:
     {
       nsDragEvent* oldDragEvent = static_cast<nsDragEvent*>(mEvent);
@@ -707,16 +708,17 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
         new nsDragEvent(false, msg, nsnull);
       NS_ENSURE_TRUE(dragEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
       dragEvent->dataTransfer = oldDragEvent->dataTransfer;
       dragEvent->clickCount = oldDragEvent->clickCount;
       dragEvent->acceptActivation = oldDragEvent->acceptActivation;
       dragEvent->relatedTarget = oldDragEvent->relatedTarget;
       dragEvent->button = oldDragEvent->button;
+      dragEvent->modifiers = oldDragEvent->modifiers;
       static_cast<nsMouseEvent*>(dragEvent)->inputSource =
         static_cast<nsMouseEvent*>(oldDragEvent)->inputSource;
       newEvent = dragEvent;
       break;
     }
     case NS_SCRIPT_ERROR_EVENT:
     {
       newEvent = new nsScriptErrorEvent(false, msg);
@@ -748,16 +750,17 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
       NS_ENSURE_TRUE(mouseScrollEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
       nsMouseScrollEvent* oldMouseScrollEvent =
         static_cast<nsMouseScrollEvent*>(mEvent);
       mouseScrollEvent->scrollFlags = oldMouseScrollEvent->scrollFlags;
       mouseScrollEvent->delta = oldMouseScrollEvent->delta;
       mouseScrollEvent->relatedTarget = oldMouseScrollEvent->relatedTarget;
       mouseScrollEvent->button = oldMouseScrollEvent->button;
+      mouseScrollEvent->modifiers = oldMouseScrollEvent->modifiers;
       static_cast<nsMouseEvent_base*>(mouseScrollEvent)->inputSource =
         static_cast<nsMouseEvent_base*>(oldMouseScrollEvent)->inputSource;
       newEvent = mouseScrollEvent;
       break;
     }
     case NS_SCROLLPORT_EVENT:
     {
       newEvent = new nsScrollPortEvent(false, msg, nsnull);
@@ -858,16 +861,17 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
     }
     case NS_SIMPLE_GESTURE_EVENT:
     {
       nsSimpleGestureEvent* oldSimpleGestureEvent = static_cast<nsSimpleGestureEvent*>(mEvent);
       nsSimpleGestureEvent* simpleGestureEvent = 
         new nsSimpleGestureEvent(false, msg, nsnull, 0, 0.0);
       NS_ENSURE_TRUE(simpleGestureEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
+      simpleGestureEvent->modifiers = oldSimpleGestureEvent->modifiers;
       simpleGestureEvent->direction = oldSimpleGestureEvent->direction;
       simpleGestureEvent->delta = oldSimpleGestureEvent->delta;
       newEvent = simpleGestureEvent;
       break;
     }
     case NS_TRANSITION_EVENT:
     {
       nsTransitionEvent* oldTransitionEvent =
@@ -885,20 +889,24 @@ NS_METHOD nsDOMEvent::DuplicatePrivateDa
       newEvent = new nsAnimationEvent(false, msg,
                                       oldAnimationEvent->animationName,
                                       oldAnimationEvent->elapsedTime);
       NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
       break;
     }
     case NS_MOZTOUCH_EVENT:
     {
-      newEvent = new nsMozTouchEvent(false, msg, nsnull,
-                                     static_cast<nsMozTouchEvent*>(mEvent)->streamId);
-      NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
+      nsMozTouchEvent* oldMozTouchEvent = static_cast<nsMozTouchEvent*>(mEvent);
+      nsMozTouchEvent* mozTouchEvent =
+        new nsMozTouchEvent(false, msg, nsnull,
+                            static_cast<nsMozTouchEvent*>(mEvent)->streamId);
+      NS_ENSURE_TRUE(mozTouchEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
+      mozTouchEvent->modifiers = oldMozTouchEvent->modifiers;
+      newEvent = mozTouchEvent;
       break;
     }
     case NS_TOUCH_EVENT:
     {
       nsTouchEvent *oldTouchEvent = static_cast<nsTouchEvent*>(mEvent);
       newEvent = new nsTouchEvent(false, oldTouchEvent);
       NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -38,16 +38,18 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMMouseEvent.h"
 #include "nsGUIEvent.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
 #include "DictionaryHelpers.h"
 
+using namespace mozilla;
+
 nsDOMMouseEvent::nsDOMMouseEvent(nsPresContext* aPresContext,
                                  nsInputEvent* aEvent)
   : nsDOMUIEvent(aPresContext, aEvent ? aEvent :
                  new nsMouseEvent(false, 0, nsnull,
                                   nsMouseEvent::eReal))
 {
   // There's no way to make this class' ctor allocate an nsMouseScrollEvent.
   // It's not that important, though, since a scroll event is not a real
@@ -141,16 +143,55 @@ nsDOMMouseEvent::InitMouseEvent(const ns
     default:
        break;
   }
 
   return NS_OK;
 }   
 
 nsresult
+nsDOMMouseEvent::InitMouseEvent(const nsAString& aType,
+                                bool aCanBubble,
+                                bool aCancelable,
+                                nsIDOMWindow* aView,
+                                PRInt32 aDetail,
+                                PRInt32 aScreenX,
+                                PRInt32 aScreenY,
+                                PRInt32 aClientX,
+                                PRInt32 aClientY,
+                                PRUint16 aButton,
+                                nsIDOMEventTarget *aRelatedTarget,
+                                const nsAString& aModifiersList)
+{
+  Modifiers modifiers = ComputeModifierState(aModifiersList);
+
+  nsresult rv = InitMouseEvent(aType, aCanBubble, aCancelable, aView,
+                               aDetail, aScreenX, aScreenY, aClientX, aClientY,
+                               (modifiers & widget::MODIFIER_CONTROL) != 0,
+                               (modifiers & widget::MODIFIER_ALT) != 0,
+                               (modifiers & widget::MODIFIER_SHIFT) != 0,
+                               (modifiers & widget::MODIFIER_META) != 0,
+                               aButton, aRelatedTarget);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  switch(mEvent->eventStructType) {
+    case NS_MOUSE_EVENT:
+    case NS_MOUSE_SCROLL_EVENT:
+    case NS_DRAG_EVENT:
+    case NS_SIMPLE_GESTURE_EVENT:
+    case NS_MOZTOUCH_EVENT:
+      static_cast<nsMouseEvent_base*>(mEvent)->modifiers = modifiers;
+      return NS_OK;
+    default:
+      MOZ_NOT_REACHED("There is no space to store the modifiers");
+      return NS_ERROR_FAILURE;
+  }
+}
+
+nsresult
 nsDOMMouseEvent::InitFromCtor(const nsAString& aType,
                               JSContext* aCx, jsval* aVal)
 {
   mozilla::dom::MouseEventInit d;
   nsresult rv = d.Init(aCx, aVal);
   NS_ENSURE_SUCCESS(rv, rv);
   return InitMouseEvent(aType, d.bubbles, d.cancelable,
                         d.view, d.detail, d.screenX, d.screenY,
--- a/content/events/src/nsDOMMouseEvent.h
+++ b/content/events/src/nsDOMMouseEvent.h
@@ -60,15 +60,28 @@ public:
   // Forward to base class
   NS_FORWARD_TO_NSDOMUIEVENT
 
   virtual nsresult InitFromCtor(const nsAString& aType,
                                 JSContext* aCx, jsval* aVal);
 protected:
   // Specific implementation for a mouse event.
   virtual nsresult Which(PRUint32* aWhich);
+
+  nsresult InitMouseEvent(const nsAString& aType,
+                          bool aCanBubble,
+                          bool aCancelable,
+                          nsIDOMWindow* aView,
+                          PRInt32 aDetail,
+                          PRInt32 aScreenX,
+                          PRInt32 aScreenY,
+                          PRInt32 aClientX,
+                          PRInt32 aClientY,
+                          PRUint16 aButton,
+                          nsIDOMEventTarget *aRelatedTarget,
+                          const nsAString& aModifiersList);
 };
 
 #define NS_FORWARD_TO_NSDOMMOUSEEVENT         \
   NS_FORWARD_NSIDOMMOUSEEVENT(nsDOMMouseEvent::) \
   NS_FORWARD_TO_NSDOMUIEVENT
 
 #endif // nsDOMMouseEvent_h__
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -46,16 +46,20 @@
 #include "nsIDOMWindow.h"
 #include "nsIDOMNode.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
 #include "nsEventStateManager.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
 #include "DictionaryHelpers.h"
+#include "mozilla/Util.h"
+#include "mozilla/Assertions.h"
+
+using namespace mozilla;
 
 nsDOMUIEvent::nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent)
   : nsDOMEvent(aPresContext, aEvent ?
                static_cast<nsEvent *>(aEvent) :
                static_cast<nsEvent *>(new nsUIEvent(false, 0, 0)))
   , mClientPoint(0, 0), mLayerPoint(0, 0), mPagePoint(0, 0)
   , mIsPointerLocked(nsEventStateManager::sIsPointerLocked)
   , mLastScreenPoint(nsEventStateManager::sLastScreenPoint)
@@ -442,15 +446,129 @@ nsDOMUIEvent::Serialize(IPC::Message* aM
 bool
 nsDOMUIEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
 {
   NS_ENSURE_TRUE(nsDOMEvent::Deserialize(aMsg, aIter), false);
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &mDetail), false);
   return true;
 }
 
+// XXX Following struct and array are used only in
+//     nsDOMUIEvent::ComputeModifierState(), but if we define them in it,
+//     we fail to build on Mac at calling mozilla::ArrayLength().
+struct nsModifierPair
+{
+  mozilla::widget::Modifier modifier;
+  const char* name;
+};
+static const nsModifierPair kPairs[] = {
+  { widget::MODIFIER_ALT,        NS_DOM_KEYNAME_ALT },
+  { widget::MODIFIER_ALTGRAPH,   NS_DOM_KEYNAME_ALTGRAPH },
+  { widget::MODIFIER_CAPSLOCK,   NS_DOM_KEYNAME_CAPSLOCK },
+  { widget::MODIFIER_CONTROL,    NS_DOM_KEYNAME_CONTROL },
+  { widget::MODIFIER_FN,         NS_DOM_KEYNAME_FN },
+  { widget::MODIFIER_META,       NS_DOM_KEYNAME_META },
+  { widget::MODIFIER_NUMLOCK,    NS_DOM_KEYNAME_NUMLOCK },
+  { widget::MODIFIER_SCROLL,     NS_DOM_KEYNAME_SCROLL },
+  { widget::MODIFIER_SHIFT,      NS_DOM_KEYNAME_SHIFT },
+  { widget::MODIFIER_SYMBOLLOCK, NS_DOM_KEYNAME_SYMBOLLOCK },
+  { widget::MODIFIER_WIN,        NS_DOM_KEYNAME_WIN }
+};
+
+/* static */
+mozilla::widget::Modifiers
+nsDOMUIEvent::ComputeModifierState(const nsAString& aModifiersList)
+{
+  if (aModifiersList.IsEmpty()) {
+    return 0;
+  }
+
+  // Be careful about the performance.  If aModifiersList is too long,
+  // parsing it needs too long time.
+  // XXX Should we abort if aModifiersList is too long?
+
+  Modifiers modifiers = 0;
+
+  nsAString::const_iterator listStart, listEnd;
+  aModifiersList.BeginReading(listStart);
+  aModifiersList.EndReading(listEnd);
+
+  for (PRUint32 i = 0; i < mozilla::ArrayLength(kPairs); i++) {
+    nsAString::const_iterator start(listStart), end(listEnd);
+    if (!FindInReadable(NS_ConvertASCIItoUTF16(kPairs[i].name), start, end)) {
+      continue;
+    }
+
+    if ((start != listStart && !NS_IsAsciiWhitespace(*(--start))) ||
+        (end != listEnd && !NS_IsAsciiWhitespace(*(end)))) {
+      continue;
+    }
+    modifiers |= kPairs[i].modifier;
+  }
+
+  return modifiers;
+}
+
+bool
+nsDOMUIEvent::GetModifierStateInternal(const nsAString& aKey)
+{
+  mozilla::widget::Modifiers modifiers = 0;
+  switch(mEvent->eventStructType) {
+    case NS_MOUSE_EVENT:
+    case NS_MOUSE_SCROLL_EVENT:
+    case NS_DRAG_EVENT:
+    case NS_SIMPLE_GESTURE_EVENT:
+    case NS_MOZTOUCH_EVENT:
+      modifiers = static_cast<nsMouseEvent_base*>(mEvent)->modifiers;
+      break;
+    default:
+      MOZ_NOT_REACHED("There is no space to store the modifiers");
+      return false;
+  }
+
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SHIFT)) {
+    return static_cast<nsInputEvent*>(mEvent)->isShift;
+  }
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_CONTROL)) {
+    return static_cast<nsInputEvent*>(mEvent)->isControl;
+  }
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_META)) {
+    return static_cast<nsInputEvent*>(mEvent)->isMeta;
+  }
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_ALT)) {
+    return static_cast<nsInputEvent*>(mEvent)->isAlt;
+  }
+
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_ALTGRAPH)) {
+    return (modifiers & widget::MODIFIER_ALTGRAPH) != 0;
+  }
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_WIN)) {
+    return (modifiers & widget::MODIFIER_WIN) != 0;
+  }
+
+
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_CAPSLOCK)) {
+    return (modifiers & widget::MODIFIER_CAPSLOCK) != 0;
+  }
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_NUMLOCK)) {
+    return (modifiers & widget::MODIFIER_NUMLOCK) != 0;
+  }
+
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_FN)) {
+    return (modifiers & widget::MODIFIER_FN) != 0;
+  }
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SCROLL)) {
+    return (modifiers & widget::MODIFIER_SCROLL) != 0;
+  }
+  if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SYMBOLLOCK)) {
+    return (modifiers & widget::MODIFIER_SYMBOLLOCK) != 0;
+  }
+  return false;
+}
+
+
 nsresult NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult,
                           nsPresContext* aPresContext,
                           nsGUIEvent *aEvent) 
 {
   nsDOMUIEvent* it = new nsDOMUIEvent(aPresContext, aEvent);
   return CallQueryInterface(it, aInstancePtrResult);
 }
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsDOMUIEvent_h
 #define nsDOMUIEvent_h
 
 #include "nsIDOMUIEvent.h"
 #include "nsDOMEvent.h"
 #include "nsLayoutUtils.h"
+#include "nsEvent.h"
 
 class nsDOMUIEvent : public nsDOMEvent,
                      public nsIDOMUIEvent
 {
 public:
   nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent);
 
   NS_DECL_ISUPPORTS_INHERITED
@@ -145,15 +146,19 @@ protected:
   nsIntPoint mClientPoint;
   // Screenpoint is mEvent->refPoint.
   nsIntPoint mLayerPoint;
   nsIntPoint mPagePoint;
   nsIntPoint mMovement;
   bool mIsPointerLocked;
   nsIntPoint mLastScreenPoint;
   nsIntPoint mLastClientPoint;
+
+  typedef mozilla::widget::Modifiers Modifiers;
+  static Modifiers ComputeModifierState(const nsAString& aModifiersList);
+  bool GetModifierStateInternal(const nsAString& aKey);
 };
 
 #define NS_FORWARD_TO_NSDOMUIEVENT \
   NS_FORWARD_NSIDOMUIEVENT(nsDOMUIEvent::) \
   NS_FORWARD_TO_NSDOMEVENT
 
 #endif // nsDOMUIEvent_h
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -2003,16 +2003,17 @@ nsEventStateManager::BeginTrackingDragGe
   inDownFrame->GetContentForEvent(inDownEvent,
                                   getter_AddRefs(mGestureDownContent));
 
   mGestureDownFrameOwner = inDownFrame->GetContent();
   mGestureDownShift = inDownEvent->isShift;
   mGestureDownControl = inDownEvent->isControl;
   mGestureDownAlt = inDownEvent->isAlt;
   mGestureDownMeta = inDownEvent->isMeta;
+  mGestureModifiers = inDownEvent->modifiers;
 
   if (mClickHoldContextMenu) {
     // fire off a timer to track click-hold
     CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
   }
 }
 
 
@@ -2039,16 +2040,17 @@ nsEventStateManager::FillInEventFromGest
   // the old event, adjusted for the fact that the widget might be
   // different
   nsIntPoint tmpPoint = aEvent->widget->WidgetToScreenOffset();
   aEvent->refPoint = mGestureDownPoint - tmpPoint;
   aEvent->isShift = mGestureDownShift;
   aEvent->isControl = mGestureDownControl;
   aEvent->isAlt = mGestureDownAlt;
   aEvent->isMeta = mGestureDownMeta;
+  aEvent->modifiers = mGestureModifiers;
 }
 
 //
 // GenerateDragGesture
 //
 // If we're in the TRACKING state of the d&d gesture tracker, check the current position
 // of the mouse in relation to the old one. If we've moved a sufficient amount from
 // the mouse down, then fire off a drag gesture event.
@@ -2572,16 +2574,17 @@ nsEventStateManager::SendLineScrollEvent
   nsMouseScrollEvent event(isTrusted, NS_MOUSE_SCROLL, nsnull);
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.isShift = aEvent->isShift;
   event.isControl = aEvent->isControl;
   event.isAlt = aEvent->isAlt;
   event.isMeta = aEvent->isMeta;
+  event.modifiers = aEvent->modifiers;
   event.scrollFlags = aEvent->scrollFlags;
   event.delta = aNumLines;
   event.inputSource = static_cast<nsMouseEvent_base*>(aEvent)->inputSource;
 
   nsEventDispatcher::Dispatch(targetContent, aPresContext, &event, nsnull, aStatus);
 }
 
 void
@@ -2607,16 +2610,17 @@ nsEventStateManager::SendPixelScrollEven
   nsMouseScrollEvent event(isTrusted, NS_MOUSE_PIXEL_SCROLL, nsnull);
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.isShift = aEvent->isShift;
   event.isControl = aEvent->isControl;
   event.isAlt = aEvent->isAlt;
   event.isMeta = aEvent->isMeta;
+  event.modifiers = aEvent->modifiers;
   event.scrollFlags = aEvent->scrollFlags;
   event.inputSource = static_cast<nsMouseEvent_base*>(aEvent)->inputSource;
   event.delta = aPresContext->AppUnitsToIntCSSPixels(aEvent->delta * lineHeight);
 
   nsEventDispatcher::Dispatch(targetContent, aPresContext, &event, nsnull, aStatus);
 }
 
 PRInt32
@@ -3406,16 +3410,17 @@ nsEventStateManager::PostHandleEvent(nsP
         if (mouseEvent->widget) {
           event.refPoint += mouseEvent->widget->WidgetToScreenOffset();
         }
         event.refPoint -= widget->WidgetToScreenOffset();
         event.isShift = mouseEvent->isShift;
         event.isControl = mouseEvent->isControl;
         event.isAlt = mouseEvent->isAlt;
         event.isMeta = mouseEvent->isMeta;
+        event.modifiers = mouseEvent->modifiers;
         event.inputSource = mouseEvent->inputSource;
 
         nsEventStatus status = nsEventStatus_eIgnore;
         nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
         if (presShell) {
           presShell->HandleEventWithTarget(&event, mCurrentTarget,
                                            targetContent, &status);
         }
@@ -3831,16 +3836,17 @@ nsEventStateManager::DispatchMouseEvent(
   nsEventStatus status = nsEventStatus_eIgnore;
   nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent), aMessage, aEvent->widget,
                      nsMouseEvent::eReal);
   event.refPoint = aEvent->refPoint;
   event.isShift = ((nsMouseEvent*)aEvent)->isShift;
   event.isControl = ((nsMouseEvent*)aEvent)->isControl;
   event.isAlt = ((nsMouseEvent*)aEvent)->isAlt;
   event.isMeta = ((nsMouseEvent*)aEvent)->isMeta;
+  event.modifiers = ((nsMouseEvent*)aEvent)->modifiers;
   event.pluginEvent = ((nsMouseEvent*)aEvent)->pluginEvent;
   event.relatedTarget = aRelatedContent;
   event.inputSource = static_cast<nsMouseEvent*>(aEvent)->inputSource;
 
   nsWeakFrame previousTarget = mCurrentTarget;
 
   mCurrentTargetContent = aTargetContent;
 
@@ -4244,16 +4250,17 @@ nsEventStateManager::FireDragEnterOrExit
 {
   nsEventStatus status = nsEventStatus_eIgnore;
   nsDragEvent event(NS_IS_TRUSTED_EVENT(aEvent), aMsg, aEvent->widget);
   event.refPoint = aEvent->refPoint;
   event.isShift = ((nsMouseEvent*)aEvent)->isShift;
   event.isControl = ((nsMouseEvent*)aEvent)->isControl;
   event.isAlt = ((nsMouseEvent*)aEvent)->isAlt;
   event.isMeta = ((nsMouseEvent*)aEvent)->isMeta;
+  event.modifiers = ((nsMouseEvent*)aEvent)->modifiers;
   event.relatedTarget = aRelatedTarget;
   event.inputSource = static_cast<nsMouseEvent*>(aEvent)->inputSource;
 
   mCurrentTargetContent = aTargetContent;
 
   if (aTargetContent != aRelatedTarget) {
     //XXX This event should still go somewhere!!
     if (aTargetContent)
@@ -4406,16 +4413,17 @@ nsEventStateManager::CheckForAndDispatch
     nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent), NS_MOUSE_CLICK, aEvent->widget,
                        nsMouseEvent::eReal);
     event.refPoint = aEvent->refPoint;
     event.clickCount = aEvent->clickCount;
     event.isShift = aEvent->isShift;
     event.isControl = aEvent->isControl;
     event.isAlt = aEvent->isAlt;
     event.isMeta = aEvent->isMeta;
+    event.modifiers = aEvent->modifiers;
     event.time = aEvent->time;
     event.flags |= flags;
     event.button = aEvent->button;
     event.inputSource = aEvent->inputSource;
 
     nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
     if (presShell) {
       nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
@@ -4427,16 +4435,17 @@ nsEventStateManager::CheckForAndDispatch
         nsMouseEvent event2(NS_IS_TRUSTED_EVENT(aEvent), NS_MOUSE_DOUBLECLICK,
                             aEvent->widget, nsMouseEvent::eReal);
         event2.refPoint = aEvent->refPoint;
         event2.clickCount = aEvent->clickCount;
         event2.isShift = aEvent->isShift;
         event2.isControl = aEvent->isControl;
         event2.isAlt = aEvent->isAlt;
         event2.isMeta = aEvent->isMeta;
+        event2.modifiers = aEvent->modifiers;
         event2.flags |= flags;
         event2.button = aEvent->button;
         event2.inputSource = aEvent->inputSource;
 
         ret = presShell->HandleEventWithTarget(&event2, mCurrentTarget,
                                                mouseContent, aStatus);
       }
     }
@@ -5029,16 +5038,17 @@ nsEventStateManager::DoQueryScrollTarget
     NS_IS_TRUSTED_EVENT(aEvent->mInput.mMouseScrollEvent),
     aEvent->mInput.mMouseScrollEvent->message,
     aEvent->mInput.mMouseScrollEvent->widget);
 
   msEvent.isShift = aEvent->mInput.mMouseScrollEvent->isShift;
   msEvent.isControl = aEvent->mInput.mMouseScrollEvent->isControl;
   msEvent.isAlt = aEvent->mInput.mMouseScrollEvent->isAlt;
   msEvent.isMeta = aEvent->mInput.mMouseScrollEvent->isMeta;
+  msEvent.modifiers = aEvent->mInput.mMouseScrollEvent->modifiers;
 
   msEvent.scrollFlags = aEvent->mInput.mMouseScrollEvent->scrollFlags;
   msEvent.delta = ComputeWheelDeltaFor(aEvent->mInput.mMouseScrollEvent);
   msEvent.scrollOverflow = aEvent->mInput.mMouseScrollEvent->scrollOverflow;
 
   bool useSystemSettings = UseSystemScrollSettingFor(&msEvent);
 
   nsIScrollableFrame::ScrollUnit unit;
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -505,16 +505,17 @@ private:
   // as the target in most cases but not always - for example when dragging
   // an <area> of an image map this is the image. (bug 289667)
   nsCOMPtr<nsIContent> mGestureDownFrameOwner;
   // State of keys when the original gesture-down happened
   bool mGestureDownShift;
   bool mGestureDownControl;
   bool mGestureDownAlt;
   bool mGestureDownMeta;
+  mozilla::widget::Modifiers mGestureModifiers;
 
   nsCOMPtr<nsIContent> mLastLeftMouseDownContent;
   nsCOMPtr<nsIContent> mLastLeftMouseDownContentParent;
   nsCOMPtr<nsIContent> mLastMiddleMouseDownContent;
   nsCOMPtr<nsIContent> mLastMiddleMouseDownContentParent;
   nsCOMPtr<nsIContent> mLastRightMouseDownContent;
   nsCOMPtr<nsIContent> mLastRightMouseDownContentParent;
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5317,16 +5317,17 @@ PresShell::ProcessSynthMouseMoveEvent(bo
     refpoint += view->ViewToWidgetOffset();
   }
   NS_ASSERTION(view->GetWidget(), "view should have a widget here");
   nsMouseEvent event(true, NS_MOUSE_MOVE, view->GetWidget(),
                      nsMouseEvent::eSynthesized);
   event.refPoint = refpoint.ToNearestPixels(viewAPD);
   event.time = PR_IntervalNow();
   // XXX set event.isShift, event.isControl, event.isAlt, event.isMeta ?
+  // XXX mnakano I think that we should get the latest information from widget.
 
   nsCOMPtr<nsIPresShell> shell = pointVM->GetPresShell();
   if (shell) {
     shell->DispatchSynthMouseMove(&event, !aFromScroll);
   }
 
   if (!aFromScroll) {
     mSynthMouseMoveEvent.Forget();
--- a/widget/nsEvent.h
+++ b/widget/nsEvent.h
@@ -109,9 +109,45 @@ class nsFormEvent;
 class nsCommandEvent;
 class nsUIEvent;
 class nsSimpleGestureEvent;
 class nsTransitionEvent;
 class nsAnimationEvent;
 class nsUIStateChangeEvent;
 class nsPluginEvent;
 
+namespace mozilla {
+namespace widget {
+
+// All modifier keys should be defined here.  This is used for managing
+// modifier states for DOM Level 3 or later.
+enum Modifier {
+  MODIFIER_ALT        = 0x0001,
+  MODIFIER_ALTGRAPH   = 0x0002,
+  MODIFIER_CAPSLOCK   = 0x0004,
+  MODIFIER_CONTROL    = 0x0008,
+  MODIFIER_FN         = 0x0010,
+  MODIFIER_META       = 0x0020,
+  MODIFIER_NUMLOCK    = 0x0040,
+  MODIFIER_SCROLL     = 0x0080,
+  MODIFIER_SHIFT      = 0x0100,
+  MODIFIER_SYMBOLLOCK = 0x0200,
+  MODIFIER_WIN        = 0x0400
+};
+
+typedef PRUint16 Modifiers;
+
+} // namespace widget
+} // namespace mozilla
+
+#define NS_DOM_KEYNAME_ALT        "Alt"
+#define NS_DOM_KEYNAME_ALTGRAPH   "AltGraph"
+#define NS_DOM_KEYNAME_CAPSLOCK   "CapsLock"
+#define NS_DOM_KEYNAME_CONTROL    "Control"
+#define NS_DOM_KEYNAME_FN         "Fn"
+#define NS_DOM_KEYNAME_META       "Meta"
+#define NS_DOM_KEYNAME_NUMLOCK    "NumLock"
+#define NS_DOM_KEYNAME_SCROLL     "Scroll"
+#define NS_DOM_KEYNAME_SHIFT      "Shift"
+#define NS_DOM_KEYNAME_SYMBOLLOCK "SymbolLock"
+#define NS_DOM_KEYNAME_WIN        "Win"
+
 #endif // nsEvent_h__
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -858,24 +858,26 @@ private:
 
 public:
 
   nsMouseEvent_base()
   {
   }
 
   nsMouseEvent_base(bool isTrusted, PRUint32 msg, nsIWidget *w, PRUint8 type)
-    : nsInputEvent(isTrusted, msg, w, type), button(0), pressure(0)
-    , inputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE) {}
+    : nsInputEvent(isTrusted, msg, w, type), button(0), modifiers(0),
+      pressure(0), inputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE) {}
 
   /// The possible related target
   nsCOMPtr<nsISupports> relatedTarget;
 
   PRInt16               button;
 
+  mozilla::widget::Modifiers modifiers;
+
   // Finger or touch pressure of event
   // ranges between 0.0 and 1.0
   float                 pressure;
 
   // Possible values at nsIDOMMouseEvent
   PRUint16              inputSource;
 };
 
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -113,24 +113,26 @@ template<>
 struct ParamTraits<nsMouseEvent_base>
 {
   typedef nsMouseEvent_base paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, static_cast<nsInputEvent>(aParam));
     WriteParam(aMsg, aParam.button);
+    WriteParam(aMsg, aParam.modifiers);
     WriteParam(aMsg, aParam.pressure);
     WriteParam(aMsg, aParam.inputSource);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, static_cast<nsInputEvent*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->button) &&
+           ReadParam(aMsg, aIter, &aResult->modifiers) &&
            ReadParam(aMsg, aIter, &aResult->pressure) &&
            ReadParam(aMsg, aIter, &aResult->inputSource);
   }
 };
 
 template<>
 struct ParamTraits<nsMouseScrollEvent>
 {