Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/events/KeyboardEvent.cpp
Line
Count
Source (jump to first uncovered line)
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/KeyboardEvent.h"
8
#include "mozilla/TextEvents.h"
9
#include "nsContentUtils.h"
10
#include "prtime.h"
11
12
namespace mozilla {
13
namespace dom {
14
15
KeyboardEvent::KeyboardEvent(EventTarget* aOwner,
16
                             nsPresContext* aPresContext,
17
                             WidgetKeyboardEvent* aEvent)
18
  : UIEvent(aOwner, aPresContext,
19
            aEvent ? aEvent :
20
                     new WidgetKeyboardEvent(false, eVoidEvent, nullptr))
21
  , mInitializedByCtor(false)
22
  , mInitializedWhichValue(0)
23
0
{
24
0
  if (aEvent) {
25
0
    mEventIsInternal = false;
26
0
  }
27
0
  else {
28
0
    mEventIsInternal = true;
29
0
    mEvent->mTime = PR_Now();
30
0
    mEvent->AsKeyboardEvent()->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
31
0
  }
32
0
}
33
34
bool
35
KeyboardEvent::AltKey(CallerType aCallerType)
36
0
{
37
0
  bool altState = mEvent->AsKeyboardEvent()->IsAlt();
38
0
39
0
  if (!ShouldResistFingerprinting(aCallerType)) {
40
0
    return altState;
41
0
  }
42
0
43
0
  // We need to give a spoofed state for Alt key since it could be used as a
44
0
  // modifier key in certain keyboard layout. For example, the '@' key for
45
0
  // German keyboard for MAC is Alt+L.
46
0
  return GetSpoofedModifierStates(Modifier::MODIFIER_ALT, altState);
47
0
}
48
49
bool
50
KeyboardEvent::CtrlKey(CallerType aCallerType)
51
0
{
52
0
  // We don't spoof this key when privacy.resistFingerprinting
53
0
  // is enabled, because it is often used for command key
54
0
  // combinations in web apps.
55
0
  return mEvent->AsKeyboardEvent()->IsControl();
56
0
}
57
58
bool
59
KeyboardEvent::ShiftKey(CallerType aCallerType)
60
0
{
61
0
  bool shiftState = mEvent->AsKeyboardEvent()->IsShift();
62
0
63
0
  if (!ShouldResistFingerprinting(aCallerType)) {
64
0
    return shiftState;
65
0
  }
66
0
67
0
  return GetSpoofedModifierStates(Modifier::MODIFIER_SHIFT, shiftState);
68
0
}
69
70
bool
71
KeyboardEvent::MetaKey()
72
0
{
73
0
  // We don't spoof this key when privacy.resistFingerprinting
74
0
  // is enabled, because it is often used for command key
75
0
  // combinations in web apps.
76
0
  return mEvent->AsKeyboardEvent()->IsMeta();
77
0
}
78
79
bool
80
KeyboardEvent::Repeat()
81
0
{
82
0
  return mEvent->AsKeyboardEvent()->mIsRepeat;
83
0
}
84
85
bool
86
KeyboardEvent::IsComposing()
87
0
{
88
0
  return mEvent->AsKeyboardEvent()->mIsComposing;
89
0
}
90
91
void
92
KeyboardEvent::GetKey(nsAString& aKeyName) const
93
0
{
94
0
  mEvent->AsKeyboardEvent()->GetDOMKeyName(aKeyName);
95
0
}
96
97
void
98
KeyboardEvent::GetCode(nsAString& aCodeName, CallerType aCallerType)
99
0
{
100
0
  if (!ShouldResistFingerprinting(aCallerType)) {
101
0
    mEvent->AsKeyboardEvent()->GetDOMCodeName(aCodeName);
102
0
    return;
103
0
  }
104
0
105
0
  // When fingerprinting resistance is enabled, we will give a spoofed code
106
0
  // according to the content-language of the document.
107
0
  nsCOMPtr<nsIDocument> doc = GetDocument();
108
0
109
0
  nsRFPService::GetSpoofedCode(doc, mEvent->AsKeyboardEvent(),
110
0
                               aCodeName);
111
0
}
112
113
void KeyboardEvent::GetInitDict(KeyboardEventInit& aParam)
114
0
{
115
0
  GetKey(aParam.mKey);
116
0
  GetCode(aParam.mCode);
117
0
  aParam.mLocation = Location();
118
0
  aParam.mRepeat = Repeat();
119
0
  aParam.mIsComposing = IsComposing();
120
0
121
0
  // legacy attributes
122
0
  aParam.mKeyCode = KeyCode();
123
0
  aParam.mCharCode = CharCode();
124
0
  aParam.mWhich = Which();
125
0
126
0
  // modifiers from EventModifierInit
127
0
  aParam.mCtrlKey = CtrlKey();
128
0
  aParam.mShiftKey = ShiftKey();
129
0
  aParam.mAltKey = AltKey();
130
0
  aParam.mMetaKey = MetaKey();
131
0
132
0
  WidgetKeyboardEvent* internalEvent = mEvent->AsKeyboardEvent();
133
0
  aParam.mModifierAltGraph = internalEvent->IsAltGraph();
134
0
  aParam.mModifierCapsLock = internalEvent->IsCapsLocked();
135
0
  aParam.mModifierFn = internalEvent->IsFn();
136
0
  aParam.mModifierFnLock = internalEvent->IsFnLocked();
137
0
  aParam.mModifierNumLock = internalEvent->IsNumLocked();
138
0
  aParam.mModifierOS = internalEvent->IsOS();
139
0
  aParam.mModifierScrollLock = internalEvent->IsScrollLocked();
140
0
  aParam.mModifierSymbol = internalEvent->IsSymbol();
141
0
  aParam.mModifierSymbolLock = internalEvent->IsSymbolLocked();
142
0
143
0
  // EventInit
144
0
  aParam.mBubbles =  internalEvent->mFlags.mBubbles;
145
0
  aParam.mCancelable = internalEvent->mFlags.mCancelable;
146
0
}
147
148
uint32_t
149
KeyboardEvent::CharCode()
150
0
{
151
0
  // If this event is initialized with ctor, we shouldn't check event type.
152
0
  if (mInitializedByCtor) {
153
0
    return mEvent->AsKeyboardEvent()->mCharCode;
154
0
  }
155
0
156
0
  switch (mEvent->mMessage) {
157
0
  case eKeyDown:
158
0
  case eKeyDownOnPlugin:
159
0
  case eKeyUp:
160
0
  case eKeyUpOnPlugin:
161
0
    return 0;
162
0
  case eKeyPress:
163
0
  case eAccessKeyNotFound:
164
0
    return mEvent->AsKeyboardEvent()->mCharCode;
165
0
  default:
166
0
    break;
167
0
  }
168
0
  return 0;
169
0
}
170
171
uint32_t
172
KeyboardEvent::KeyCode(CallerType aCallerType)
173
0
{
174
0
  // If this event is initialized with ctor, we shouldn't check event type.
175
0
  if (mInitializedByCtor) {
176
0
    return mEvent->AsKeyboardEvent()->mKeyCode;
177
0
  }
178
0
179
0
  if (!mEvent->HasKeyEventMessage()) {
180
0
    return 0;
181
0
  }
182
0
183
0
  if (!ShouldResistFingerprinting(aCallerType)) {
184
0
    return mEvent->AsKeyboardEvent()->mKeyCode;
185
0
  }
186
0
187
0
  // The keyCode should be zero if the char code is given.
188
0
  if (CharCode()) {
189
0
    return 0;
190
0
  }
191
0
192
0
  // When fingerprinting resistance is enabled, we will give a spoofed keyCode
193
0
  // according to the content-language of the document.
194
0
  nsCOMPtr<nsIDocument> doc = GetDocument();
195
0
  uint32_t spoofedKeyCode;
196
0
197
0
  if (nsRFPService::GetSpoofedKeyCode(doc, mEvent->AsKeyboardEvent(),
198
0
                                      spoofedKeyCode)) {
199
0
    return spoofedKeyCode;
200
0
  }
201
0
202
0
  return 0;
203
0
}
204
205
uint32_t
206
KeyboardEvent::Which(CallerType aCallerType)
207
0
{
208
0
  // If this event is initialized with ctor, which can have independent value.
209
0
  if (mInitializedByCtor) {
210
0
    return mInitializedWhichValue;
211
0
  }
212
0
213
0
  switch (mEvent->mMessage) {
214
0
    case eKeyDown:
215
0
    case eKeyDownOnPlugin:
216
0
    case eKeyUp:
217
0
    case eKeyUpOnPlugin:
218
0
      return KeyCode(aCallerType);
219
0
    case eKeyPress:
220
0
      //Special case for 4xp bug 62878.  Try to make value of which
221
0
      //more closely mirror the values that 4.x gave for RETURN and BACKSPACE
222
0
      {
223
0
        uint32_t keyCode = mEvent->AsKeyboardEvent()->mKeyCode;
224
0
        if (keyCode == NS_VK_RETURN || keyCode == NS_VK_BACK) {
225
0
          return keyCode;
226
0
        }
227
0
        return CharCode();
228
0
      }
229
0
    default:
230
0
      break;
231
0
  }
232
0
233
0
  return 0;
234
0
}
235
236
uint32_t
237
KeyboardEvent::Location()
238
0
{
239
0
  return mEvent->AsKeyboardEvent()->mLocation;
240
0
}
241
242
// static
243
already_AddRefed<KeyboardEvent>
244
KeyboardEvent::Constructor(const GlobalObject& aGlobal,
245
                           const nsAString& aType,
246
                           const KeyboardEventInit& aParam,
247
                           ErrorResult& aRv)
248
0
{
249
0
  nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.GetAsSupports());
250
0
  RefPtr<KeyboardEvent> newEvent =
251
0
    new KeyboardEvent(target, nullptr, nullptr);
252
0
  newEvent->InitWithKeyboardEventInit(target, aType, aParam, aRv);
253
0
254
0
  return newEvent.forget();
255
0
}
256
257
void
258
KeyboardEvent::InitWithKeyboardEventInit(EventTarget* aOwner,
259
                                         const nsAString& aType,
260
                                         const KeyboardEventInit& aParam,
261
                                         ErrorResult& aRv)
262
0
{
263
0
  bool trusted = Init(aOwner);
264
0
  InitKeyEvent(aType, aParam.mBubbles, aParam.mCancelable,
265
0
               aParam.mView, false, false, false, false,
266
0
               aParam.mKeyCode, aParam.mCharCode);
267
0
  InitModifiers(aParam);
268
0
  SetTrusted(trusted);
269
0
  mDetail = aParam.mDetail;
270
0
  mInitializedByCtor = true;
271
0
  mInitializedWhichValue = aParam.mWhich;
272
0
273
0
  WidgetKeyboardEvent* internalEvent = mEvent->AsKeyboardEvent();
274
0
  internalEvent->mLocation = aParam.mLocation;
275
0
  internalEvent->mIsRepeat = aParam.mRepeat;
276
0
  internalEvent->mIsComposing = aParam.mIsComposing;
277
0
  internalEvent->mKeyNameIndex =
278
0
    WidgetKeyboardEvent::GetKeyNameIndex(aParam.mKey);
279
0
  if (internalEvent->mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
280
0
    internalEvent->mKeyValue = aParam.mKey;
281
0
  }
282
0
  internalEvent->mCodeNameIndex =
283
0
    WidgetKeyboardEvent::GetCodeNameIndex(aParam.mCode);
284
0
  if (internalEvent->mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
285
0
    internalEvent->mCodeValue = aParam.mCode;
286
0
  }
287
0
}
288
289
void
290
KeyboardEvent::InitKeyEvent(const nsAString& aType, bool aCanBubble,
291
                            bool aCancelable, nsGlobalWindowInner* aView,
292
                            bool aCtrlKey, bool aAltKey,
293
                            bool aShiftKey, bool aMetaKey,
294
                            uint32_t aKeyCode, uint32_t aCharCode)
295
0
{
296
0
  NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
297
0
298
0
  UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0);
299
0
300
0
  WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
301
0
  keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
302
0
  keyEvent->mKeyCode = aKeyCode;
303
0
  keyEvent->mCharCode = aCharCode;
304
0
}
305
306
void
307
KeyboardEvent::InitKeyboardEvent(const nsAString& aType,
308
                                 bool aCanBubble,
309
                                 bool aCancelable,
310
                                 nsGlobalWindowInner* aView,
311
                                 const nsAString& aKey,
312
                                 uint32_t aLocation,
313
                                 bool aCtrlKey,
314
                                 bool aAltKey,
315
                                 bool aShiftKey,
316
                                 bool aMetaKey,
317
                                 ErrorResult& aRv)
318
0
{
319
0
  NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
320
0
321
0
  UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0);
322
0
323
0
  WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
324
0
  keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
325
0
  keyEvent->mLocation = aLocation;
326
0
  keyEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
327
0
  keyEvent->mKeyValue = aKey;
328
0
}
329
330
already_AddRefed<nsIDocument>
331
KeyboardEvent::GetDocument()
332
0
{
333
0
  nsCOMPtr<nsIDocument> doc;
334
0
  nsCOMPtr<EventTarget> eventTarget = GetTarget();
335
0
336
0
  if (eventTarget) {
337
0
    nsCOMPtr<nsPIDOMWindowInner> win =
338
0
      do_QueryInterface(eventTarget->GetOwnerGlobal());
339
0
340
0
    if (win) {
341
0
      doc = win->GetExtantDoc();
342
0
    }
343
0
  }
344
0
345
0
  return doc.forget();
346
0
}
347
348
bool
349
KeyboardEvent::ShouldResistFingerprinting(CallerType aCallerType)
350
0
{
351
0
  // There are five situations we don't need to spoof this keyboard event.
352
0
  //   1. This event is generated by scripts.
353
0
  //   2. This event is from Numpad.
354
0
  //   3. This event is in the system group.
355
0
  //   4. The caller type is system.
356
0
  //   5. The pref privcy.resistFingerprinting' is false, we fast return here since
357
0
  //      we don't need to do any QI of following codes.
358
0
  if (mInitializedByCtor ||
359
0
      aCallerType == CallerType::System ||
360
0
      mEvent->mFlags.mInSystemGroup ||
361
0
      !nsContentUtils::ShouldResistFingerprinting() ||
362
0
      mEvent->AsKeyboardEvent()->mLocation ==
363
0
        KeyboardEvent_Binding::DOM_KEY_LOCATION_NUMPAD) {
364
0
    return false;
365
0
  }
366
0
367
0
  nsCOMPtr<nsIDocument> doc = GetDocument();
368
0
369
0
  return doc && !nsContentUtils::IsChromeDoc(doc);
370
0
}
371
372
bool
373
KeyboardEvent::GetSpoofedModifierStates(const Modifiers aModifierKey,
374
                                        const bool aRawModifierState)
375
0
{
376
0
  bool spoofedState;
377
0
  nsCOMPtr<nsIDocument> doc = GetDocument();
378
0
379
0
  if(nsRFPService::GetSpoofedModifierStates(doc,
380
0
                                            mEvent->AsKeyboardEvent(),
381
0
                                            aModifierKey,
382
0
                                            spoofedState)) {
383
0
    return spoofedState;
384
0
  }
385
0
386
0
  return aRawModifierState;
387
0
}
388
389
} // namespace dom
390
} // namespace mozilla
391
392
using namespace mozilla;
393
using namespace mozilla::dom;
394
395
already_AddRefed<KeyboardEvent>
396
NS_NewDOMKeyboardEvent(EventTarget* aOwner,
397
                       nsPresContext* aPresContext,
398
                       WidgetKeyboardEvent* aEvent)
399
0
{
400
0
  RefPtr<KeyboardEvent> it = new KeyboardEvent(aOwner, aPresContext, aEvent);
401
0
  return it.forget();
402
0
}