Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "base/basictypes.h"
7 #include "ipc/IPCMessageUtils.h"
8 #include "mozilla/dom/UIEvent.h"
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/Assertions.h"
11 #include "mozilla/ContentEvents.h"
12 #include "mozilla/EventStateManager.h"
13 #include "mozilla/TextEvents.h"
14 #include "nsCOMPtr.h"
15 #include "nsContentUtils.h"
16 #include "nsIContent.h"
17 #include "nsIInterfaceRequestorUtils.h"
18 #include "nsIDOMWindow.h"
19 #include "nsIDOMNode.h"
20 #include "nsIFrame.h"
21 #include "prtime.h"
23 namespace mozilla {
24 namespace dom {
26 UIEvent::UIEvent(EventTarget* aOwner,
27 nsPresContext* aPresContext,
28 WidgetGUIEvent* aEvent)
29 : Event(aOwner, aPresContext,
30 aEvent ? aEvent : new InternalUIEvent(false, 0))
31 , mClientPoint(0, 0)
32 , mLayerPoint(0, 0)
33 , mPagePoint(0, 0)
34 , mMovementPoint(0, 0)
35 , mIsPointerLocked(EventStateManager::sIsPointerLocked)
36 , mLastClientPoint(EventStateManager::sLastClientPoint)
37 {
38 if (aEvent) {
39 mEventIsInternal = false;
40 }
41 else {
42 mEventIsInternal = true;
43 mEvent->time = PR_Now();
44 }
46 // Fill mDetail and mView according to the mEvent (widget-generated
47 // event) we've got
48 switch(mEvent->eventStructType)
49 {
50 case NS_UI_EVENT:
51 {
52 mDetail = mEvent->AsUIEvent()->detail;
53 break;
54 }
56 case NS_SCROLLPORT_EVENT:
57 {
58 InternalScrollPortEvent* scrollEvent = mEvent->AsScrollPortEvent();
59 mDetail = (int32_t)scrollEvent->orient;
60 break;
61 }
63 default:
64 mDetail = 0;
65 break;
66 }
68 mView = nullptr;
69 if (mPresContext)
70 {
71 nsISupports* container = mPresContext->GetContainerWeak();
72 if (container)
73 {
74 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container);
75 if (window)
76 mView = do_QueryInterface(window);
77 }
78 }
79 }
81 // static
82 already_AddRefed<UIEvent>
83 UIEvent::Constructor(const GlobalObject& aGlobal,
84 const nsAString& aType,
85 const UIEventInit& aParam,
86 ErrorResult& aRv)
87 {
88 nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
89 nsRefPtr<UIEvent> e = new UIEvent(t, nullptr, nullptr);
90 bool trusted = e->Init(t);
91 aRv = e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
92 aParam.mDetail);
93 e->SetTrusted(trusted);
94 return e.forget();
95 }
97 NS_IMPL_CYCLE_COLLECTION_INHERITED(UIEvent, Event,
98 mView)
100 NS_IMPL_ADDREF_INHERITED(UIEvent, Event)
101 NS_IMPL_RELEASE_INHERITED(UIEvent, Event)
103 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(UIEvent)
104 NS_INTERFACE_MAP_ENTRY(nsIDOMUIEvent)
105 NS_INTERFACE_MAP_END_INHERITING(Event)
107 static nsIntPoint
108 DevPixelsToCSSPixels(const LayoutDeviceIntPoint& aPoint,
109 nsPresContext* aContext)
110 {
111 return nsIntPoint(aContext->DevPixelsToIntCSSPixels(aPoint.x),
112 aContext->DevPixelsToIntCSSPixels(aPoint.y));
113 }
115 nsIntPoint
116 UIEvent::GetMovementPoint()
117 {
118 if (mPrivateDataDuplicated) {
119 return mMovementPoint;
120 }
122 if (!mEvent ||
123 (mEvent->eventStructType != NS_MOUSE_EVENT &&
124 mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
125 mEvent->eventStructType != NS_WHEEL_EVENT &&
126 mEvent->eventStructType != NS_DRAG_EVENT &&
127 mEvent->eventStructType != NS_POINTER_EVENT &&
128 mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
129 !mEvent->AsGUIEvent()->widget) {
130 return nsIntPoint(0, 0);
131 }
133 // Calculate the delta between the last screen point and the current one.
134 nsIntPoint current = DevPixelsToCSSPixels(mEvent->refPoint, mPresContext);
135 nsIntPoint last = DevPixelsToCSSPixels(mEvent->lastRefPoint, mPresContext);
136 return current - last;
137 }
139 NS_IMETHODIMP
140 UIEvent::GetView(nsIDOMWindow** aView)
141 {
142 *aView = mView;
143 NS_IF_ADDREF(*aView);
144 return NS_OK;
145 }
147 NS_IMETHODIMP
148 UIEvent::GetDetail(int32_t* aDetail)
149 {
150 *aDetail = mDetail;
151 return NS_OK;
152 }
154 NS_IMETHODIMP
155 UIEvent::InitUIEvent(const nsAString& typeArg,
156 bool canBubbleArg,
157 bool cancelableArg,
158 nsIDOMWindow* viewArg,
159 int32_t detailArg)
160 {
161 if (viewArg) {
162 nsCOMPtr<nsPIDOMWindow> view = do_QueryInterface(viewArg);
163 NS_ENSURE_TRUE(view, NS_ERROR_INVALID_ARG);
164 }
165 nsresult rv = Event::InitEvent(typeArg, canBubbleArg, cancelableArg);
166 NS_ENSURE_SUCCESS(rv, rv);
168 mDetail = detailArg;
169 mView = viewArg;
171 return NS_OK;
172 }
174 NS_IMETHODIMP
175 UIEvent::GetPageX(int32_t* aPageX)
176 {
177 NS_ENSURE_ARG_POINTER(aPageX);
178 *aPageX = PageX();
179 return NS_OK;
180 }
182 int32_t
183 UIEvent::PageX() const
184 {
185 if (mPrivateDataDuplicated) {
186 return mPagePoint.x;
187 }
189 return Event::GetPageCoords(mPresContext, mEvent, mEvent->refPoint,
190 mClientPoint).x;
191 }
193 NS_IMETHODIMP
194 UIEvent::GetPageY(int32_t* aPageY)
195 {
196 NS_ENSURE_ARG_POINTER(aPageY);
197 *aPageY = PageY();
198 return NS_OK;
199 }
201 int32_t
202 UIEvent::PageY() const
203 {
204 if (mPrivateDataDuplicated) {
205 return mPagePoint.y;
206 }
208 return Event::GetPageCoords(mPresContext, mEvent, mEvent->refPoint,
209 mClientPoint).y;
210 }
212 NS_IMETHODIMP
213 UIEvent::GetWhich(uint32_t* aWhich)
214 {
215 NS_ENSURE_ARG_POINTER(aWhich);
216 *aWhich = Which();
217 return NS_OK;
218 }
220 already_AddRefed<nsINode>
221 UIEvent::GetRangeParent()
222 {
223 nsIFrame* targetFrame = nullptr;
225 if (mPresContext) {
226 targetFrame = mPresContext->EventStateManager()->GetEventTarget();
227 }
229 if (targetFrame) {
230 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
231 targetFrame);
232 nsCOMPtr<nsIContent> parent = targetFrame->GetContentOffsetsFromPoint(pt).content;
233 if (parent) {
234 if (parent->ChromeOnlyAccess() &&
235 !nsContentUtils::CanAccessNativeAnon()) {
236 return nullptr;
237 }
238 return parent.forget();
239 }
240 }
242 return nullptr;
243 }
245 NS_IMETHODIMP
246 UIEvent::GetRangeParent(nsIDOMNode** aRangeParent)
247 {
248 NS_ENSURE_ARG_POINTER(aRangeParent);
249 *aRangeParent = nullptr;
250 nsCOMPtr<nsINode> n = GetRangeParent();
251 if (n) {
252 CallQueryInterface(n, aRangeParent);
253 }
254 return NS_OK;
255 }
257 NS_IMETHODIMP
258 UIEvent::GetRangeOffset(int32_t* aRangeOffset)
259 {
260 NS_ENSURE_ARG_POINTER(aRangeOffset);
261 *aRangeOffset = RangeOffset();
262 return NS_OK;
263 }
265 int32_t
266 UIEvent::RangeOffset() const
267 {
268 if (!mPresContext) {
269 return 0;
270 }
272 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
273 if (!targetFrame) {
274 return 0;
275 }
277 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
278 targetFrame);
279 return targetFrame->GetContentOffsetsFromPoint(pt).offset;
280 }
282 NS_IMETHODIMP
283 UIEvent::GetCancelBubble(bool* aCancelBubble)
284 {
285 NS_ENSURE_ARG_POINTER(aCancelBubble);
286 *aCancelBubble = CancelBubble();
287 return NS_OK;
288 }
290 NS_IMETHODIMP
291 UIEvent::SetCancelBubble(bool aCancelBubble)
292 {
293 mEvent->mFlags.mPropagationStopped = aCancelBubble;
294 return NS_OK;
295 }
297 nsIntPoint
298 UIEvent::GetLayerPoint() const
299 {
300 if (!mEvent ||
301 (mEvent->eventStructType != NS_MOUSE_EVENT &&
302 mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
303 mEvent->eventStructType != NS_WHEEL_EVENT &&
304 mEvent->eventStructType != NS_POINTER_EVENT &&
305 mEvent->eventStructType != NS_TOUCH_EVENT &&
306 mEvent->eventStructType != NS_DRAG_EVENT &&
307 mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
308 !mPresContext ||
309 mEventIsInternal) {
310 return mLayerPoint;
311 }
312 // XXX I'm not really sure this is correct; it's my best shot, though
313 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
314 if (!targetFrame)
315 return mLayerPoint;
316 nsIFrame* layer = nsLayoutUtils::GetClosestLayer(targetFrame);
317 nsPoint pt(nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, layer));
318 return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
319 nsPresContext::AppUnitsToIntCSSPixels(pt.y));
320 }
322 NS_IMETHODIMP
323 UIEvent::GetLayerX(int32_t* aLayerX)
324 {
325 NS_ENSURE_ARG_POINTER(aLayerX);
326 *aLayerX = GetLayerPoint().x;
327 return NS_OK;
328 }
330 NS_IMETHODIMP
331 UIEvent::GetLayerY(int32_t* aLayerY)
332 {
333 NS_ENSURE_ARG_POINTER(aLayerY);
334 *aLayerY = GetLayerPoint().y;
335 return NS_OK;
336 }
338 NS_IMETHODIMP
339 UIEvent::GetIsChar(bool* aIsChar)
340 {
341 *aIsChar = IsChar();
342 return NS_OK;
343 }
345 bool
346 UIEvent::IsChar() const
347 {
348 WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
349 if (keyEvent) {
350 return keyEvent->isChar;
351 }
352 WidgetTextEvent* textEvent = mEvent->AsTextEvent();
353 return textEvent ? textEvent->isChar : false;
354 }
356 NS_IMETHODIMP
357 UIEvent::DuplicatePrivateData()
358 {
359 mClientPoint =
360 Event::GetClientCoords(mPresContext, mEvent, mEvent->refPoint,
361 mClientPoint);
362 mMovementPoint = GetMovementPoint();
363 mLayerPoint = GetLayerPoint();
364 mPagePoint =
365 Event::GetPageCoords(mPresContext, mEvent, mEvent->refPoint, mClientPoint);
366 // GetScreenPoint converts mEvent->refPoint to right coordinates.
367 nsIntPoint screenPoint =
368 Event::GetScreenCoords(mPresContext, mEvent, mEvent->refPoint);
369 nsresult rv = Event::DuplicatePrivateData();
370 if (NS_SUCCEEDED(rv)) {
371 mEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(screenPoint);
372 }
373 return rv;
374 }
376 NS_IMETHODIMP_(void)
377 UIEvent::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType)
378 {
379 if (aSerializeInterfaceType) {
380 IPC::WriteParam(aMsg, NS_LITERAL_STRING("uievent"));
381 }
383 Event::Serialize(aMsg, false);
385 int32_t detail = 0;
386 GetDetail(&detail);
387 IPC::WriteParam(aMsg, detail);
388 }
390 NS_IMETHODIMP_(bool)
391 UIEvent::Deserialize(const IPC::Message* aMsg, void** aIter)
392 {
393 NS_ENSURE_TRUE(Event::Deserialize(aMsg, aIter), false);
394 NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &mDetail), false);
395 return true;
396 }
398 // XXX Following struct and array are used only in
399 // UIEvent::ComputeModifierState(), but if we define them in it,
400 // we fail to build on Mac at calling mozilla::ArrayLength().
401 struct ModifierPair
402 {
403 Modifier modifier;
404 const char* name;
405 };
406 static const ModifierPair kPairs[] = {
407 { MODIFIER_ALT, NS_DOM_KEYNAME_ALT },
408 { MODIFIER_ALTGRAPH, NS_DOM_KEYNAME_ALTGRAPH },
409 { MODIFIER_CAPSLOCK, NS_DOM_KEYNAME_CAPSLOCK },
410 { MODIFIER_CONTROL, NS_DOM_KEYNAME_CONTROL },
411 { MODIFIER_FN, NS_DOM_KEYNAME_FN },
412 { MODIFIER_META, NS_DOM_KEYNAME_META },
413 { MODIFIER_NUMLOCK, NS_DOM_KEYNAME_NUMLOCK },
414 { MODIFIER_SCROLLLOCK, NS_DOM_KEYNAME_SCROLLLOCK },
415 { MODIFIER_SHIFT, NS_DOM_KEYNAME_SHIFT },
416 { MODIFIER_SYMBOLLOCK, NS_DOM_KEYNAME_SYMBOLLOCK },
417 { MODIFIER_OS, NS_DOM_KEYNAME_OS }
418 };
420 // static
421 Modifiers
422 UIEvent::ComputeModifierState(const nsAString& aModifiersList)
423 {
424 if (aModifiersList.IsEmpty()) {
425 return 0;
426 }
428 // Be careful about the performance. If aModifiersList is too long,
429 // parsing it needs too long time.
430 // XXX Should we abort if aModifiersList is too long?
432 Modifiers modifiers = 0;
434 nsAString::const_iterator listStart, listEnd;
435 aModifiersList.BeginReading(listStart);
436 aModifiersList.EndReading(listEnd);
438 for (uint32_t i = 0; i < ArrayLength(kPairs); i++) {
439 nsAString::const_iterator start(listStart), end(listEnd);
440 if (!FindInReadable(NS_ConvertASCIItoUTF16(kPairs[i].name), start, end)) {
441 continue;
442 }
444 if ((start != listStart && !NS_IsAsciiWhitespace(*(--start))) ||
445 (end != listEnd && !NS_IsAsciiWhitespace(*(end)))) {
446 continue;
447 }
448 modifiers |= kPairs[i].modifier;
449 }
451 return modifiers;
452 }
454 bool
455 UIEvent::GetModifierStateInternal(const nsAString& aKey)
456 {
457 WidgetInputEvent* inputEvent = mEvent->AsInputEvent();
458 MOZ_ASSERT(inputEvent, "mEvent must be WidgetInputEvent or derived class");
459 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SHIFT)) {
460 return inputEvent->IsShift();
461 }
462 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_CONTROL)) {
463 return inputEvent->IsControl();
464 }
465 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_META)) {
466 return inputEvent->IsMeta();
467 }
468 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_ALT)) {
469 return inputEvent->IsAlt();
470 }
472 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_ALTGRAPH)) {
473 return inputEvent->IsAltGraph();
474 }
475 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_OS)) {
476 return inputEvent->IsOS();
477 }
479 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_CAPSLOCK)) {
480 return inputEvent->IsCapsLocked();
481 }
482 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_NUMLOCK)) {
483 return inputEvent->IsNumLocked();
484 }
486 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_FN)) {
487 return inputEvent->IsFn();
488 }
489 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SCROLLLOCK)) {
490 return inputEvent->IsScrollLocked();
491 }
492 if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SYMBOLLOCK)) {
493 return inputEvent->IsSymbolLocked();
494 }
495 return false;
496 }
498 } // namespace dom
499 } // namespace mozilla
501 using namespace mozilla;
502 using namespace mozilla::dom;
504 nsresult
505 NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult,
506 EventTarget* aOwner,
507 nsPresContext* aPresContext,
508 WidgetGUIEvent* aEvent)
509 {
510 UIEvent* it = new UIEvent(aOwner, aPresContext, aEvent);
511 NS_ADDREF(it);
512 *aInstancePtrResult = static_cast<Event*>(it);
513 return NS_OK;
514 }