tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

UIEvent.cpp (10361B)


      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/UIEvent.h"
      8 
      9 #include "base/basictypes.h"
     10 #include "ipc/IPCMessageUtils.h"
     11 #include "ipc/IPCMessageUtilsSpecializations.h"
     12 #include "mozilla/Assertions.h"
     13 #include "mozilla/ContentEvents.h"
     14 #include "mozilla/EventStateManager.h"
     15 #include "mozilla/PointerLockManager.h"
     16 #include "mozilla/PresShell.h"
     17 #include "mozilla/TextEvents.h"
     18 #include "nsCOMPtr.h"
     19 #include "nsContentUtils.h"
     20 #include "nsIContent.h"
     21 #include "nsIDocShell.h"
     22 #include "nsIFrame.h"
     23 #include "nsIInterfaceRequestorUtils.h"
     24 #include "nsLayoutUtils.h"
     25 #include "prtime.h"
     26 
     27 namespace mozilla::dom {
     28 
     29 UIEvent::UIEvent(EventTarget* aOwner, nsPresContext* aPresContext,
     30                 WidgetGUIEvent* aEvent)
     31    : Event(aOwner, aPresContext,
     32            aEvent ? aEvent : new InternalUIEvent(false, eVoidEvent, nullptr)),
     33      mLayerPoint(0, 0) {
     34  if (aEvent) {
     35    mEventIsInternal = false;
     36  } else {
     37    mEventIsInternal = true;
     38  }
     39 
     40  // Fill mDetail and mView according to the mEvent (widget-generated
     41  // event) we've got
     42  switch (mEvent->mClass) {
     43    case eUIEventClass: {
     44      mDetail = mEvent->AsUIEvent()->mDetail;
     45      break;
     46    }
     47 
     48    case eScrollPortEventClass: {
     49      InternalScrollPortEvent* scrollEvent = mEvent->AsScrollPortEvent();
     50      mDetail = static_cast<int32_t>(scrollEvent->mOrient);
     51      break;
     52    }
     53 
     54    default:
     55      mDetail = 0;
     56      break;
     57  }
     58 
     59  mView = nullptr;
     60  if (mPresContext) {
     61    nsIDocShell* docShell = mPresContext->GetDocShell();
     62    if (docShell) {
     63      mView = docShell->GetWindow();
     64    }
     65  }
     66 }
     67 
     68 // static
     69 already_AddRefed<UIEvent> UIEvent::Constructor(const GlobalObject& aGlobal,
     70                                               const nsAString& aType,
     71                                               const UIEventInit& aParam) {
     72  nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
     73  RefPtr<UIEvent> e = new UIEvent(t, nullptr, nullptr);
     74  bool trusted = e->Init(t);
     75  e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
     76                 aParam.mDetail);
     77  e->SetTrusted(trusted);
     78  e->SetComposed(aParam.mComposed);
     79  return e.forget();
     80 }
     81 
     82 NS_IMPL_CYCLE_COLLECTION_INHERITED(UIEvent, Event, mView)
     83 
     84 NS_IMPL_ADDREF_INHERITED(UIEvent, Event)
     85 NS_IMPL_RELEASE_INHERITED(UIEvent, Event)
     86 
     87 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UIEvent)
     88 NS_INTERFACE_MAP_END_INHERITING(Event)
     89 
     90 void UIEvent::InitUIEvent(const nsAString& typeArg, bool canBubbleArg,
     91                          bool cancelableArg, nsGlobalWindowInner* viewArg,
     92                          int32_t detailArg) {
     93  if (NS_WARN_IF(mEvent->mFlags.mIsBeingDispatched)) {
     94    return;
     95  }
     96 
     97  Event::InitEvent(typeArg, canBubbleArg, cancelableArg);
     98 
     99  mDetail = detailArg;
    100  mView = viewArg ? viewArg->GetOuterWindow() : nullptr;
    101 }
    102 
    103 already_AddRefed<nsIContent> UIEvent::GetRangeParentContentAndOffset(
    104    int32_t* aOffset) const {
    105  if (NS_WARN_IF(!mPresContext)) {
    106    return nullptr;
    107  }
    108  RefPtr<PresShell> presShell = mPresContext->GetPresShell();
    109  if (NS_WARN_IF(!presShell)) {
    110    return nullptr;
    111  }
    112  nsCOMPtr<nsIContent> container;
    113  nsLayoutUtils::GetContainerAndOffsetAtEvent(
    114      presShell, mEvent, getter_AddRefs(container), aOffset);
    115  return container.forget();
    116 }
    117 
    118 int32_t UIEvent::RangeOffset() const {
    119  if (NS_WARN_IF(!mPresContext)) {
    120    return 0;
    121  }
    122  RefPtr<PresShell> presShell = mPresContext->GetPresShell();
    123  if (NS_WARN_IF(!presShell)) {
    124    return 0;
    125  }
    126  int32_t offset = 0;
    127  nsLayoutUtils::GetContainerAndOffsetAtEvent(presShell, mEvent, nullptr,
    128                                              &offset);
    129  return offset;
    130 }
    131 
    132 nsIntPoint UIEvent::GetLayerPoint() const {
    133  if (mEvent->mFlags.mIsPositionless) {
    134    return nsIntPoint(0, 0);
    135  }
    136  if (!mEvent ||
    137      (mEvent->mClass != eMouseEventClass &&
    138       mEvent->mClass != eMouseScrollEventClass &&
    139       mEvent->mClass != eWheelEventClass &&
    140       mEvent->mClass != ePointerEventClass &&
    141       mEvent->mClass != eTouchEventClass &&
    142       mEvent->mClass != eDragEventClass &&
    143       mEvent->mClass != eSimpleGestureEventClass) ||
    144      !mPresContext || mEventIsInternal) {
    145    return mLayerPoint;
    146  }
    147  nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
    148  if (!targetFrame) {
    149    return mLayerPoint;
    150  }
    151  // NOTE(emilio): This matches Blink to my knowledge, but it's generally not
    152  // super-well specified, see https://github.com/w3c/uievents/issues/398
    153  RelativeTo root{targetFrame->PresShell()->GetRootFrame()};
    154  const nsPoint rootPoint =
    155      nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, root);
    156  nsIFrame* layer = nsLayoutUtils::GetClosestLayer(targetFrame);
    157  nsPoint layerRootPoint{0, 0};
    158  if (nsLayoutUtils::TransformPoint(RelativeTo{layer}, RelativeTo{root},
    159                                    layerRootPoint) !=
    160      nsLayoutUtils::TRANSFORM_SUCCEEDED) {
    161    return mLayerPoint;
    162  }
    163  return RoundedToInt(CSSPoint::FromAppUnits(rootPoint - layerRootPoint))
    164      .ToUnknownPoint();
    165 }
    166 
    167 void UIEvent::DuplicatePrivateData() {
    168  mLayerPoint = GetLayerPoint();
    169 
    170  // GetScreenCoords() converts mEvent->mRefPoint to right coordinates.
    171  // Note that mPresContext will be cleared by Event::DuplicatePrivateData().
    172  // Therefore, we need to use mPresContext before calling it.
    173  const CSSIntPoint screenPoint = RoundedToInt(
    174      Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint)
    175          .valueOr(CSSIntPoint{0, 0}));
    176 
    177  Event::DuplicatePrivateData();
    178  MOZ_ASSERT_IF(!mEventIsInternal, !mPresContext);
    179 
    180  // GetScreenCoords() has already computed the screen point in CSS pixels which
    181  // applied the scale of mPresContext.  Additionally, we don't have the widget
    182  // anymore.  Therefore, we need to cache the point as in the screen
    183  // coordinates.
    184  MOZ_ASSERT(!mEvent || !mEvent->AsGUIEvent() ||
    185             !mEvent->AsGUIEvent()->mWidget);
    186  mEvent->mRefPoint = RoundedToInt(screenPoint * CSSToLayoutDeviceScale(1));
    187 }
    188 
    189 void UIEvent::Serialize(IPC::MessageWriter* aWriter,
    190                        bool aSerializeInterfaceType) {
    191  if (aSerializeInterfaceType) {
    192    IPC::WriteParam(aWriter, u"uievent"_ns);
    193  }
    194 
    195  Event::Serialize(aWriter, false);
    196 
    197  IPC::WriteParam(aWriter, Detail());
    198 }
    199 
    200 bool UIEvent::Deserialize(IPC::MessageReader* aReader) {
    201  NS_ENSURE_TRUE(Event::Deserialize(aReader), false);
    202  NS_ENSURE_TRUE(IPC::ReadParam(aReader, &mDetail), false);
    203  return true;
    204 }
    205 
    206 // XXX Following struct and array are used only in
    207 //     UIEvent::ComputeModifierState(), but if we define them in it,
    208 //     we fail to build on Mac at calling std::size().
    209 struct ModifierPair {
    210  Modifier modifier;
    211  const char* name;
    212 };
    213 static const ModifierPair kPairs[] = {
    214    // clang-format off
    215  { MODIFIER_ALT,        NS_DOM_KEYNAME_ALT },
    216  { MODIFIER_ALTGRAPH,   NS_DOM_KEYNAME_ALTGRAPH },
    217  { MODIFIER_CAPSLOCK,   NS_DOM_KEYNAME_CAPSLOCK },
    218  { MODIFIER_CONTROL,    NS_DOM_KEYNAME_CONTROL },
    219  { MODIFIER_FN,         NS_DOM_KEYNAME_FN },
    220  { MODIFIER_FNLOCK,     NS_DOM_KEYNAME_FNLOCK },
    221  { MODIFIER_META,       NS_DOM_KEYNAME_META },
    222  { MODIFIER_NUMLOCK,    NS_DOM_KEYNAME_NUMLOCK },
    223  { MODIFIER_SCROLLLOCK, NS_DOM_KEYNAME_SCROLLLOCK },
    224  { MODIFIER_SHIFT,      NS_DOM_KEYNAME_SHIFT },
    225  { MODIFIER_SYMBOL,     NS_DOM_KEYNAME_SYMBOL },
    226  { MODIFIER_SYMBOLLOCK, NS_DOM_KEYNAME_SYMBOLLOCK },
    227    // clang-format on
    228 };
    229 
    230 // static
    231 Modifiers UIEvent::ComputeModifierState(const nsAString& aModifiersList) {
    232  if (aModifiersList.IsEmpty()) {
    233    return 0;
    234  }
    235 
    236  // Be careful about the performance.  If aModifiersList is too long,
    237  // parsing it needs too long time.
    238  // XXX Should we abort if aModifiersList is too long?
    239 
    240  Modifiers modifiers = 0;
    241 
    242  nsAString::const_iterator listStart, listEnd;
    243  aModifiersList.BeginReading(listStart);
    244  aModifiersList.EndReading(listEnd);
    245 
    246  for (uint32_t i = 0; i < std::size(kPairs); i++) {
    247    nsAString::const_iterator start(listStart), end(listEnd);
    248    if (!FindInReadable(NS_ConvertASCIItoUTF16(kPairs[i].name), start, end)) {
    249      continue;
    250    }
    251 
    252    if ((start != listStart && !NS_IsAsciiWhitespace(*(--start))) ||
    253        (end != listEnd && !NS_IsAsciiWhitespace(*(end)))) {
    254      continue;
    255    }
    256    modifiers |= kPairs[i].modifier;
    257  }
    258 
    259  return modifiers;
    260 }
    261 
    262 bool UIEvent::GetModifierStateInternal(const nsAString& aKey) {
    263  WidgetInputEvent* inputEvent = mEvent->AsInputEvent();
    264  MOZ_ASSERT(inputEvent, "mEvent must be WidgetInputEvent or derived class");
    265  return ((inputEvent->mModifiers & WidgetInputEvent::GetModifier(aKey)) != 0);
    266 }
    267 
    268 static Modifiers ConvertToModifiers(const EventModifierInit& aParam) {
    269  Modifiers bits = MODIFIER_NONE;
    270 
    271 #define SET_MODIFIER(aName, aValue) bits |= aParam.m##aName ? (aValue) : 0;
    272 
    273  SET_MODIFIER(CtrlKey, MODIFIER_CONTROL)
    274  SET_MODIFIER(ShiftKey, MODIFIER_SHIFT)
    275  SET_MODIFIER(AltKey, MODIFIER_ALT)
    276  SET_MODIFIER(MetaKey, MODIFIER_META)
    277  SET_MODIFIER(ModifierAltGraph, MODIFIER_ALTGRAPH)
    278  SET_MODIFIER(ModifierCapsLock, MODIFIER_CAPSLOCK)
    279  SET_MODIFIER(ModifierFn, MODIFIER_FN)
    280  SET_MODIFIER(ModifierFnLock, MODIFIER_FNLOCK)
    281  SET_MODIFIER(ModifierNumLock, MODIFIER_NUMLOCK)
    282  SET_MODIFIER(ModifierScrollLock, MODIFIER_SCROLLLOCK)
    283  SET_MODIFIER(ModifierSymbol, MODIFIER_SYMBOL)
    284  SET_MODIFIER(ModifierSymbolLock, MODIFIER_SYMBOLLOCK)
    285 
    286 #undef SET_MODIFIER
    287 
    288  return bits;
    289 }
    290 
    291 void UIEvent::InitModifiers(const EventModifierInit& aParam) {
    292  if (NS_WARN_IF(!mEvent)) {
    293    return;
    294  }
    295  WidgetInputEvent* inputEvent = mEvent->AsInputEvent();
    296  MOZ_ASSERT(inputEvent,
    297             "This method shouldn't be called if it doesn't have modifiers");
    298  if (NS_WARN_IF(!inputEvent)) {
    299    return;
    300  }
    301 
    302  inputEvent->mModifiers = ConvertToModifiers(aParam);
    303 }
    304 
    305 }  // namespace mozilla::dom
    306 
    307 using namespace mozilla;
    308 using namespace mozilla::dom;
    309 
    310 already_AddRefed<UIEvent> NS_NewDOMUIEvent(EventTarget* aOwner,
    311                                           nsPresContext* aPresContext,
    312                                           WidgetGUIEvent* aEvent) {
    313  RefPtr<UIEvent> it = new UIEvent(aOwner, aPresContext, aEvent);
    314  return it.forget();
    315 }