1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "mozilla/dom/MouseEvent.h"
8 #include "mozilla/MouseEvents.h"
9 #include "nsContentUtils.h"
10 #include "nsIContent.h"
11 #include "prtime.h"
12 
13 namespace mozilla {
14 namespace dom {
15 
MouseEvent(EventTarget * aOwner,nsPresContext * aPresContext,WidgetMouseEventBase * aEvent)16 MouseEvent::MouseEvent(EventTarget* aOwner,
17                        nsPresContext* aPresContext,
18                        WidgetMouseEventBase* aEvent)
19   : UIEvent(aOwner, aPresContext,
20             aEvent ? aEvent :
21                      new WidgetMouseEvent(false, eVoidEvent, nullptr,
22                                           WidgetMouseEvent::eReal))
23 {
24   // There's no way to make this class' ctor allocate an WidgetMouseScrollEvent.
25   // It's not that important, though, since a scroll event is not a real
26   // DOM event.
27 
28   WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
29   if (aEvent) {
30     mEventIsInternal = false;
31   }
32   else {
33     mEventIsInternal = true;
34     mEvent->mTime = PR_Now();
35     mEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
36     mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
37   }
38 
39   if (mouseEvent) {
40     MOZ_ASSERT(mouseEvent->mReason != WidgetMouseEvent::eSynthesized,
41                "Don't dispatch DOM events from synthesized mouse events");
42     mDetail = mouseEvent->mClickCount;
43   }
44 }
45 
NS_IMPL_ADDREF_INHERITED(MouseEvent,UIEvent)46 NS_IMPL_ADDREF_INHERITED(MouseEvent, UIEvent)
47 NS_IMPL_RELEASE_INHERITED(MouseEvent, UIEvent)
48 
49 NS_INTERFACE_MAP_BEGIN(MouseEvent)
50   NS_INTERFACE_MAP_ENTRY(nsIDOMMouseEvent)
51 NS_INTERFACE_MAP_END_INHERITING(UIEvent)
52 
53 void
54 MouseEvent::InitMouseEvent(const nsAString& aType,
55                            bool aCanBubble,
56                            bool aCancelable,
57                            nsGlobalWindow* aView,
58                            int32_t aDetail,
59                            int32_t aScreenX,
60                            int32_t aScreenY,
61                            int32_t aClientX,
62                            int32_t aClientY,
63                            bool aCtrlKey,
64                            bool aAltKey,
65                            bool aShiftKey,
66                            bool aMetaKey,
67                            uint16_t aButton,
68                            EventTarget* aRelatedTarget)
69 {
70   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
71 
72   UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
73 
74   switch(mEvent->mClass) {
75     case eMouseEventClass:
76     case eMouseScrollEventClass:
77     case eWheelEventClass:
78     case eDragEventClass:
79     case ePointerEventClass:
80     case eSimpleGestureEventClass: {
81       WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
82       mouseEventBase->relatedTarget = aRelatedTarget;
83       mouseEventBase->button = aButton;
84       mouseEventBase->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
85       mClientPoint.x = aClientX;
86       mClientPoint.y = aClientY;
87       mouseEventBase->mRefPoint.x = aScreenX;
88       mouseEventBase->mRefPoint.y = aScreenY;
89 
90       WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
91       if (mouseEvent) {
92         mouseEvent->mClickCount = aDetail;
93       }
94       break;
95     }
96     default:
97        break;
98   }
99 }
100 
101 NS_IMETHODIMP
InitMouseEvent(const nsAString & aType,bool aCanBubble,bool aCancelable,mozIDOMWindow * aView,int32_t aDetail,int32_t aScreenX,int32_t aScreenY,int32_t aClientX,int32_t aClientY,bool aCtrlKey,bool aAltKey,bool aShiftKey,bool aMetaKey,uint16_t aButton,nsIDOMEventTarget * aRelatedTarget)102 MouseEvent::InitMouseEvent(const nsAString& aType,
103                            bool aCanBubble,
104                            bool aCancelable,
105                            mozIDOMWindow* aView,
106                            int32_t aDetail,
107                            int32_t aScreenX,
108                            int32_t aScreenY,
109                            int32_t aClientX,
110                            int32_t aClientY,
111                            bool aCtrlKey,
112                            bool aAltKey,
113                            bool aShiftKey,
114                            bool aMetaKey,
115                            uint16_t aButton,
116                            nsIDOMEventTarget* aRelatedTarget)
117 {
118   MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable,
119                              nsGlobalWindow::Cast(aView), aDetail,
120                              aScreenX, aScreenY,
121                              aClientX, aClientY,
122                              aCtrlKey, aAltKey, aShiftKey,
123                              aMetaKey, aButton,
124                              static_cast<EventTarget *>(aRelatedTarget));
125 
126   return NS_OK;
127 }
128 
129 void
InitMouseEvent(const nsAString & aType,bool aCanBubble,bool aCancelable,nsGlobalWindow * aView,int32_t aDetail,int32_t aScreenX,int32_t aScreenY,int32_t aClientX,int32_t aClientY,int16_t aButton,EventTarget * aRelatedTarget,const nsAString & aModifiersList)130 MouseEvent::InitMouseEvent(const nsAString& aType,
131                            bool aCanBubble,
132                            bool aCancelable,
133                            nsGlobalWindow* aView,
134                            int32_t aDetail,
135                            int32_t aScreenX,
136                            int32_t aScreenY,
137                            int32_t aClientX,
138                            int32_t aClientY,
139                            int16_t aButton,
140                            EventTarget* aRelatedTarget,
141                            const nsAString& aModifiersList)
142 {
143   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
144 
145   Modifiers modifiers = ComputeModifierState(aModifiersList);
146 
147   InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
148                  aScreenX, aScreenY, aClientX, aClientY,
149                  (modifiers & MODIFIER_CONTROL) != 0,
150                  (modifiers & MODIFIER_ALT) != 0,
151                  (modifiers & MODIFIER_SHIFT) != 0,
152                  (modifiers & MODIFIER_META) != 0,
153                  aButton, aRelatedTarget);
154 
155   switch(mEvent->mClass) {
156     case eMouseEventClass:
157     case eMouseScrollEventClass:
158     case eWheelEventClass:
159     case eDragEventClass:
160     case ePointerEventClass:
161     case eSimpleGestureEventClass:
162       mEvent->AsInputEvent()->mModifiers = modifiers;
163       return;
164     default:
165       MOZ_CRASH("There is no space to store the modifiers");
166   }
167 }
168 
169 void
InitializeExtraMouseEventDictionaryMembers(const MouseEventInit & aParam)170 MouseEvent::InitializeExtraMouseEventDictionaryMembers(const MouseEventInit& aParam)
171 {
172   InitModifiers(aParam);
173   mEvent->AsMouseEventBase()->buttons = aParam.mButtons;
174   mMovementPoint.x = aParam.mMovementX;
175   mMovementPoint.y = aParam.mMovementY;
176 }
177 
178 already_AddRefed<MouseEvent>
Constructor(const GlobalObject & aGlobal,const nsAString & aType,const MouseEventInit & aParam,ErrorResult & aRv)179 MouseEvent::Constructor(const GlobalObject& aGlobal,
180                         const nsAString& aType,
181                         const MouseEventInit& aParam,
182                         ErrorResult& aRv)
183 {
184   nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
185   RefPtr<MouseEvent> e = new MouseEvent(t, nullptr, nullptr);
186   bool trusted = e->Init(t);
187   e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable,
188                     aParam.mView, aParam.mDetail, aParam.mScreenX,
189                     aParam.mScreenY, aParam.mClientX, aParam.mClientY,
190                     aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey,
191                     aParam.mMetaKey, aParam.mButton, aParam.mRelatedTarget);
192   e->InitializeExtraMouseEventDictionaryMembers(aParam);
193   e->SetTrusted(trusted);
194   e->SetComposed(aParam.mComposed);
195   return e.forget();
196 }
197 
198 void
InitNSMouseEvent(const nsAString & aType,bool aCanBubble,bool aCancelable,nsGlobalWindow * aView,int32_t aDetail,int32_t aScreenX,int32_t aScreenY,int32_t aClientX,int32_t aClientY,bool aCtrlKey,bool aAltKey,bool aShiftKey,bool aMetaKey,uint16_t aButton,EventTarget * aRelatedTarget,float aPressure,uint16_t aInputSource)199 MouseEvent::InitNSMouseEvent(const nsAString& aType,
200                              bool aCanBubble,
201                              bool aCancelable,
202                              nsGlobalWindow* aView,
203                              int32_t aDetail,
204                              int32_t aScreenX,
205                              int32_t aScreenY,
206                              int32_t aClientX,
207                              int32_t aClientY,
208                              bool aCtrlKey,
209                              bool aAltKey,
210                              bool aShiftKey,
211                              bool aMetaKey,
212                              uint16_t aButton,
213                              EventTarget* aRelatedTarget,
214                              float aPressure,
215                              uint16_t aInputSource)
216 {
217   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
218 
219   MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable,
220                              aView, aDetail, aScreenX, aScreenY,
221                              aClientX, aClientY,
222                              aCtrlKey, aAltKey, aShiftKey,
223                              aMetaKey, aButton, aRelatedTarget);
224 
225   WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
226   mouseEventBase->pressure = aPressure;
227   mouseEventBase->inputSource = aInputSource;
228 }
229 
230 NS_IMETHODIMP
GetButton(int16_t * aButton)231 MouseEvent::GetButton(int16_t* aButton)
232 {
233   NS_ENSURE_ARG_POINTER(aButton);
234   *aButton = Button();
235   return NS_OK;
236 }
237 
238 int16_t
Button()239 MouseEvent::Button()
240 {
241   switch(mEvent->mClass) {
242     case eMouseEventClass:
243     case eMouseScrollEventClass:
244     case eWheelEventClass:
245     case eDragEventClass:
246     case ePointerEventClass:
247     case eSimpleGestureEventClass:
248       return mEvent->AsMouseEventBase()->button;
249     default:
250       NS_WARNING("Tried to get mouse button for non-mouse event!");
251       return WidgetMouseEvent::eLeftButton;
252   }
253 }
254 
255 NS_IMETHODIMP
GetButtons(uint16_t * aButtons)256 MouseEvent::GetButtons(uint16_t* aButtons)
257 {
258   NS_ENSURE_ARG_POINTER(aButtons);
259   *aButtons = Buttons();
260   return NS_OK;
261 }
262 
263 uint16_t
Buttons()264 MouseEvent::Buttons()
265 {
266   switch(mEvent->mClass) {
267     case eMouseEventClass:
268     case eMouseScrollEventClass:
269     case eWheelEventClass:
270     case eDragEventClass:
271     case ePointerEventClass:
272     case eSimpleGestureEventClass:
273       return mEvent->AsMouseEventBase()->buttons;
274     default:
275       MOZ_CRASH("Tried to get mouse buttons for non-mouse event!");
276   }
277 }
278 
279 NS_IMETHODIMP
GetRelatedTarget(nsIDOMEventTarget ** aRelatedTarget)280 MouseEvent::GetRelatedTarget(nsIDOMEventTarget** aRelatedTarget)
281 {
282   NS_ENSURE_ARG_POINTER(aRelatedTarget);
283   *aRelatedTarget = GetRelatedTarget().take();
284   return NS_OK;
285 }
286 
287 already_AddRefed<EventTarget>
GetRelatedTarget()288 MouseEvent::GetRelatedTarget()
289 {
290   nsCOMPtr<EventTarget> relatedTarget;
291   switch(mEvent->mClass) {
292     case eMouseEventClass:
293     case eMouseScrollEventClass:
294     case eWheelEventClass:
295     case eDragEventClass:
296     case ePointerEventClass:
297     case eSimpleGestureEventClass:
298       relatedTarget =
299         do_QueryInterface(mEvent->AsMouseEventBase()->relatedTarget);
300       break;
301     default:
302       break;
303   }
304 
305   if (relatedTarget) {
306     nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
307     nsCOMPtr<nsIContent> currentTarget =
308       do_QueryInterface(mEvent->mCurrentTarget);
309 
310     nsIContent* shadowRelatedTarget = GetShadowRelatedTarget(currentTarget, content);
311     if (shadowRelatedTarget) {
312       relatedTarget = shadowRelatedTarget;
313     }
314 
315     if (content && content->ChromeOnlyAccess() &&
316         !nsContentUtils::CanAccessNativeAnon()) {
317       relatedTarget = do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
318     }
319 
320     if (relatedTarget) {
321       relatedTarget = relatedTarget->GetTargetForDOMEvent();
322     }
323     return relatedTarget.forget();
324   }
325   return nullptr;
326 }
327 
328 void
GetRegion(nsAString & aRegion)329 MouseEvent::GetRegion(nsAString& aRegion)
330 {
331   SetDOMStringToNull(aRegion);
332   WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
333   if (mouseEventBase) {
334     aRegion = mouseEventBase->region;
335   }
336 }
337 
338 NS_IMETHODIMP
GetMozMovementX(int32_t * aMovementX)339 MouseEvent::GetMozMovementX(int32_t* aMovementX)
340 {
341   NS_ENSURE_ARG_POINTER(aMovementX);
342   *aMovementX = MovementX();
343 
344   return NS_OK;
345 }
346 
347 NS_IMETHODIMP
GetMozMovementY(int32_t * aMovementY)348 MouseEvent::GetMozMovementY(int32_t* aMovementY)
349 {
350   NS_ENSURE_ARG_POINTER(aMovementY);
351   *aMovementY = MovementY();
352 
353   return NS_OK;
354 }
355 
356 NS_IMETHODIMP
GetScreenX(int32_t * aScreenX)357 MouseEvent::GetScreenX(int32_t* aScreenX)
358 {
359   NS_ENSURE_ARG_POINTER(aScreenX);
360   *aScreenX = ScreenX();
361   return NS_OK;
362 }
363 
364 int32_t
ScreenX()365 MouseEvent::ScreenX()
366 {
367   return Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint).x;
368 }
369 
370 NS_IMETHODIMP
GetScreenY(int32_t * aScreenY)371 MouseEvent::GetScreenY(int32_t* aScreenY)
372 {
373   NS_ENSURE_ARG_POINTER(aScreenY);
374   *aScreenY = ScreenY();
375   return NS_OK;
376 }
377 
378 int32_t
ScreenY()379 MouseEvent::ScreenY()
380 {
381   return Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint).y;
382 }
383 
384 
385 NS_IMETHODIMP
GetClientX(int32_t * aClientX)386 MouseEvent::GetClientX(int32_t* aClientX)
387 {
388   NS_ENSURE_ARG_POINTER(aClientX);
389   *aClientX = ClientX();
390   return NS_OK;
391 }
392 
393 int32_t
ClientX()394 MouseEvent::ClientX()
395 {
396   return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
397                                 mClientPoint).x;
398 }
399 
400 NS_IMETHODIMP
GetClientY(int32_t * aClientY)401 MouseEvent::GetClientY(int32_t* aClientY)
402 {
403   NS_ENSURE_ARG_POINTER(aClientY);
404   *aClientY = ClientY();
405   return NS_OK;
406 }
407 
408 int32_t
ClientY()409 MouseEvent::ClientY()
410 {
411   return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
412                                 mClientPoint).y;
413 }
414 
415 int32_t
OffsetX()416 MouseEvent::OffsetX()
417 {
418   return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->mRefPoint,
419                                 mClientPoint).x;
420 }
421 
422 int32_t
OffsetY()423 MouseEvent::OffsetY()
424 {
425   return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->mRefPoint,
426                                 mClientPoint).y;
427 }
428 
429 bool
AltKey()430 MouseEvent::AltKey()
431 {
432   return mEvent->AsInputEvent()->IsAlt();
433 }
434 
435 NS_IMETHODIMP
GetAltKey(bool * aIsDown)436 MouseEvent::GetAltKey(bool* aIsDown)
437 {
438   NS_ENSURE_ARG_POINTER(aIsDown);
439   *aIsDown = AltKey();
440   return NS_OK;
441 }
442 
443 bool
CtrlKey()444 MouseEvent::CtrlKey()
445 {
446   return mEvent->AsInputEvent()->IsControl();
447 }
448 
449 NS_IMETHODIMP
GetCtrlKey(bool * aIsDown)450 MouseEvent::GetCtrlKey(bool* aIsDown)
451 {
452   NS_ENSURE_ARG_POINTER(aIsDown);
453   *aIsDown = CtrlKey();
454   return NS_OK;
455 }
456 
457 bool
ShiftKey()458 MouseEvent::ShiftKey()
459 {
460   return mEvent->AsInputEvent()->IsShift();
461 }
462 
463 NS_IMETHODIMP
GetShiftKey(bool * aIsDown)464 MouseEvent::GetShiftKey(bool* aIsDown)
465 {
466   NS_ENSURE_ARG_POINTER(aIsDown);
467   *aIsDown = ShiftKey();
468   return NS_OK;
469 }
470 
471 bool
MetaKey()472 MouseEvent::MetaKey()
473 {
474   return mEvent->AsInputEvent()->IsMeta();
475 }
476 
477 NS_IMETHODIMP
GetMetaKey(bool * aIsDown)478 MouseEvent::GetMetaKey(bool* aIsDown)
479 {
480   NS_ENSURE_ARG_POINTER(aIsDown);
481   *aIsDown = MetaKey();
482   return NS_OK;
483 }
484 
485 NS_IMETHODIMP
GetModifierState(const nsAString & aKey,bool * aState)486 MouseEvent::GetModifierState(const nsAString& aKey,
487                                   bool* aState)
488 {
489   NS_ENSURE_ARG_POINTER(aState);
490 
491   *aState = GetModifierState(aKey);
492   return NS_OK;
493 }
494 
495 float
MozPressure() const496 MouseEvent::MozPressure() const
497 {
498   return mEvent->AsMouseEventBase()->pressure;
499 }
500 
501 NS_IMETHODIMP
GetMozPressure(float * aPressure)502 MouseEvent::GetMozPressure(float* aPressure)
503 {
504   NS_ENSURE_ARG_POINTER(aPressure);
505   *aPressure = MozPressure();
506   return NS_OK;
507 }
508 
509 bool
HitCluster() const510 MouseEvent::HitCluster() const
511 {
512   return mEvent->AsMouseEventBase()->hitCluster;
513 }
514 
515 uint16_t
MozInputSource() const516 MouseEvent::MozInputSource() const
517 {
518   return mEvent->AsMouseEventBase()->inputSource;
519 }
520 
521 NS_IMETHODIMP
GetMozInputSource(uint16_t * aInputSource)522 MouseEvent::GetMozInputSource(uint16_t* aInputSource)
523 {
524   NS_ENSURE_ARG_POINTER(aInputSource);
525   *aInputSource = MozInputSource();
526   return NS_OK;
527 }
528 
529 } // namespace dom
530 } // namespace mozilla
531 
532 using namespace mozilla;
533 using namespace mozilla::dom;
534 
535 already_AddRefed<MouseEvent>
NS_NewDOMMouseEvent(EventTarget * aOwner,nsPresContext * aPresContext,WidgetMouseEvent * aEvent)536 NS_NewDOMMouseEvent(EventTarget* aOwner,
537                     nsPresContext* aPresContext,
538                     WidgetMouseEvent* aEvent)
539 {
540   RefPtr<MouseEvent> it = new MouseEvent(aOwner, aPresContext, aEvent);
541   return it.forget();
542 }
543