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 "mozilla/ArrayUtils.h"
8 #include "mozilla/layers/CompositorChild.h"
9 #include "mozilla/layers/CompositorParent.h"
10 #include "mozilla/layers/ImageBridgeChild.h"
11 #include "nsBaseWidget.h"
12 #include "nsDeviceContext.h"
13 #include "nsCOMPtr.h"
14 #include "nsGfxCIID.h"
15 #include "nsWidgetsCID.h"
16 #include "nsServiceManagerUtils.h"
17 #include "nsIScreenManager.h"
18 #include "nsAppDirectoryServiceDefs.h"
19 #include "nsISimpleEnumerator.h"
20 #include "nsIContent.h"
21 #include "nsIDocument.h"
22 #include "nsIPresShell.h"
23 #include "nsIServiceManager.h"
24 #include "mozilla/Preferences.h"
25 #include "BasicLayers.h"
26 #include "ClientLayerManager.h"
27 #include "mozilla/layers/Compositor.h"
28 #include "nsIXULRuntime.h"
29 #include "nsIXULWindow.h"
30 #include "nsIBaseWindow.h"
31 #include "nsXULPopupManager.h"
32 #include "nsIWidgetListener.h"
33 #include "nsIGfxInfo.h"
34 #include "npapi.h"
35 #include "base/thread.h"
36 #include "prdtoa.h"
37 #include "prenv.h"
38 #include "mozilla/Attributes.h"
39 #include "mozilla/unused.h"
40 #include "nsContentUtils.h"
41 #include "gfxPrefs.h"
42 #include "mozilla/gfx/2D.h"
43 #include "mozilla/MouseEvents.h"
44 #include "GLConsts.h"
45 #include "LayerScope.h"
46 #include "mozilla/unused.h"
48 #ifdef ACCESSIBILITY
49 #include "nsAccessibilityService.h"
50 #endif
52 #ifdef DEBUG
53 #include "nsIObserver.h"
55 static void debug_RegisterPrefCallbacks();
57 #endif
59 #ifdef NOISY_WIDGET_LEAKS
60 static int32_t gNumWidgets;
61 #endif
63 #ifdef XP_MACOSX
64 #include "nsCocoaFeatures.h"
65 #endif
67 nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
69 using namespace mozilla::layers;
70 using namespace mozilla::ipc;
71 using namespace mozilla;
72 using base::Thread;
74 nsIContent* nsBaseWidget::mLastRollup = nullptr;
75 // Global user preference for disabling native theme. Used
76 // in NativeWindowTheme.
77 bool gDisableNativeTheme = false;
79 // Async pump timer during injected long touch taps
80 #define TOUCH_INJECT_PUMP_TIMER_MSEC 50
81 #define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
82 int32_t nsIWidget::sPointerIdCounter = 0;
84 // nsBaseWidget
85 NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidget)
88 nsAutoRollup::nsAutoRollup()
89 {
90 // remember if mLastRollup was null, and only clear it upon destruction
91 // if so. This prevents recursive usage of nsAutoRollup from clearing
92 // mLastRollup when it shouldn't.
93 wasClear = !nsBaseWidget::mLastRollup;
94 }
96 nsAutoRollup::~nsAutoRollup()
97 {
98 if (nsBaseWidget::mLastRollup && wasClear) {
99 NS_RELEASE(nsBaseWidget::mLastRollup);
100 }
101 }
103 //-------------------------------------------------------------------------
104 //
105 // nsBaseWidget constructor
106 //
107 //-------------------------------------------------------------------------
109 nsBaseWidget::nsBaseWidget()
110 : mWidgetListener(nullptr)
111 , mAttachedWidgetListener(nullptr)
112 , mContext(nullptr)
113 , mCursor(eCursor_standard)
114 , mBorderStyle(eBorderStyle_none)
115 , mUseLayersAcceleration(false)
116 , mForceLayersAcceleration(false)
117 , mTemporarilyUseBasicLayerManager(false)
118 , mUseAttachedEvents(false)
119 , mContextInitialized(false)
120 , mBounds(0,0,0,0)
121 , mOriginalBounds(nullptr)
122 , mClipRectCount(0)
123 , mSizeMode(nsSizeMode_Normal)
124 , mPopupLevel(ePopupLevelTop)
125 , mPopupType(ePopupTypeAny)
126 {
127 #ifdef NOISY_WIDGET_LEAKS
128 gNumWidgets++;
129 printf("WIDGETS+ = %d\n", gNumWidgets);
130 #endif
132 #ifdef DEBUG
133 debug_RegisterPrefCallbacks();
134 #endif
136 mShutdownObserver = new WidgetShutdownObserver(this);
137 nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
138 }
140 NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
142 NS_IMETHODIMP
143 WidgetShutdownObserver::Observe(nsISupports *aSubject,
144 const char *aTopic,
145 const char16_t *aData)
146 {
147 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0 &&
148 mWidget) {
149 mWidget->Shutdown();
150 nsContentUtils::UnregisterShutdownObserver(this);
151 }
152 return NS_OK;
153 }
155 void
156 nsBaseWidget::Shutdown()
157 {
158 DestroyCompositor();
159 mShutdownObserver = nullptr;
160 }
162 static void DeferredDestroyCompositor(CompositorParent* aCompositorParent,
163 CompositorChild* aCompositorChild)
164 {
165 // Bug 848949 needs to be fixed before
166 // we can close the channel properly
167 //aCompositorChild->Close();
168 aCompositorParent->Release();
169 aCompositorChild->Release();
170 }
172 void nsBaseWidget::DestroyCompositor()
173 {
174 LayerScope::DestroyServerSocket();
176 if (mCompositorChild) {
177 mCompositorChild->SendWillStop();
178 mCompositorChild->Destroy();
180 // The call just made to SendWillStop can result in IPC from the
181 // CompositorParent to the CompositorChild (e.g. caused by the destruction
182 // of shared memory). We need to ensure this gets processed by the
183 // CompositorChild before it gets destroyed. It suffices to ensure that
184 // events already in the MessageLoop get processed before the
185 // CompositorChild is destroyed, so we add a task to the MessageLoop to
186 // handle compositor desctruction.
187 MessageLoop::current()->PostTask(FROM_HERE,
188 NewRunnableFunction(DeferredDestroyCompositor, mCompositorParent,
189 mCompositorChild));
190 // The DestroyCompositor task we just added to the MessageLoop will handle
191 // releasing mCompositorParent and mCompositorChild.
192 unused << mCompositorParent.forget();
193 unused << mCompositorChild.forget();
194 }
195 }
197 //-------------------------------------------------------------------------
198 //
199 // nsBaseWidget destructor
200 //
201 //-------------------------------------------------------------------------
202 nsBaseWidget::~nsBaseWidget()
203 {
204 if (mLayerManager &&
205 mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
206 static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
207 }
209 if (mLayerManager) {
210 mLayerManager->Destroy();
211 mLayerManager = nullptr;
212 }
214 if (mShutdownObserver) {
215 // If the shutdown observer is currently processing observers,
216 // then UnregisterShutdownObserver won't stop our Observer
217 // function from being called. Make sure we don't try
218 // to reference the dead widget.
219 mShutdownObserver->mWidget = nullptr;
220 nsContentUtils::UnregisterShutdownObserver(mShutdownObserver);
221 }
223 DestroyCompositor();
225 #ifdef NOISY_WIDGET_LEAKS
226 gNumWidgets--;
227 printf("WIDGETS- = %d\n", gNumWidgets);
228 #endif
230 NS_IF_RELEASE(mContext);
231 delete mOriginalBounds;
232 }
235 //-------------------------------------------------------------------------
236 //
237 // Basic create.
238 //
239 //-------------------------------------------------------------------------
240 void nsBaseWidget::BaseCreate(nsIWidget *aParent,
241 const nsIntRect &aRect,
242 nsDeviceContext *aContext,
243 nsWidgetInitData *aInitData)
244 {
245 static bool gDisableNativeThemeCached = false;
246 if (!gDisableNativeThemeCached) {
247 Preferences::AddBoolVarCache(&gDisableNativeTheme,
248 "mozilla.widget.disable-native-theme",
249 gDisableNativeTheme);
250 gDisableNativeThemeCached = true;
251 }
253 // keep a reference to the device context
254 if (aContext) {
255 mContext = aContext;
256 NS_ADDREF(mContext);
257 }
258 else {
259 mContext = new nsDeviceContext();
260 NS_ADDREF(mContext);
261 mContext->Init(nullptr);
262 }
264 if (nullptr != aInitData) {
265 mWindowType = aInitData->mWindowType;
266 mBorderStyle = aInitData->mBorderStyle;
267 mPopupLevel = aInitData->mPopupLevel;
268 mPopupType = aInitData->mPopupHint;
269 mRequireOffMainThreadCompositing = aInitData->mRequireOffMainThreadCompositing;
270 }
272 if (aParent) {
273 aParent->AddChild(this);
274 }
275 }
277 NS_IMETHODIMP nsBaseWidget::CaptureMouse(bool aCapture)
278 {
279 return NS_OK;
280 }
282 //-------------------------------------------------------------------------
283 //
284 // Accessor functions to get/set the client data
285 //
286 //-------------------------------------------------------------------------
288 nsIWidgetListener* nsBaseWidget::GetWidgetListener()
289 {
290 return mWidgetListener;
291 }
293 void nsBaseWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
294 {
295 mWidgetListener = aWidgetListener;
296 }
298 already_AddRefed<nsIWidget>
299 nsBaseWidget::CreateChild(const nsIntRect &aRect,
300 nsDeviceContext *aContext,
301 nsWidgetInitData *aInitData,
302 bool aForceUseIWidgetParent)
303 {
304 nsIWidget* parent = this;
305 nsNativeWidget nativeParent = nullptr;
307 if (!aForceUseIWidgetParent) {
308 // Use only either parent or nativeParent, not both, to match
309 // existing code. Eventually Create() should be divested of its
310 // nativeWidget parameter.
311 nativeParent = parent ? parent->GetNativeData(NS_NATIVE_WIDGET) : nullptr;
312 parent = nativeParent ? nullptr : parent;
313 NS_ABORT_IF_FALSE(!parent || !nativeParent, "messed up logic");
314 }
316 nsCOMPtr<nsIWidget> widget;
317 if (aInitData && aInitData->mWindowType == eWindowType_popup) {
318 widget = AllocateChildPopupWidget();
319 } else {
320 static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
321 widget = do_CreateInstance(kCChildCID);
322 }
324 if (widget &&
325 NS_SUCCEEDED(widget->Create(parent, nativeParent, aRect,
326 aContext, aInitData))) {
327 return widget.forget();
328 }
330 return nullptr;
331 }
333 // Attach a view to our widget which we'll send events to.
334 NS_IMETHODIMP
335 nsBaseWidget::AttachViewToTopLevel(bool aUseAttachedEvents,
336 nsDeviceContext *aContext)
337 {
338 NS_ASSERTION((mWindowType == eWindowType_toplevel ||
339 mWindowType == eWindowType_dialog ||
340 mWindowType == eWindowType_invisible ||
341 mWindowType == eWindowType_child),
342 "Can't attach to window of that type");
344 mUseAttachedEvents = aUseAttachedEvents;
346 if (aContext) {
347 if (mContext) {
348 NS_IF_RELEASE(mContext);
349 }
350 mContext = aContext;
351 NS_ADDREF(mContext);
352 }
354 return NS_OK;
355 }
357 nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener()
358 {
359 return mAttachedWidgetListener;
360 }
362 void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener)
363 {
364 mAttachedWidgetListener = aListener;
365 }
367 //-------------------------------------------------------------------------
368 //
369 // Close this nsBaseWidget
370 //
371 //-------------------------------------------------------------------------
372 NS_METHOD nsBaseWidget::Destroy()
373 {
374 // Just in case our parent is the only ref to us
375 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
376 // disconnect from the parent
377 nsIWidget *parent = GetParent();
378 if (parent) {
379 parent->RemoveChild(this);
380 }
382 return NS_OK;
383 }
386 //-------------------------------------------------------------------------
387 //
388 // Set this nsBaseWidget's parent
389 //
390 //-------------------------------------------------------------------------
391 NS_IMETHODIMP nsBaseWidget::SetParent(nsIWidget* aNewParent)
392 {
393 return NS_ERROR_NOT_IMPLEMENTED;
394 }
397 //-------------------------------------------------------------------------
398 //
399 // Get this nsBaseWidget parent
400 //
401 //-------------------------------------------------------------------------
402 nsIWidget* nsBaseWidget::GetParent(void)
403 {
404 return nullptr;
405 }
407 //-------------------------------------------------------------------------
408 //
409 // Get this nsBaseWidget top level widget
410 //
411 //-------------------------------------------------------------------------
412 nsIWidget* nsBaseWidget::GetTopLevelWidget()
413 {
414 nsIWidget *topLevelWidget = nullptr, *widget = this;
415 while (widget) {
416 topLevelWidget = widget;
417 widget = widget->GetParent();
418 }
419 return topLevelWidget;
420 }
422 //-------------------------------------------------------------------------
423 //
424 // Get this nsBaseWidget's top (non-sheet) parent (if it's a sheet)
425 //
426 //-------------------------------------------------------------------------
427 nsIWidget* nsBaseWidget::GetSheetWindowParent(void)
428 {
429 return nullptr;
430 }
432 float nsBaseWidget::GetDPI()
433 {
434 return 96.0f;
435 }
437 CSSToLayoutDeviceScale nsIWidget::GetDefaultScale()
438 {
439 double devPixelsPerCSSPixel = DefaultScaleOverride();
441 if (devPixelsPerCSSPixel <= 0.0) {
442 devPixelsPerCSSPixel = GetDefaultScaleInternal();
443 }
445 return CSSToLayoutDeviceScale(devPixelsPerCSSPixel);
446 }
448 /* static */
449 double nsIWidget::DefaultScaleOverride()
450 {
451 // The number of device pixels per CSS pixel. A value <= 0 means choose
452 // automatically based on the DPI. A positive value is used as-is. This effectively
453 // controls the size of a CSS "px".
454 double devPixelsPerCSSPixel = -1.0;
456 nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
457 if (!prefString.IsEmpty()) {
458 devPixelsPerCSSPixel = PR_strtod(prefString, nullptr);
459 }
461 return devPixelsPerCSSPixel;
462 }
464 //-------------------------------------------------------------------------
465 //
466 // Add a child to the list of children
467 //
468 //-------------------------------------------------------------------------
469 void nsBaseWidget::AddChild(nsIWidget* aChild)
470 {
471 NS_PRECONDITION(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
472 "aChild not properly removed from its old child list");
474 if (!mFirstChild) {
475 mFirstChild = mLastChild = aChild;
476 } else {
477 // append to the list
478 NS_ASSERTION(mLastChild, "Bogus state");
479 NS_ASSERTION(!mLastChild->GetNextSibling(), "Bogus state");
480 mLastChild->SetNextSibling(aChild);
481 aChild->SetPrevSibling(mLastChild);
482 mLastChild = aChild;
483 }
484 }
487 //-------------------------------------------------------------------------
488 //
489 // Remove a child from the list of children
490 //
491 //-------------------------------------------------------------------------
492 void nsBaseWidget::RemoveChild(nsIWidget* aChild)
493 {
494 #ifdef DEBUG
495 #ifdef XP_MACOSX
496 // nsCocoaWindow doesn't implement GetParent, so in that case parent will be
497 // null and we'll just have to do without this assertion.
498 nsIWidget* parent = aChild->GetParent();
499 NS_ASSERTION(!parent || parent == this, "Not one of our kids!");
500 #else
501 NS_ASSERTION(aChild->GetParent() == this, "Not one of our kids!");
502 #endif
503 #endif
505 if (mLastChild == aChild) {
506 mLastChild = mLastChild->GetPrevSibling();
507 }
508 if (mFirstChild == aChild) {
509 mFirstChild = mFirstChild->GetNextSibling();
510 }
512 // Now remove from the list. Make sure that we pass ownership of the tail
513 // of the list correctly before we have aChild let go of it.
514 nsIWidget* prev = aChild->GetPrevSibling();
515 nsIWidget* next = aChild->GetNextSibling();
516 if (prev) {
517 prev->SetNextSibling(next);
518 }
519 if (next) {
520 next->SetPrevSibling(prev);
521 }
523 aChild->SetNextSibling(nullptr);
524 aChild->SetPrevSibling(nullptr);
525 }
528 //-------------------------------------------------------------------------
529 //
530 // Sets widget's position within its parent's child list.
531 //
532 //-------------------------------------------------------------------------
533 void nsBaseWidget::SetZIndex(int32_t aZIndex)
534 {
535 // Hold a ref to ourselves just in case, since we're going to remove
536 // from our parent.
537 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
539 mZIndex = aZIndex;
541 // reorder this child in its parent's list.
542 nsBaseWidget* parent = static_cast<nsBaseWidget*>(GetParent());
543 if (parent) {
544 parent->RemoveChild(this);
545 // Scope sib outside the for loop so we can check it afterward
546 nsIWidget* sib = parent->GetFirstChild();
547 for ( ; sib; sib = sib->GetNextSibling()) {
548 int32_t childZIndex = GetZIndex();
549 if (aZIndex < childZIndex) {
550 // Insert ourselves before sib
551 nsIWidget* prev = sib->GetPrevSibling();
552 mNextSibling = sib;
553 mPrevSibling = prev;
554 sib->SetPrevSibling(this);
555 if (prev) {
556 prev->SetNextSibling(this);
557 } else {
558 NS_ASSERTION(sib == parent->mFirstChild, "Broken child list");
559 // We've taken ownership of sib, so it's safe to have parent let
560 // go of it
561 parent->mFirstChild = this;
562 }
563 PlaceBehind(eZPlacementBelow, sib, false);
564 break;
565 }
566 }
567 // were we added to the list?
568 if (!sib) {
569 parent->AddChild(this);
570 }
571 }
572 }
574 //-------------------------------------------------------------------------
575 //
576 // Places widget behind the given widget (platforms must override)
577 //
578 //-------------------------------------------------------------------------
579 NS_IMETHODIMP nsBaseWidget::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
580 nsIWidget *aWidget, bool aActivate)
581 {
582 return NS_OK;
583 }
585 //-------------------------------------------------------------------------
586 //
587 // Maximize, minimize or restore the window. The BaseWidget implementation
588 // merely stores the state.
589 //
590 //-------------------------------------------------------------------------
591 NS_IMETHODIMP nsBaseWidget::SetSizeMode(int32_t aMode)
592 {
593 if (aMode == nsSizeMode_Normal ||
594 aMode == nsSizeMode_Minimized ||
595 aMode == nsSizeMode_Maximized ||
596 aMode == nsSizeMode_Fullscreen) {
598 mSizeMode = (nsSizeMode) aMode;
599 return NS_OK;
600 }
601 return NS_ERROR_ILLEGAL_VALUE;
602 }
604 //-------------------------------------------------------------------------
605 //
606 // Get this component cursor
607 //
608 //-------------------------------------------------------------------------
609 nsCursor nsBaseWidget::GetCursor()
610 {
611 return mCursor;
612 }
614 NS_METHOD nsBaseWidget::SetCursor(nsCursor aCursor)
615 {
616 mCursor = aCursor;
617 return NS_OK;
618 }
620 NS_IMETHODIMP nsBaseWidget::SetCursor(imgIContainer* aCursor,
621 uint32_t aHotspotX, uint32_t aHotspotY)
622 {
623 return NS_ERROR_NOT_IMPLEMENTED;
624 }
626 //-------------------------------------------------------------------------
627 //
628 // Window transparency methods
629 //
630 //-------------------------------------------------------------------------
632 void nsBaseWidget::SetTransparencyMode(nsTransparencyMode aMode) {
633 }
635 nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
636 return eTransparencyOpaque;
637 }
639 bool
640 nsBaseWidget::StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects)
641 {
642 if (mClipRects && mClipRectCount == aRects.Length() &&
643 memcmp(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount) == 0)
644 return false;
646 mClipRectCount = aRects.Length();
647 mClipRects = new nsIntRect[mClipRectCount];
648 if (mClipRects) {
649 memcpy(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount);
650 }
651 return true;
652 }
654 void
655 nsBaseWidget::GetWindowClipRegion(nsTArray<nsIntRect>* aRects)
656 {
657 if (mClipRects) {
658 aRects->AppendElements(mClipRects.get(), mClipRectCount);
659 } else {
660 aRects->AppendElement(nsIntRect(0, 0, mBounds.width, mBounds.height));
661 }
662 }
664 //-------------------------------------------------------------------------
665 //
666 // Set window shadow style
667 //
668 //-------------------------------------------------------------------------
670 NS_IMETHODIMP nsBaseWidget::SetWindowShadowStyle(int32_t aMode)
671 {
672 return NS_ERROR_NOT_IMPLEMENTED;
673 }
675 //-------------------------------------------------------------------------
676 //
677 // Hide window borders/decorations for this widget
678 //
679 //-------------------------------------------------------------------------
680 NS_IMETHODIMP nsBaseWidget::HideWindowChrome(bool aShouldHide)
681 {
682 return NS_ERROR_NOT_IMPLEMENTED;
683 }
685 //-------------------------------------------------------------------------
686 //
687 // Put the window into full-screen mode
688 //
689 //-------------------------------------------------------------------------
690 NS_IMETHODIMP nsBaseWidget::MakeFullScreen(bool aFullScreen)
691 {
692 HideWindowChrome(aFullScreen);
694 if (aFullScreen) {
695 if (!mOriginalBounds)
696 mOriginalBounds = new nsIntRect();
697 GetScreenBounds(*mOriginalBounds);
698 // convert dev pix to display pix for window manipulation
699 CSSToLayoutDeviceScale scale = GetDefaultScale();
700 mOriginalBounds->x = NSToIntRound(mOriginalBounds->x / scale.scale);
701 mOriginalBounds->y = NSToIntRound(mOriginalBounds->y / scale.scale);
702 mOriginalBounds->width = NSToIntRound(mOriginalBounds->width / scale.scale);
703 mOriginalBounds->height = NSToIntRound(mOriginalBounds->height / scale.scale);
705 // Move to top-left corner of screen and size to the screen dimensions
706 nsCOMPtr<nsIScreenManager> screenManager;
707 screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
708 NS_ASSERTION(screenManager, "Unable to grab screenManager.");
709 if (screenManager) {
710 nsCOMPtr<nsIScreen> screen;
711 screenManager->ScreenForRect(mOriginalBounds->x,
712 mOriginalBounds->y,
713 mOriginalBounds->width,
714 mOriginalBounds->height,
715 getter_AddRefs(screen));
716 if (screen) {
717 int32_t left, top, width, height;
718 if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
719 Resize(left, top, width, height, true);
720 }
721 }
722 }
724 } else if (mOriginalBounds) {
725 Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
726 mOriginalBounds->height, true);
727 }
729 return NS_OK;
730 }
732 nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
733 nsBaseWidget* aWidget, gfxContext* aTarget,
734 BufferMode aDoubleBuffering, ScreenRotation aRotation)
735 : mWidget(aWidget)
736 {
737 mLayerManager = static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
738 if (mLayerManager) {
739 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
740 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
741 mLayerManager->SetDefaultTarget(aTarget);
742 mLayerManager->SetDefaultTargetConfiguration(aDoubleBuffering, aRotation);
743 }
744 }
746 nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
747 {
748 if (mLayerManager) {
749 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
750 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
751 mLayerManager->SetDefaultTarget(nullptr);
752 mLayerManager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, ROTATION_0);
753 }
754 }
756 nsBaseWidget::AutoUseBasicLayerManager::AutoUseBasicLayerManager(nsBaseWidget* aWidget)
757 : mWidget(aWidget)
758 {
759 mPreviousTemporarilyUseBasicLayerManager =
760 mWidget->mTemporarilyUseBasicLayerManager;
761 mWidget->mTemporarilyUseBasicLayerManager = true;
762 }
764 nsBaseWidget::AutoUseBasicLayerManager::~AutoUseBasicLayerManager()
765 {
766 mWidget->mTemporarilyUseBasicLayerManager =
767 mPreviousTemporarilyUseBasicLayerManager;
768 }
770 bool
771 nsBaseWidget::ComputeShouldAccelerate(bool aDefault)
772 {
773 #if defined(XP_WIN) || defined(ANDROID) || \
774 defined(MOZ_GL_PROVIDER) || defined(XP_MACOSX) || defined(MOZ_WIDGET_QT)
775 bool accelerateByDefault = true;
776 #else
777 bool accelerateByDefault = false;
778 #endif
780 #ifdef XP_MACOSX
781 // 10.6.2 and lower have a bug involving textures and pixel buffer objects
782 // that caused bug 629016, so we don't allow OpenGL-accelerated layers on
783 // those versions of the OS.
784 // This will still let full-screen video be accelerated on OpenGL, because
785 // that XUL widget opts in to acceleration, but that's probably OK.
786 SInt32 major = nsCocoaFeatures::OSXVersionMajor();
787 SInt32 minor = nsCocoaFeatures::OSXVersionMinor();
788 SInt32 bugfix = nsCocoaFeatures::OSXVersionBugFix();
789 if (major == 10 && minor == 6 && bugfix <= 2) {
790 accelerateByDefault = false;
791 }
792 #endif
794 // we should use AddBoolPrefVarCache
795 bool disableAcceleration = gfxPrefs::LayersAccelerationDisabled();
796 mForceLayersAcceleration = gfxPrefs::LayersAccelerationForceEnabled();
798 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
799 accelerateByDefault = accelerateByDefault ||
800 (acceleratedEnv && (*acceleratedEnv != '0'));
802 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
803 bool safeMode = false;
804 if (xr)
805 xr->GetInSafeMode(&safeMode);
807 bool whitelisted = false;
809 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
810 if (gfxInfo) {
811 // bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
812 // as that's what causes GfxInfo initialization which kills the zombie 'glxtest' process.
813 // initially we relied on the fact that GetFeatureStatus calls GetData for us, but bug 681026 showed
814 // that assumption to be unsafe.
815 gfxInfo->GetData();
817 int32_t status;
818 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) {
819 if (status == nsIGfxInfo::FEATURE_NO_INFO) {
820 whitelisted = true;
821 }
822 }
823 }
825 if (disableAcceleration || safeMode)
826 return false;
828 if (mForceLayersAcceleration)
829 return true;
831 if (!whitelisted) {
832 static int tell_me_once = 0;
833 if (!tell_me_once) {
834 NS_WARNING("OpenGL-accelerated layers are not supported on this system");
835 tell_me_once = 1;
836 }
837 #ifdef MOZ_ANDROID_OMTC
838 NS_RUNTIMEABORT("OpenGL-accelerated layers are a hard requirement on this platform. "
839 "Cannot continue without support for them");
840 #endif
841 return false;
842 }
844 if (accelerateByDefault)
845 return true;
847 /* use the window acceleration flag */
848 return aDefault;
849 }
851 CompositorParent* nsBaseWidget::NewCompositorParent(int aSurfaceWidth,
852 int aSurfaceHeight)
853 {
854 return new CompositorParent(this, false, aSurfaceWidth, aSurfaceHeight);
855 }
857 void nsBaseWidget::CreateCompositor()
858 {
859 nsIntRect rect;
860 GetBounds(rect);
861 CreateCompositor(rect.width, rect.height);
862 }
864 void
865 nsBaseWidget::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints)
866 {
867 if (mUseLayersAcceleration) {
868 aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
869 }
871 aHints.AppendElement(LayersBackend::LAYERS_BASIC);
872 }
874 static void
875 CheckForBasicBackends(nsTArray<LayersBackend>& aHints)
876 {
877 for (size_t i = 0; i < aHints.Length(); ++i) {
878 if (aHints[i] == LayersBackend::LAYERS_BASIC &&
879 !Preferences::GetBool("layers.offmainthreadcomposition.force-basic", false)) {
880 // basic compositor is not stable enough for regular use
881 aHints[i] = LayersBackend::LAYERS_NONE;
882 }
883 }
884 }
886 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
887 {
888 // Recreating this is tricky, as we may still have an old and we need
889 // to make sure it's properly destroyed by calling DestroyCompositor!
891 // If we've already received a shutdown notification, don't try
892 // create a new compositor.
893 if (!mShutdownObserver) {
894 return;
895 }
897 // The server socket has to be created on the main thread.
898 LayerScope::CreateServerSocket();
900 mCompositorParent = NewCompositorParent(aWidth, aHeight);
901 MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
902 ClientLayerManager* lm = new ClientLayerManager(this);
903 MessageLoop *childMessageLoop = CompositorParent::CompositorLoop();
904 mCompositorChild = new CompositorChild(lm);
905 mCompositorChild->Open(parentChannel, childMessageLoop, ipc::ChildSide);
907 TextureFactoryIdentifier textureFactoryIdentifier;
908 PLayerTransactionChild* shadowManager = nullptr;
909 nsTArray<LayersBackend> backendHints;
910 GetPreferredCompositorBackends(backendHints);
912 if (!mRequireOffMainThreadCompositing) {
913 CheckForBasicBackends(backendHints);
914 }
916 bool success = false;
917 if (!backendHints.IsEmpty()) {
918 shadowManager = mCompositorChild->SendPLayerTransactionConstructor(
919 backendHints, 0, &textureFactoryIdentifier, &success);
920 }
922 if (success) {
923 ShadowLayerForwarder* lf = lm->AsShadowForwarder();
924 if (!lf) {
925 delete lm;
926 mCompositorChild = nullptr;
927 return;
928 }
929 lf->SetShadowManager(shadowManager);
930 lf->IdentifyTextureHost(textureFactoryIdentifier);
931 ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
932 WindowUsesOMTC();
934 mLayerManager = lm;
935 return;
936 }
938 NS_WARNING("Failed to create an OMT compositor.");
939 DestroyCompositor();
940 // Compositor child had the only reference to LayerManager and will have
941 // deallocated it when being freed.
942 }
944 bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
945 {
946 return CompositorParent::CompositorLoop();
947 }
949 LayerManager* nsBaseWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
950 LayersBackend aBackendHint,
951 LayerManagerPersistence aPersistence,
952 bool* aAllowRetaining)
953 {
954 if (!mLayerManager) {
956 mUseLayersAcceleration = ComputeShouldAccelerate(mUseLayersAcceleration);
958 // Try to use an async compositor first, if possible
959 if (ShouldUseOffMainThreadCompositing()) {
960 // e10s uses the parameter to pass in the shadow manager from the TabChild
961 // so we don't expect to see it there since this doesn't support e10s.
962 NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
963 CreateCompositor();
964 }
966 if (!mLayerManager) {
967 mLayerManager = CreateBasicLayerManager();
968 }
969 }
970 if (mTemporarilyUseBasicLayerManager && !mBasicLayerManager) {
971 mBasicLayerManager = CreateBasicLayerManager();
972 }
973 LayerManager* usedLayerManager = mTemporarilyUseBasicLayerManager ?
974 mBasicLayerManager : mLayerManager;
975 if (aAllowRetaining) {
976 *aAllowRetaining = (usedLayerManager == mLayerManager);
977 }
978 return usedLayerManager;
979 }
981 LayerManager* nsBaseWidget::CreateBasicLayerManager()
982 {
983 return new BasicLayerManager(this);
984 }
986 CompositorChild* nsBaseWidget::GetRemoteRenderer()
987 {
988 return mCompositorChild;
989 }
991 TemporaryRef<mozilla::gfx::DrawTarget> nsBaseWidget::StartRemoteDrawing()
992 {
993 return nullptr;
994 }
996 //-------------------------------------------------------------------------
997 //
998 // Return the used device context
999 //
1000 //-------------------------------------------------------------------------
1001 nsDeviceContext* nsBaseWidget::GetDeviceContext()
1002 {
1003 if (!mContextInitialized) {
1004 mContext->Init(this);
1005 mContextInitialized = true;
1006 }
1007 return mContext;
1008 }
1010 //-------------------------------------------------------------------------
1011 //
1012 // Get the thebes surface
1013 //
1014 //-------------------------------------------------------------------------
1015 gfxASurface *nsBaseWidget::GetThebesSurface()
1016 {
1017 // in theory we should get our parent's surface,
1018 // clone it, and set a device offset before returning
1019 return nullptr;
1020 }
1023 //-------------------------------------------------------------------------
1024 //
1025 // Destroy the window
1026 //
1027 //-------------------------------------------------------------------------
1028 void nsBaseWidget::OnDestroy()
1029 {
1030 // release references to device context and app shell
1031 NS_IF_RELEASE(mContext);
1032 }
1034 NS_METHOD nsBaseWidget::SetWindowClass(const nsAString& xulWinType)
1035 {
1036 return NS_ERROR_NOT_IMPLEMENTED;
1037 }
1039 NS_METHOD nsBaseWidget::MoveClient(double aX, double aY)
1040 {
1041 nsIntPoint clientOffset(GetClientOffset());
1043 // GetClientOffset returns device pixels; scale back to display pixels
1044 // if that's what this widget uses for the Move/Resize APIs
1045 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
1046 ? GetDefaultScale()
1047 : CSSToLayoutDeviceScale(1.0);
1048 aX -= clientOffset.x * 1.0 / scale.scale;
1049 aY -= clientOffset.y * 1.0 / scale.scale;
1051 return Move(aX, aY);
1052 }
1054 NS_METHOD nsBaseWidget::ResizeClient(double aWidth,
1055 double aHeight,
1056 bool aRepaint)
1057 {
1058 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1059 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1061 nsIntRect clientBounds;
1062 GetClientBounds(clientBounds);
1064 // GetClientBounds and mBounds are device pixels; scale back to display pixels
1065 // if that's what this widget uses for the Move/Resize APIs
1066 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
1067 ? GetDefaultScale()
1068 : CSSToLayoutDeviceScale(1.0);
1069 double invScale = 1.0 / scale.scale;
1070 aWidth = mBounds.width * invScale + (aWidth - clientBounds.width * invScale);
1071 aHeight = mBounds.height * invScale + (aHeight - clientBounds.height * invScale);
1073 return Resize(aWidth, aHeight, aRepaint);
1074 }
1076 NS_METHOD nsBaseWidget::ResizeClient(double aX,
1077 double aY,
1078 double aWidth,
1079 double aHeight,
1080 bool aRepaint)
1081 {
1082 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1083 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1085 nsIntRect clientBounds;
1086 GetClientBounds(clientBounds);
1088 double scale = BoundsUseDisplayPixels() ? 1.0 / GetDefaultScale().scale : 1.0;
1089 aWidth = mBounds.width * scale + (aWidth - clientBounds.width * scale);
1090 aHeight = mBounds.height * scale + (aHeight - clientBounds.height * scale);
1092 nsIntPoint clientOffset(GetClientOffset());
1093 aX -= clientOffset.x * scale;
1094 aY -= clientOffset.y * scale;
1096 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1097 }
1099 //-------------------------------------------------------------------------
1100 //
1101 // Bounds
1102 //
1103 //-------------------------------------------------------------------------
1105 /**
1106 * If the implementation of nsWindow supports borders this method MUST be overridden
1107 *
1108 **/
1109 NS_METHOD nsBaseWidget::GetClientBounds(nsIntRect &aRect)
1110 {
1111 return GetBounds(aRect);
1112 }
1114 /**
1115 * If the implementation of nsWindow supports borders this method MUST be overridden
1116 *
1117 **/
1118 NS_METHOD nsBaseWidget::GetBounds(nsIntRect &aRect)
1119 {
1120 aRect = mBounds;
1121 return NS_OK;
1122 }
1124 /**
1125 * If the implementation of nsWindow uses a local coordinate system within the window,
1126 * this method must be overridden
1127 *
1128 **/
1129 NS_METHOD nsBaseWidget::GetScreenBounds(nsIntRect &aRect)
1130 {
1131 return GetBounds(aRect);
1132 }
1134 nsIntPoint nsBaseWidget::GetClientOffset()
1135 {
1136 return nsIntPoint(0, 0);
1137 }
1139 NS_IMETHODIMP
1140 nsBaseWidget::GetNonClientMargins(nsIntMargin &margins)
1141 {
1142 return NS_ERROR_NOT_IMPLEMENTED;
1143 }
1145 NS_IMETHODIMP
1146 nsBaseWidget::SetNonClientMargins(nsIntMargin &margins)
1147 {
1148 return NS_ERROR_NOT_IMPLEMENTED;
1149 }
1151 NS_METHOD nsBaseWidget::EnableDragDrop(bool aEnable)
1152 {
1153 return NS_OK;
1154 }
1156 uint32_t nsBaseWidget::GetMaxTouchPoints() const
1157 {
1158 return 0;
1159 }
1161 NS_METHOD nsBaseWidget::SetModal(bool aModal)
1162 {
1163 return NS_ERROR_FAILURE;
1164 }
1166 NS_IMETHODIMP
1167 nsBaseWidget::GetAttention(int32_t aCycleCount) {
1168 return NS_OK;
1169 }
1171 bool
1172 nsBaseWidget::HasPendingInputEvent()
1173 {
1174 return false;
1175 }
1177 NS_IMETHODIMP
1178 nsBaseWidget::SetIcon(const nsAString&)
1179 {
1180 return NS_OK;
1181 }
1183 NS_IMETHODIMP
1184 nsBaseWidget::SetWindowTitlebarColor(nscolor aColor, bool aActive)
1185 {
1186 return NS_ERROR_NOT_IMPLEMENTED;
1187 }
1189 bool
1190 nsBaseWidget::ShowsResizeIndicator(nsIntRect* aResizerRect)
1191 {
1192 return false;
1193 }
1195 NS_IMETHODIMP
1196 nsBaseWidget::SetLayersAcceleration(bool aEnabled)
1197 {
1198 if (mUseLayersAcceleration == aEnabled) {
1199 return NS_OK;
1200 }
1202 bool usedAcceleration = mUseLayersAcceleration;
1204 mUseLayersAcceleration = ComputeShouldAccelerate(aEnabled);
1205 // ComputeShouldAccelerate may have set mUseLayersAcceleration to a value
1206 // different from aEnabled.
1207 if (usedAcceleration == mUseLayersAcceleration) {
1208 return NS_OK;
1209 }
1210 if (mLayerManager) {
1211 mLayerManager->Destroy();
1212 }
1213 mLayerManager = nullptr;
1214 return NS_OK;
1215 }
1217 NS_METHOD nsBaseWidget::RegisterTouchWindow()
1218 {
1219 return NS_ERROR_NOT_IMPLEMENTED;
1220 }
1222 NS_METHOD nsBaseWidget::UnregisterTouchWindow()
1223 {
1224 return NS_ERROR_NOT_IMPLEMENTED;
1225 }
1227 NS_IMETHODIMP
1228 nsBaseWidget::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX,
1229 double aOriginalDeltaY,
1230 double& aOverriddenDeltaX,
1231 double& aOverriddenDeltaY)
1232 {
1233 aOverriddenDeltaX = aOriginalDeltaX;
1234 aOverriddenDeltaY = aOriginalDeltaY;
1236 static bool sInitialized = false;
1237 static bool sIsOverrideEnabled = false;
1238 static int32_t sIntFactorX = 0;
1239 static int32_t sIntFactorY = 0;
1241 if (!sInitialized) {
1242 Preferences::AddBoolVarCache(&sIsOverrideEnabled,
1243 "mousewheel.system_scroll_override_on_root_content.enabled", false);
1244 Preferences::AddIntVarCache(&sIntFactorX,
1245 "mousewheel.system_scroll_override_on_root_content.horizontal.factor", 0);
1246 Preferences::AddIntVarCache(&sIntFactorY,
1247 "mousewheel.system_scroll_override_on_root_content.vertical.factor", 0);
1248 sIntFactorX = std::max(sIntFactorX, 0);
1249 sIntFactorY = std::max(sIntFactorY, 0);
1250 sInitialized = true;
1251 }
1253 if (!sIsOverrideEnabled) {
1254 return NS_OK;
1255 }
1257 // The pref value must be larger than 100, otherwise, we don't override the
1258 // delta value.
1259 if (sIntFactorX > 100) {
1260 double factor = static_cast<double>(sIntFactorX) / 100;
1261 aOverriddenDeltaX *= factor;
1262 }
1263 if (sIntFactorY > 100) {
1264 double factor = static_cast<double>(sIntFactorY) / 100;
1265 aOverriddenDeltaY *= factor;
1266 }
1268 return NS_OK;
1269 }
1272 /**
1273 * Modifies aFile to point at an icon file with the given name and suffix. The
1274 * suffix may correspond to a file extension with leading '.' if appropriate.
1275 * Returns true if the icon file exists and can be read.
1276 */
1277 static bool
1278 ResolveIconNameHelper(nsIFile *aFile,
1279 const nsAString &aIconName,
1280 const nsAString &aIconSuffix)
1281 {
1282 aFile->Append(NS_LITERAL_STRING("icons"));
1283 aFile->Append(NS_LITERAL_STRING("default"));
1284 aFile->Append(aIconName + aIconSuffix);
1286 bool readable;
1287 return NS_SUCCEEDED(aFile->IsReadable(&readable)) && readable;
1288 }
1290 /**
1291 * Resolve the given icon name into a local file object. This method is
1292 * intended to be called by subclasses of nsBaseWidget. aIconSuffix is a
1293 * platform specific icon file suffix (e.g., ".ico" under Win32).
1294 *
1295 * If no file is found matching the given parameters, then null is returned.
1296 */
1297 void
1298 nsBaseWidget::ResolveIconName(const nsAString &aIconName,
1299 const nsAString &aIconSuffix,
1300 nsIFile **aResult)
1301 {
1302 *aResult = nullptr;
1304 nsCOMPtr<nsIProperties> dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
1305 if (!dirSvc)
1306 return;
1308 // first check auxilary chrome directories
1310 nsCOMPtr<nsISimpleEnumerator> dirs;
1311 dirSvc->Get(NS_APP_CHROME_DIR_LIST, NS_GET_IID(nsISimpleEnumerator),
1312 getter_AddRefs(dirs));
1313 if (dirs) {
1314 bool hasMore;
1315 while (NS_SUCCEEDED(dirs->HasMoreElements(&hasMore)) && hasMore) {
1316 nsCOMPtr<nsISupports> element;
1317 dirs->GetNext(getter_AddRefs(element));
1318 if (!element)
1319 continue;
1320 nsCOMPtr<nsIFile> file = do_QueryInterface(element);
1321 if (!file)
1322 continue;
1323 if (ResolveIconNameHelper(file, aIconName, aIconSuffix)) {
1324 NS_ADDREF(*aResult = file);
1325 return;
1326 }
1327 }
1328 }
1330 // then check the main app chrome directory
1332 nsCOMPtr<nsIFile> file;
1333 dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
1334 getter_AddRefs(file));
1335 if (file && ResolveIconNameHelper(file, aIconName, aIconSuffix))
1336 NS_ADDREF(*aResult = file);
1337 }
1339 NS_IMETHODIMP
1340 nsBaseWidget::BeginResizeDrag(WidgetGUIEvent* aEvent,
1341 int32_t aHorizontal,
1342 int32_t aVertical)
1343 {
1344 return NS_ERROR_NOT_IMPLEMENTED;
1345 }
1347 NS_IMETHODIMP
1348 nsBaseWidget::BeginMoveDrag(WidgetMouseEvent* aEvent)
1349 {
1350 return NS_ERROR_NOT_IMPLEMENTED;
1351 }
1353 uint32_t
1354 nsBaseWidget::GetGLFrameBufferFormat()
1355 {
1356 return LOCAL_GL_RGBA;
1357 }
1359 void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints)
1360 {
1361 mSizeConstraints = aConstraints;
1362 // We can't ensure that the size is honored at this point because we're
1363 // probably in the middle of a reflow.
1364 }
1366 const widget::SizeConstraints& nsBaseWidget::GetSizeConstraints() const
1367 {
1368 return mSizeConstraints;
1369 }
1371 // static
1372 nsIRollupListener*
1373 nsBaseWidget::GetActiveRollupListener()
1374 {
1375 // If set, then this is likely an <html:select> dropdown.
1376 if (gRollupListener)
1377 return gRollupListener;
1379 return nsXULPopupManager::GetInstance();
1380 }
1382 void
1383 nsBaseWidget::NotifyWindowDestroyed()
1384 {
1385 if (!mWidgetListener)
1386 return;
1388 nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
1389 nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
1390 if (xulWindow) {
1391 xulWindow->Destroy();
1392 }
1393 }
1395 void
1396 nsBaseWidget::NotifySizeMoveDone()
1397 {
1398 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1399 return;
1401 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1402 if (presShell) {
1403 presShell->WindowSizeMoveDone();
1404 }
1405 }
1407 void
1408 nsBaseWidget::NotifyWindowMoved(int32_t aX, int32_t aY)
1409 {
1410 if (mWidgetListener) {
1411 mWidgetListener->WindowMoved(this, aX, aY);
1412 }
1414 if (GetIMEUpdatePreference().WantPositionChanged()) {
1415 NotifyIME(IMENotification(IMEMessage::NOTIFY_IME_OF_POSITION_CHANGE));
1416 }
1417 }
1419 void
1420 nsBaseWidget::NotifySysColorChanged()
1421 {
1422 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1423 return;
1425 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1426 if (presShell) {
1427 presShell->SysColorChanged();
1428 }
1429 }
1431 void
1432 nsBaseWidget::NotifyThemeChanged()
1433 {
1434 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1435 return;
1437 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1438 if (presShell) {
1439 presShell->ThemeChanged();
1440 }
1441 }
1443 void
1444 nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
1445 UIStateChangeType aShowFocusRings)
1446 {
1447 if (!mWidgetListener)
1448 return;
1450 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1451 if (!presShell)
1452 return;
1454 nsIDocument* doc = presShell->GetDocument();
1455 if (doc) {
1456 nsPIDOMWindow* win = doc->GetWindow();
1457 if (win) {
1458 win->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
1459 }
1460 }
1461 }
1463 #ifdef ACCESSIBILITY
1465 a11y::Accessible*
1466 nsBaseWidget::GetRootAccessible()
1467 {
1468 NS_ENSURE_TRUE(mWidgetListener, nullptr);
1470 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1471 NS_ENSURE_TRUE(presShell, nullptr);
1473 // If container is null then the presshell is not active. This often happens
1474 // when a preshell is being held onto for fastback.
1475 nsPresContext* presContext = presShell->GetPresContext();
1476 NS_ENSURE_TRUE(presContext->GetContainerWeak(), nullptr);
1478 // Accessible creation might be not safe so use IsSafeToRunScript to
1479 // make sure it's not created at unsafe times.
1480 nsCOMPtr<nsIAccessibilityService> accService =
1481 services::GetAccessibilityService();
1482 if (accService) {
1483 return accService->GetRootDocumentAccessible(presShell, nsContentUtils::IsSafeToRunScript());
1484 }
1486 return nullptr;
1487 }
1489 #endif // ACCESSIBILITY
1491 nsresult
1492 nsIWidget::SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint, bool aLongTap)
1493 {
1494 if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
1495 sPointerIdCounter = 0;
1496 }
1497 int pointerId = sPointerIdCounter;
1498 sPointerIdCounter++;
1499 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_CONTACT,
1500 aPointerScreenPoint, 1.0, 90);
1501 if (NS_FAILED(rv)) {
1502 return rv;
1503 }
1505 if (!aLongTap) {
1506 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_REMOVE,
1507 aPointerScreenPoint, 0, 0);
1508 return rv;
1509 }
1511 // initiate a long tap
1512 int elapse = Preferences::GetInt("ui.click_hold_context_menus.delay",
1513 TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC);
1514 if (!mLongTapTimer) {
1515 mLongTapTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1516 if (NS_FAILED(rv)) {
1517 SynthesizeNativeTouchPoint(pointerId, TOUCH_CANCEL,
1518 aPointerScreenPoint, 0, 0);
1519 return NS_ERROR_UNEXPECTED;
1520 }
1521 // Windows requires recuring events, so we set this to a smaller window
1522 // than the pref value.
1523 int timeout = elapse;
1524 if (timeout > TOUCH_INJECT_PUMP_TIMER_MSEC) {
1525 timeout = TOUCH_INJECT_PUMP_TIMER_MSEC;
1526 }
1527 mLongTapTimer->InitWithFuncCallback(OnLongTapTimerCallback, this,
1528 timeout,
1529 nsITimer::TYPE_REPEATING_SLACK);
1530 }
1532 // If we already have a long tap pending, cancel it. We only allow one long
1533 // tap to be active at a time.
1534 if (mLongTapTouchPoint) {
1535 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
1536 mLongTapTouchPoint->mPosition, 0, 0);
1537 }
1539 mLongTapTouchPoint = new LongTapInfo(pointerId, aPointerScreenPoint,
1540 TimeDuration::FromMilliseconds(elapse));
1541 return NS_OK;
1542 }
1544 // static
1545 void
1546 nsIWidget::OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure)
1547 {
1548 nsIWidget *self = static_cast<nsIWidget *>(aClosure);
1550 if ((self->mLongTapTouchPoint->mStamp + self->mLongTapTouchPoint->mDuration) >
1551 TimeStamp::Now()) {
1552 #ifdef XP_WIN
1553 // Windows needs us to keep pumping feedback to the digitizer, so update
1554 // the pointer id with the same position.
1555 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
1556 TOUCH_CONTACT,
1557 self->mLongTapTouchPoint->mPosition,
1558 1.0, 90);
1559 #endif
1560 return;
1561 }
1563 // finished, remove the touch point
1564 self->mLongTapTimer->Cancel();
1565 self->mLongTapTimer = nullptr;
1566 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
1567 TOUCH_REMOVE,
1568 self->mLongTapTouchPoint->mPosition,
1569 0, 0);
1570 self->mLongTapTouchPoint = nullptr;
1571 }
1573 nsresult
1574 nsIWidget::ClearNativeTouchSequence()
1575 {
1576 if (!mLongTapTimer) {
1577 return NS_OK;
1578 }
1579 mLongTapTimer->Cancel();
1580 mLongTapTimer = nullptr;
1581 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
1582 mLongTapTouchPoint->mPosition, 0, 0);
1583 mLongTapTouchPoint = nullptr;
1584 return NS_OK;
1585 }
1587 #ifdef DEBUG
1588 //////////////////////////////////////////////////////////////
1589 //
1590 // Convert a GUI event message code to a string.
1591 // Makes it a lot easier to debug events.
1592 //
1593 // See gtk/nsWidget.cpp and windows/nsWindow.cpp
1594 // for a DebugPrintEvent() function that uses
1595 // this.
1596 //
1597 //////////////////////////////////////////////////////////////
1598 /* static */ nsAutoString
1599 nsBaseWidget::debug_GuiEventToString(WidgetGUIEvent* aGuiEvent)
1600 {
1601 NS_ASSERTION(nullptr != aGuiEvent,"cmon, null gui event.");
1603 nsAutoString eventName(NS_LITERAL_STRING("UNKNOWN"));
1605 #define _ASSIGN_eventName(_value,_name)\
1606 case _value: eventName.AssignLiteral(_name) ; break
1608 switch(aGuiEvent->message)
1609 {
1610 _ASSIGN_eventName(NS_BLUR_CONTENT,"NS_BLUR_CONTENT");
1611 _ASSIGN_eventName(NS_DRAGDROP_GESTURE,"NS_DND_GESTURE");
1612 _ASSIGN_eventName(NS_DRAGDROP_DROP,"NS_DND_DROP");
1613 _ASSIGN_eventName(NS_DRAGDROP_ENTER,"NS_DND_ENTER");
1614 _ASSIGN_eventName(NS_DRAGDROP_EXIT,"NS_DND_EXIT");
1615 _ASSIGN_eventName(NS_DRAGDROP_OVER,"NS_DND_OVER");
1616 _ASSIGN_eventName(NS_EDITOR_INPUT,"NS_EDITOR_INPUT");
1617 _ASSIGN_eventName(NS_FOCUS_CONTENT,"NS_FOCUS_CONTENT");
1618 _ASSIGN_eventName(NS_FORM_SELECTED,"NS_FORM_SELECTED");
1619 _ASSIGN_eventName(NS_FORM_CHANGE,"NS_FORM_CHANGE");
1620 _ASSIGN_eventName(NS_FORM_RESET,"NS_FORM_RESET");
1621 _ASSIGN_eventName(NS_FORM_SUBMIT,"NS_FORM_SUBMIT");
1622 _ASSIGN_eventName(NS_IMAGE_ABORT,"NS_IMAGE_ABORT");
1623 _ASSIGN_eventName(NS_LOAD_ERROR,"NS_LOAD_ERROR");
1624 _ASSIGN_eventName(NS_KEY_DOWN,"NS_KEY_DOWN");
1625 _ASSIGN_eventName(NS_KEY_PRESS,"NS_KEY_PRESS");
1626 _ASSIGN_eventName(NS_KEY_UP,"NS_KEY_UP");
1627 _ASSIGN_eventName(NS_MOUSE_ENTER,"NS_MOUSE_ENTER");
1628 _ASSIGN_eventName(NS_MOUSE_EXIT,"NS_MOUSE_EXIT");
1629 _ASSIGN_eventName(NS_MOUSE_BUTTON_DOWN,"NS_MOUSE_BUTTON_DOWN");
1630 _ASSIGN_eventName(NS_MOUSE_BUTTON_UP,"NS_MOUSE_BUTTON_UP");
1631 _ASSIGN_eventName(NS_MOUSE_CLICK,"NS_MOUSE_CLICK");
1632 _ASSIGN_eventName(NS_MOUSE_DOUBLECLICK,"NS_MOUSE_DBLCLICK");
1633 _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE");
1634 _ASSIGN_eventName(NS_LOAD,"NS_LOAD");
1635 _ASSIGN_eventName(NS_POPSTATE,"NS_POPSTATE");
1636 _ASSIGN_eventName(NS_BEFORE_SCRIPT_EXECUTE,"NS_BEFORE_SCRIPT_EXECUTE");
1637 _ASSIGN_eventName(NS_AFTER_SCRIPT_EXECUTE,"NS_AFTER_SCRIPT_EXECUTE");
1638 _ASSIGN_eventName(NS_PAGE_UNLOAD,"NS_PAGE_UNLOAD");
1639 _ASSIGN_eventName(NS_HASHCHANGE,"NS_HASHCHANGE");
1640 _ASSIGN_eventName(NS_READYSTATECHANGE,"NS_READYSTATECHANGE");
1641 _ASSIGN_eventName(NS_XUL_BROADCAST, "NS_XUL_BROADCAST");
1642 _ASSIGN_eventName(NS_XUL_COMMAND_UPDATE, "NS_XUL_COMMAND_UPDATE");
1644 #undef _ASSIGN_eventName
1646 default:
1647 {
1648 char buf[32];
1650 sprintf(buf,"UNKNOWN: %d",aGuiEvent->message);
1652 CopyASCIItoUTF16(buf, eventName);
1653 }
1654 break;
1655 }
1657 return nsAutoString(eventName);
1658 }
1659 //////////////////////////////////////////////////////////////
1660 //
1661 // Code to deal with paint and event debug prefs.
1662 //
1663 //////////////////////////////////////////////////////////////
1664 struct PrefPair
1665 {
1666 const char * name;
1667 bool value;
1668 };
1670 static PrefPair debug_PrefValues[] =
1671 {
1672 { "nglayout.debug.crossing_event_dumping", false },
1673 { "nglayout.debug.event_dumping", false },
1674 { "nglayout.debug.invalidate_dumping", false },
1675 { "nglayout.debug.motion_event_dumping", false },
1676 { "nglayout.debug.paint_dumping", false },
1677 { "nglayout.debug.paint_flashing", false }
1678 };
1680 //////////////////////////////////////////////////////////////
1681 bool
1682 nsBaseWidget::debug_GetCachedBoolPref(const char * aPrefName)
1683 {
1684 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
1686 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
1687 {
1688 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
1689 {
1690 return debug_PrefValues[i].value;
1691 }
1692 }
1694 return false;
1695 }
1696 //////////////////////////////////////////////////////////////
1697 static void debug_SetCachedBoolPref(const char * aPrefName,bool aValue)
1698 {
1699 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
1701 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
1702 {
1703 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
1704 {
1705 debug_PrefValues[i].value = aValue;
1707 return;
1708 }
1709 }
1711 NS_ASSERTION(false, "cmon, this code is not reached dude.");
1712 }
1714 //////////////////////////////////////////////////////////////
1715 class Debug_PrefObserver MOZ_FINAL : public nsIObserver {
1716 public:
1717 NS_DECL_ISUPPORTS
1718 NS_DECL_NSIOBSERVER
1719 };
1721 NS_IMPL_ISUPPORTS(Debug_PrefObserver, nsIObserver)
1723 NS_IMETHODIMP
1724 Debug_PrefObserver::Observe(nsISupports* subject, const char* topic,
1725 const char16_t* data)
1726 {
1727 NS_ConvertUTF16toUTF8 prefName(data);
1729 bool value = Preferences::GetBool(prefName.get(), false);
1730 debug_SetCachedBoolPref(prefName.get(), value);
1731 return NS_OK;
1732 }
1734 //////////////////////////////////////////////////////////////
1735 /* static */ void
1736 debug_RegisterPrefCallbacks()
1737 {
1738 static bool once = true;
1740 if (!once) {
1741 return;
1742 }
1744 once = false;
1746 nsCOMPtr<nsIObserver> obs(new Debug_PrefObserver());
1747 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++) {
1748 // Initialize the pref values
1749 debug_PrefValues[i].value =
1750 Preferences::GetBool(debug_PrefValues[i].name, false);
1752 if (obs) {
1753 // Register callbacks for when these change
1754 Preferences::AddStrongObserver(obs, debug_PrefValues[i].name);
1755 }
1756 }
1757 }
1758 //////////////////////////////////////////////////////////////
1759 static int32_t
1760 _GetPrintCount()
1761 {
1762 static int32_t sCount = 0;
1764 return ++sCount;
1765 }
1766 //////////////////////////////////////////////////////////////
1767 /* static */ bool
1768 nsBaseWidget::debug_WantPaintFlashing()
1769 {
1770 return debug_GetCachedBoolPref("nglayout.debug.paint_flashing");
1771 }
1772 //////////////////////////////////////////////////////////////
1773 /* static */ void
1774 nsBaseWidget::debug_DumpEvent(FILE * aFileOut,
1775 nsIWidget * aWidget,
1776 WidgetGUIEvent* aGuiEvent,
1777 const nsAutoCString & aWidgetName,
1778 int32_t aWindowID)
1779 {
1780 if (aGuiEvent->message == NS_MOUSE_MOVE)
1781 {
1782 if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping"))
1783 return;
1784 }
1786 if (aGuiEvent->message == NS_MOUSE_ENTER ||
1787 aGuiEvent->message == NS_MOUSE_EXIT)
1788 {
1789 if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping"))
1790 return;
1791 }
1793 if (!debug_GetCachedBoolPref("nglayout.debug.event_dumping"))
1794 return;
1796 NS_LossyConvertUTF16toASCII tempString(debug_GuiEventToString(aGuiEvent).get());
1798 fprintf(aFileOut,
1799 "%4d %-26s widget=%-8p name=%-12s id=0x%-6x refpt=%d,%d\n",
1800 _GetPrintCount(),
1801 tempString.get(),
1802 (void *) aWidget,
1803 aWidgetName.get(),
1804 aWindowID,
1805 aGuiEvent->refPoint.x,
1806 aGuiEvent->refPoint.y);
1807 }
1808 //////////////////////////////////////////////////////////////
1809 /* static */ void
1810 nsBaseWidget::debug_DumpPaintEvent(FILE * aFileOut,
1811 nsIWidget * aWidget,
1812 const nsIntRegion & aRegion,
1813 const nsAutoCString & aWidgetName,
1814 int32_t aWindowID)
1815 {
1816 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
1817 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
1819 if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
1820 return;
1822 nsIntRect rect = aRegion.GetBounds();
1823 fprintf(aFileOut,
1824 "%4d PAINT widget=%p name=%-12s id=0x%-6x bounds-rect=%3d,%-3d %3d,%-3d",
1825 _GetPrintCount(),
1826 (void *) aWidget,
1827 aWidgetName.get(),
1828 aWindowID,
1829 rect.x, rect.y, rect.width, rect.height
1830 );
1832 fprintf(aFileOut,"\n");
1833 }
1834 //////////////////////////////////////////////////////////////
1835 /* static */ void
1836 nsBaseWidget::debug_DumpInvalidate(FILE * aFileOut,
1837 nsIWidget * aWidget,
1838 const nsIntRect * aRect,
1839 const nsAutoCString & aWidgetName,
1840 int32_t aWindowID)
1841 {
1842 if (!debug_GetCachedBoolPref("nglayout.debug.invalidate_dumping"))
1843 return;
1845 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
1846 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
1848 fprintf(aFileOut,
1849 "%4d Invalidate widget=%p name=%-12s id=0x%-6x",
1850 _GetPrintCount(),
1851 (void *) aWidget,
1852 aWidgetName.get(),
1853 aWindowID);
1855 if (aRect)
1856 {
1857 fprintf(aFileOut,
1858 " rect=%3d,%-3d %3d,%-3d",
1859 aRect->x,
1860 aRect->y,
1861 aRect->width,
1862 aRect->height);
1863 }
1864 else
1865 {
1866 fprintf(aFileOut,
1867 " rect=%-15s",
1868 "none");
1869 }
1871 fprintf(aFileOut,"\n");
1872 }
1873 //////////////////////////////////////////////////////////////
1875 #endif // DEBUG