Bug 1073336 part 5 - Add AnimationPlayerCollection::PlayerUpdated; r=dbaron
[gecko.git] / widget / nsBaseWidget.cpp
blobed6f888d7bbdc5b3c5a8f6fd643d98efde967d3d
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()
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;
96 nsAutoRollup::~nsAutoRollup()
98 if (nsBaseWidget::mLastRollup && wasClear) {
99 NS_RELEASE(nsBaseWidget::mLastRollup);
103 //-------------------------------------------------------------------------
105 // nsBaseWidget constructor
107 //-------------------------------------------------------------------------
109 nsBaseWidget::nsBaseWidget()
110 : mWidgetListener(nullptr)
111 , mAttachedWidgetListener(nullptr)
112 , mContext(nullptr)
113 , mCursor(eCursor_standard)
114 , mUpdateCursor(true)
115 , mBorderStyle(eBorderStyle_none)
116 , mUseLayersAcceleration(false)
117 , mForceLayersAcceleration(false)
118 , mTemporarilyUseBasicLayerManager(false)
119 , mUseAttachedEvents(false)
120 , mContextInitialized(false)
121 , mBounds(0,0,0,0)
122 , mOriginalBounds(nullptr)
123 , mClipRectCount(0)
124 , mSizeMode(nsSizeMode_Normal)
125 , mPopupLevel(ePopupLevelTop)
126 , mPopupType(ePopupTypeAny)
128 #ifdef NOISY_WIDGET_LEAKS
129 gNumWidgets++;
130 printf("WIDGETS+ = %d\n", gNumWidgets);
131 #endif
133 #ifdef DEBUG
134 debug_RegisterPrefCallbacks();
135 #endif
137 mShutdownObserver = new WidgetShutdownObserver(this);
138 nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
141 NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
143 NS_IMETHODIMP
144 WidgetShutdownObserver::Observe(nsISupports *aSubject,
145 const char *aTopic,
146 const char16_t *aData)
148 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0 &&
149 mWidget) {
150 mWidget->Shutdown();
151 nsContentUtils::UnregisterShutdownObserver(this);
153 return NS_OK;
156 void
157 nsBaseWidget::Shutdown()
159 DestroyCompositor();
160 mShutdownObserver = nullptr;
163 static void DeferredDestroyCompositor(CompositorParent* aCompositorParent,
164 CompositorChild* aCompositorChild)
166 // Bug 848949 needs to be fixed before
167 // we can close the channel properly
168 //aCompositorChild->Close();
169 aCompositorParent->Release();
170 aCompositorChild->Release();
173 void nsBaseWidget::DestroyCompositor()
175 LayerScope::DeInit();
177 if (mCompositorChild) {
178 mCompositorChild->SendWillStop();
179 mCompositorChild->Destroy();
181 // The call just made to SendWillStop can result in IPC from the
182 // CompositorParent to the CompositorChild (e.g. caused by the destruction
183 // of shared memory). We need to ensure this gets processed by the
184 // CompositorChild before it gets destroyed. It suffices to ensure that
185 // events already in the MessageLoop get processed before the
186 // CompositorChild is destroyed, so we add a task to the MessageLoop to
187 // handle compositor desctruction.
188 MessageLoop::current()->PostTask(FROM_HERE,
189 NewRunnableFunction(DeferredDestroyCompositor, mCompositorParent,
190 mCompositorChild));
191 // The DestroyCompositor task we just added to the MessageLoop will handle
192 // releasing mCompositorParent and mCompositorChild.
193 unused << mCompositorParent.forget();
194 unused << mCompositorChild.forget();
198 //-------------------------------------------------------------------------
200 // nsBaseWidget destructor
202 //-------------------------------------------------------------------------
203 nsBaseWidget::~nsBaseWidget()
205 if (mLayerManager &&
206 mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
207 static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
210 if (mLayerManager) {
211 mLayerManager->Destroy();
212 mLayerManager = nullptr;
215 if (mShutdownObserver) {
216 // If the shutdown observer is currently processing observers,
217 // then UnregisterShutdownObserver won't stop our Observer
218 // function from being called. Make sure we don't try
219 // to reference the dead widget.
220 mShutdownObserver->mWidget = nullptr;
221 nsContentUtils::UnregisterShutdownObserver(mShutdownObserver);
224 DestroyCompositor();
226 #ifdef NOISY_WIDGET_LEAKS
227 gNumWidgets--;
228 printf("WIDGETS- = %d\n", gNumWidgets);
229 #endif
231 NS_IF_RELEASE(mContext);
232 delete mOriginalBounds;
236 //-------------------------------------------------------------------------
238 // Basic create.
240 //-------------------------------------------------------------------------
241 void nsBaseWidget::BaseCreate(nsIWidget *aParent,
242 const nsIntRect &aRect,
243 nsDeviceContext *aContext,
244 nsWidgetInitData *aInitData)
246 static bool gDisableNativeThemeCached = false;
247 if (!gDisableNativeThemeCached) {
248 Preferences::AddBoolVarCache(&gDisableNativeTheme,
249 "mozilla.widget.disable-native-theme",
250 gDisableNativeTheme);
251 gDisableNativeThemeCached = true;
254 // keep a reference to the device context
255 if (aContext) {
256 mContext = aContext;
257 NS_ADDREF(mContext);
259 else {
260 mContext = new nsDeviceContext();
261 NS_ADDREF(mContext);
262 mContext->Init(nullptr);
265 if (nullptr != aInitData) {
266 mWindowType = aInitData->mWindowType;
267 mBorderStyle = aInitData->mBorderStyle;
268 mPopupLevel = aInitData->mPopupLevel;
269 mPopupType = aInitData->mPopupHint;
270 mRequireOffMainThreadCompositing = aInitData->mRequireOffMainThreadCompositing;
273 if (aParent) {
274 aParent->AddChild(this);
278 NS_IMETHODIMP nsBaseWidget::CaptureMouse(bool aCapture)
280 return NS_OK;
283 //-------------------------------------------------------------------------
285 // Accessor functions to get/set the client data
287 //-------------------------------------------------------------------------
289 nsIWidgetListener* nsBaseWidget::GetWidgetListener()
291 return mWidgetListener;
294 void nsBaseWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
296 mWidgetListener = aWidgetListener;
299 already_AddRefed<nsIWidget>
300 nsBaseWidget::CreateChild(const nsIntRect &aRect,
301 nsDeviceContext *aContext,
302 nsWidgetInitData *aInitData,
303 bool aForceUseIWidgetParent)
305 nsIWidget* parent = this;
306 nsNativeWidget nativeParent = nullptr;
308 if (!aForceUseIWidgetParent) {
309 // Use only either parent or nativeParent, not both, to match
310 // existing code. Eventually Create() should be divested of its
311 // nativeWidget parameter.
312 nativeParent = parent ? parent->GetNativeData(NS_NATIVE_WIDGET) : nullptr;
313 parent = nativeParent ? nullptr : parent;
314 NS_ABORT_IF_FALSE(!parent || !nativeParent, "messed up logic");
317 nsCOMPtr<nsIWidget> widget;
318 if (aInitData && aInitData->mWindowType == eWindowType_popup) {
319 widget = AllocateChildPopupWidget();
320 } else {
321 static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
322 widget = do_CreateInstance(kCChildCID);
325 if (widget &&
326 NS_SUCCEEDED(widget->Create(parent, nativeParent, aRect,
327 aContext, aInitData))) {
328 return widget.forget();
331 return nullptr;
334 // Attach a view to our widget which we'll send events to.
335 NS_IMETHODIMP
336 nsBaseWidget::AttachViewToTopLevel(bool aUseAttachedEvents,
337 nsDeviceContext *aContext)
339 NS_ASSERTION((mWindowType == eWindowType_toplevel ||
340 mWindowType == eWindowType_dialog ||
341 mWindowType == eWindowType_invisible ||
342 mWindowType == eWindowType_child),
343 "Can't attach to window of that type");
345 mUseAttachedEvents = aUseAttachedEvents;
347 if (aContext) {
348 if (mContext) {
349 NS_IF_RELEASE(mContext);
351 mContext = aContext;
352 NS_ADDREF(mContext);
355 return NS_OK;
358 nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener()
360 return mAttachedWidgetListener;
363 void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener)
365 mAttachedWidgetListener = aListener;
368 //-------------------------------------------------------------------------
370 // Close this nsBaseWidget
372 //-------------------------------------------------------------------------
373 NS_METHOD nsBaseWidget::Destroy()
375 // Just in case our parent is the only ref to us
376 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
377 // disconnect from the parent
378 nsIWidget *parent = GetParent();
379 if (parent) {
380 parent->RemoveChild(this);
383 return NS_OK;
387 //-------------------------------------------------------------------------
389 // Set this nsBaseWidget's parent
391 //-------------------------------------------------------------------------
392 NS_IMETHODIMP nsBaseWidget::SetParent(nsIWidget* aNewParent)
394 return NS_ERROR_NOT_IMPLEMENTED;
398 //-------------------------------------------------------------------------
400 // Get this nsBaseWidget parent
402 //-------------------------------------------------------------------------
403 nsIWidget* nsBaseWidget::GetParent(void)
405 return nullptr;
408 //-------------------------------------------------------------------------
410 // Get this nsBaseWidget top level widget
412 //-------------------------------------------------------------------------
413 nsIWidget* nsBaseWidget::GetTopLevelWidget()
415 nsIWidget *topLevelWidget = nullptr, *widget = this;
416 while (widget) {
417 topLevelWidget = widget;
418 widget = widget->GetParent();
420 return topLevelWidget;
423 //-------------------------------------------------------------------------
425 // Get this nsBaseWidget's top (non-sheet) parent (if it's a sheet)
427 //-------------------------------------------------------------------------
428 nsIWidget* nsBaseWidget::GetSheetWindowParent(void)
430 return nullptr;
433 float nsBaseWidget::GetDPI()
435 return 96.0f;
438 CSSToLayoutDeviceScale nsIWidget::GetDefaultScale()
440 double devPixelsPerCSSPixel = DefaultScaleOverride();
442 if (devPixelsPerCSSPixel <= 0.0) {
443 devPixelsPerCSSPixel = GetDefaultScaleInternal();
446 return CSSToLayoutDeviceScale(devPixelsPerCSSPixel);
449 /* static */
450 double nsIWidget::DefaultScaleOverride()
452 // The number of device pixels per CSS pixel. A value <= 0 means choose
453 // automatically based on the DPI. A positive value is used as-is. This effectively
454 // controls the size of a CSS "px".
455 double devPixelsPerCSSPixel = -1.0;
457 nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
458 if (!prefString.IsEmpty()) {
459 devPixelsPerCSSPixel = PR_strtod(prefString, nullptr);
462 return devPixelsPerCSSPixel;
465 //-------------------------------------------------------------------------
467 // Add a child to the list of children
469 //-------------------------------------------------------------------------
470 void nsBaseWidget::AddChild(nsIWidget* aChild)
472 NS_PRECONDITION(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
473 "aChild not properly removed from its old child list");
475 if (!mFirstChild) {
476 mFirstChild = mLastChild = aChild;
477 } else {
478 // append to the list
479 NS_ASSERTION(mLastChild, "Bogus state");
480 NS_ASSERTION(!mLastChild->GetNextSibling(), "Bogus state");
481 mLastChild->SetNextSibling(aChild);
482 aChild->SetPrevSibling(mLastChild);
483 mLastChild = aChild;
488 //-------------------------------------------------------------------------
490 // Remove a child from the list of children
492 //-------------------------------------------------------------------------
493 void nsBaseWidget::RemoveChild(nsIWidget* aChild)
495 #ifdef DEBUG
496 #ifdef XP_MACOSX
497 // nsCocoaWindow doesn't implement GetParent, so in that case parent will be
498 // null and we'll just have to do without this assertion.
499 nsIWidget* parent = aChild->GetParent();
500 NS_ASSERTION(!parent || parent == this, "Not one of our kids!");
501 #else
502 NS_ASSERTION(aChild->GetParent() == this, "Not one of our kids!");
503 #endif
504 #endif
506 if (mLastChild == aChild) {
507 mLastChild = mLastChild->GetPrevSibling();
509 if (mFirstChild == aChild) {
510 mFirstChild = mFirstChild->GetNextSibling();
513 // Now remove from the list. Make sure that we pass ownership of the tail
514 // of the list correctly before we have aChild let go of it.
515 nsIWidget* prev = aChild->GetPrevSibling();
516 nsIWidget* next = aChild->GetNextSibling();
517 if (prev) {
518 prev->SetNextSibling(next);
520 if (next) {
521 next->SetPrevSibling(prev);
524 aChild->SetNextSibling(nullptr);
525 aChild->SetPrevSibling(nullptr);
529 //-------------------------------------------------------------------------
531 // Sets widget's position within its parent's child list.
533 //-------------------------------------------------------------------------
534 void nsBaseWidget::SetZIndex(int32_t aZIndex)
536 // Hold a ref to ourselves just in case, since we're going to remove
537 // from our parent.
538 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
540 mZIndex = aZIndex;
542 // reorder this child in its parent's list.
543 nsBaseWidget* parent = static_cast<nsBaseWidget*>(GetParent());
544 if (parent) {
545 parent->RemoveChild(this);
546 // Scope sib outside the for loop so we can check it afterward
547 nsIWidget* sib = parent->GetFirstChild();
548 for ( ; sib; sib = sib->GetNextSibling()) {
549 int32_t childZIndex = GetZIndex();
550 if (aZIndex < childZIndex) {
551 // Insert ourselves before sib
552 nsIWidget* prev = sib->GetPrevSibling();
553 mNextSibling = sib;
554 mPrevSibling = prev;
555 sib->SetPrevSibling(this);
556 if (prev) {
557 prev->SetNextSibling(this);
558 } else {
559 NS_ASSERTION(sib == parent->mFirstChild, "Broken child list");
560 // We've taken ownership of sib, so it's safe to have parent let
561 // go of it
562 parent->mFirstChild = this;
564 PlaceBehind(eZPlacementBelow, sib, false);
565 break;
568 // were we added to the list?
569 if (!sib) {
570 parent->AddChild(this);
575 //-------------------------------------------------------------------------
577 // Places widget behind the given widget (platforms must override)
579 //-------------------------------------------------------------------------
580 NS_IMETHODIMP nsBaseWidget::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
581 nsIWidget *aWidget, bool aActivate)
583 return NS_OK;
586 //-------------------------------------------------------------------------
588 // Maximize, minimize or restore the window. The BaseWidget implementation
589 // merely stores the state.
591 //-------------------------------------------------------------------------
592 NS_IMETHODIMP nsBaseWidget::SetSizeMode(int32_t aMode)
594 if (aMode == nsSizeMode_Normal ||
595 aMode == nsSizeMode_Minimized ||
596 aMode == nsSizeMode_Maximized ||
597 aMode == nsSizeMode_Fullscreen) {
599 mSizeMode = (nsSizeMode) aMode;
600 return NS_OK;
602 return NS_ERROR_ILLEGAL_VALUE;
605 //-------------------------------------------------------------------------
607 // Get this component cursor
609 //-------------------------------------------------------------------------
610 nsCursor nsBaseWidget::GetCursor()
612 return mCursor;
615 NS_METHOD nsBaseWidget::SetCursor(nsCursor aCursor)
617 mCursor = aCursor;
618 return NS_OK;
621 NS_IMETHODIMP nsBaseWidget::SetCursor(imgIContainer* aCursor,
622 uint32_t aHotspotX, uint32_t aHotspotY)
624 return NS_ERROR_NOT_IMPLEMENTED;
627 //-------------------------------------------------------------------------
629 // Window transparency methods
631 //-------------------------------------------------------------------------
633 void nsBaseWidget::SetTransparencyMode(nsTransparencyMode aMode) {
636 nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
637 return eTransparencyOpaque;
640 bool
641 nsBaseWidget::StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects)
643 if (mClipRects && mClipRectCount == aRects.Length() &&
644 memcmp(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount) == 0)
645 return false;
647 mClipRectCount = aRects.Length();
648 mClipRects = new nsIntRect[mClipRectCount];
649 if (mClipRects) {
650 memcpy(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount);
652 return true;
655 void
656 nsBaseWidget::GetWindowClipRegion(nsTArray<nsIntRect>* aRects)
658 if (mClipRects) {
659 aRects->AppendElements(mClipRects.get(), mClipRectCount);
660 } else {
661 aRects->AppendElement(nsIntRect(0, 0, mBounds.width, mBounds.height));
665 const nsIntRegion
666 nsBaseWidget::RegionFromArray(const nsTArray<nsIntRect>& aRects)
668 nsIntRegion region;
669 for (uint32_t i = 0; i < aRects.Length(); ++i) {
670 region.Or(region, aRects[i]);
672 return region;
675 void
676 nsBaseWidget::ArrayFromRegion(const nsIntRegion& aRegion, nsTArray<nsIntRect>& aRects)
678 const nsIntRect* r;
679 for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) {
680 aRects.AppendElement(*r);
684 nsresult
685 nsBaseWidget::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
686 bool aIntersectWithExisting)
688 if (!aIntersectWithExisting) {
689 nsBaseWidget::StoreWindowClipRegion(aRects);
690 } else {
691 // In this case still early return if nothing changed.
692 if (mClipRects && mClipRectCount == aRects.Length() &&
693 memcmp(mClipRects,
694 aRects.Elements(),
695 sizeof(nsIntRect)*mClipRectCount) == 0) {
696 return NS_OK;
699 // get current rects
700 nsTArray<nsIntRect> currentRects;
701 GetWindowClipRegion(&currentRects);
702 // create region from them
703 nsIntRegion currentRegion = RegionFromArray(currentRects);
704 // create region from new rects
705 nsIntRegion newRegion = RegionFromArray(aRects);
706 // intersect regions
707 nsIntRegion intersection;
708 intersection.And(currentRegion, newRegion);
709 // create int rect array from intersection
710 nsTArray<nsIntRect> rects;
711 ArrayFromRegion(intersection, rects);
712 // store
713 nsBaseWidget::StoreWindowClipRegion(rects);
715 return NS_OK;
718 //-------------------------------------------------------------------------
720 // Set window shadow style
722 //-------------------------------------------------------------------------
724 NS_IMETHODIMP nsBaseWidget::SetWindowShadowStyle(int32_t aMode)
726 return NS_ERROR_NOT_IMPLEMENTED;
729 //-------------------------------------------------------------------------
731 // Hide window borders/decorations for this widget
733 //-------------------------------------------------------------------------
734 NS_IMETHODIMP nsBaseWidget::HideWindowChrome(bool aShouldHide)
736 return NS_ERROR_NOT_IMPLEMENTED;
739 //-------------------------------------------------------------------------
741 // Put the window into full-screen mode
743 //-------------------------------------------------------------------------
744 NS_IMETHODIMP nsBaseWidget::MakeFullScreen(bool aFullScreen)
746 HideWindowChrome(aFullScreen);
748 if (aFullScreen) {
749 if (!mOriginalBounds)
750 mOriginalBounds = new nsIntRect();
751 GetScreenBounds(*mOriginalBounds);
752 // convert dev pix to display pix for window manipulation
753 CSSToLayoutDeviceScale scale = GetDefaultScale();
754 mOriginalBounds->x = NSToIntRound(mOriginalBounds->x / scale.scale);
755 mOriginalBounds->y = NSToIntRound(mOriginalBounds->y / scale.scale);
756 mOriginalBounds->width = NSToIntRound(mOriginalBounds->width / scale.scale);
757 mOriginalBounds->height = NSToIntRound(mOriginalBounds->height / scale.scale);
759 // Move to top-left corner of screen and size to the screen dimensions
760 nsCOMPtr<nsIScreenManager> screenManager;
761 screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
762 NS_ASSERTION(screenManager, "Unable to grab screenManager.");
763 if (screenManager) {
764 nsCOMPtr<nsIScreen> screen;
765 screenManager->ScreenForRect(mOriginalBounds->x,
766 mOriginalBounds->y,
767 mOriginalBounds->width,
768 mOriginalBounds->height,
769 getter_AddRefs(screen));
770 if (screen) {
771 int32_t left, top, width, height;
772 if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
773 Resize(left, top, width, height, true);
778 } else if (mOriginalBounds) {
779 Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
780 mOriginalBounds->height, true);
783 return NS_OK;
786 nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
787 nsBaseWidget* aWidget, gfxContext* aTarget,
788 BufferMode aDoubleBuffering, ScreenRotation aRotation)
789 : mWidget(aWidget)
791 mLayerManager = static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
792 if (mLayerManager) {
793 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
794 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
795 mLayerManager->SetDefaultTarget(aTarget);
796 mLayerManager->SetDefaultTargetConfiguration(aDoubleBuffering, aRotation);
800 nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
802 if (mLayerManager) {
803 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
804 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
805 mLayerManager->SetDefaultTarget(nullptr);
806 mLayerManager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, ROTATION_0);
810 nsBaseWidget::AutoUseBasicLayerManager::AutoUseBasicLayerManager(nsBaseWidget* aWidget)
811 : mWidget(aWidget)
813 mPreviousTemporarilyUseBasicLayerManager =
814 mWidget->mTemporarilyUseBasicLayerManager;
815 mWidget->mTemporarilyUseBasicLayerManager = true;
818 nsBaseWidget::AutoUseBasicLayerManager::~AutoUseBasicLayerManager()
820 mWidget->mTemporarilyUseBasicLayerManager =
821 mPreviousTemporarilyUseBasicLayerManager;
824 bool
825 nsBaseWidget::ComputeShouldAccelerate(bool aDefault)
827 #if defined(XP_WIN) || defined(ANDROID) || \
828 defined(MOZ_GL_PROVIDER) || defined(XP_MACOSX) || defined(MOZ_WIDGET_QT)
829 bool accelerateByDefault = true;
830 #else
831 bool accelerateByDefault = false;
832 #endif
834 #ifdef XP_MACOSX
835 // 10.6.2 and lower have a bug involving textures and pixel buffer objects
836 // that caused bug 629016, so we don't allow OpenGL-accelerated layers on
837 // those versions of the OS.
838 // This will still let full-screen video be accelerated on OpenGL, because
839 // that XUL widget opts in to acceleration, but that's probably OK.
840 accelerateByDefault = nsCocoaFeatures::AccelerateByDefault();
841 #endif
843 // we should use AddBoolPrefVarCache
844 bool disableAcceleration = gfxPrefs::LayersAccelerationDisabled();
845 mForceLayersAcceleration = gfxPrefs::LayersAccelerationForceEnabled();
847 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
848 accelerateByDefault = accelerateByDefault ||
849 (acceleratedEnv && (*acceleratedEnv != '0'));
851 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
852 bool safeMode = false;
853 if (xr)
854 xr->GetInSafeMode(&safeMode);
856 bool whitelisted = false;
858 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
859 if (gfxInfo) {
860 // bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
861 // as that's what causes GfxInfo initialization which kills the zombie 'glxtest' process.
862 // initially we relied on the fact that GetFeatureStatus calls GetData for us, but bug 681026 showed
863 // that assumption to be unsafe.
864 gfxInfo->GetData();
866 int32_t status;
867 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) {
868 if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
869 whitelisted = true;
874 if (disableAcceleration || safeMode)
875 return false;
877 if (mForceLayersAcceleration)
878 return true;
880 if (!whitelisted) {
881 static int tell_me_once = 0;
882 if (!tell_me_once) {
883 NS_WARNING("OpenGL-accelerated layers are not supported on this system");
884 tell_me_once = 1;
886 #ifdef MOZ_WIDGET_ANDROID
887 NS_RUNTIMEABORT("OpenGL-accelerated layers are a hard requirement on this platform. "
888 "Cannot continue without support for them");
889 #endif
890 return false;
893 if (accelerateByDefault)
894 return true;
896 /* use the window acceleration flag */
897 return aDefault;
900 CompositorParent* nsBaseWidget::NewCompositorParent(int aSurfaceWidth,
901 int aSurfaceHeight)
903 return new CompositorParent(this, false, aSurfaceWidth, aSurfaceHeight);
906 void nsBaseWidget::CreateCompositor()
908 nsIntRect rect;
909 GetBounds(rect);
910 CreateCompositor(rect.width, rect.height);
913 void
914 nsBaseWidget::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints)
916 if (mUseLayersAcceleration) {
917 aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
920 aHints.AppendElement(LayersBackend::LAYERS_BASIC);
923 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
925 // This makes sure that gfxPlatforms gets initialized if it hasn't by now.
926 gfxPlatform::GetPlatform();
928 MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(),
929 "This function assumes OMTC");
931 // Recreating this is tricky, as we may still have an old and we need
932 // to make sure it's properly destroyed by calling DestroyCompositor!
934 // If we've already received a shutdown notification, don't try
935 // create a new compositor.
936 if (!mShutdownObserver) {
937 return;
940 // Initialize LayerScope on the main thread.
941 LayerScope::Init();
943 mCompositorParent = NewCompositorParent(aWidth, aHeight);
944 MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
945 nsRefPtr<ClientLayerManager> lm = new ClientLayerManager(this);
946 MessageLoop *childMessageLoop = CompositorParent::CompositorLoop();
947 mCompositorChild = new CompositorChild(lm);
948 mCompositorChild->Open(parentChannel, childMessageLoop, ipc::ChildSide);
950 TextureFactoryIdentifier textureFactoryIdentifier;
951 PLayerTransactionChild* shadowManager = nullptr;
952 nsTArray<LayersBackend> backendHints;
953 GetPreferredCompositorBackends(backendHints);
955 #if !defined(MOZ_X11) && !defined(XP_WIN)
956 if (!mRequireOffMainThreadCompositing &&
957 !Preferences::GetBool("layers.offmainthreadcomposition.force-basic", false)) {
958 for (size_t i = 0; i < backendHints.Length(); ++i) {
959 if (backendHints[i] == LayersBackend::LAYERS_BASIC) {
960 backendHints[i] = LayersBackend::LAYERS_NONE;
964 #endif
966 bool success = false;
967 if (!backendHints.IsEmpty()) {
968 shadowManager = mCompositorChild->SendPLayerTransactionConstructor(
969 backendHints, 0, &textureFactoryIdentifier, &success);
972 if (success) {
973 ShadowLayerForwarder* lf = lm->AsShadowForwarder();
974 if (!lf) {
975 lm = nullptr;
976 mCompositorChild = nullptr;
977 return;
979 lf->SetShadowManager(shadowManager);
980 lf->IdentifyTextureHost(textureFactoryIdentifier);
981 ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
982 WindowUsesOMTC();
984 mLayerManager = lm.forget();
985 return;
988 NS_WARNING("Failed to create an OMT compositor.");
989 DestroyCompositor();
990 // Compositor child had the only reference to LayerManager and will have
991 // deallocated it when being freed.
994 bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
996 return gfxPlatform::UsesOffMainThreadCompositing();
999 LayerManager* nsBaseWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
1000 LayersBackend aBackendHint,
1001 LayerManagerPersistence aPersistence,
1002 bool* aAllowRetaining)
1004 if (!mLayerManager) {
1006 mUseLayersAcceleration = ComputeShouldAccelerate(mUseLayersAcceleration);
1008 // Try to use an async compositor first, if possible
1009 if (ShouldUseOffMainThreadCompositing()) {
1010 // e10s uses the parameter to pass in the shadow manager from the TabChild
1011 // so we don't expect to see it there since this doesn't support e10s.
1012 NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
1013 CreateCompositor();
1016 if (!mLayerManager) {
1017 mLayerManager = CreateBasicLayerManager();
1020 if (mTemporarilyUseBasicLayerManager && !mBasicLayerManager) {
1021 mBasicLayerManager = CreateBasicLayerManager();
1023 LayerManager* usedLayerManager = mTemporarilyUseBasicLayerManager ?
1024 mBasicLayerManager : mLayerManager;
1025 if (aAllowRetaining) {
1026 *aAllowRetaining = (usedLayerManager == mLayerManager);
1028 return usedLayerManager;
1031 LayerManager* nsBaseWidget::CreateBasicLayerManager()
1033 return new BasicLayerManager(this);
1036 CompositorChild* nsBaseWidget::GetRemoteRenderer()
1038 return mCompositorChild;
1041 TemporaryRef<mozilla::gfx::DrawTarget> nsBaseWidget::StartRemoteDrawing()
1043 return nullptr;
1046 //-------------------------------------------------------------------------
1048 // Return the used device context
1050 //-------------------------------------------------------------------------
1051 nsDeviceContext* nsBaseWidget::GetDeviceContext()
1053 if (!mContextInitialized) {
1054 mContext->Init(this);
1055 mContextInitialized = true;
1057 return mContext;
1060 //-------------------------------------------------------------------------
1062 // Destroy the window
1064 //-------------------------------------------------------------------------
1065 void nsBaseWidget::OnDestroy()
1067 // release references to device context and app shell
1068 NS_IF_RELEASE(mContext);
1071 NS_METHOD nsBaseWidget::SetWindowClass(const nsAString& xulWinType)
1073 return NS_ERROR_NOT_IMPLEMENTED;
1076 NS_METHOD nsBaseWidget::MoveClient(double aX, double aY)
1078 nsIntPoint clientOffset(GetClientOffset());
1080 // GetClientOffset returns device pixels; scale back to display pixels
1081 // if that's what this widget uses for the Move/Resize APIs
1082 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
1083 ? GetDefaultScale()
1084 : CSSToLayoutDeviceScale(1.0);
1085 aX -= clientOffset.x * 1.0 / scale.scale;
1086 aY -= clientOffset.y * 1.0 / scale.scale;
1088 return Move(aX, aY);
1091 NS_METHOD nsBaseWidget::ResizeClient(double aWidth,
1092 double aHeight,
1093 bool aRepaint)
1095 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1096 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1098 nsIntRect clientBounds;
1099 GetClientBounds(clientBounds);
1101 // GetClientBounds and mBounds are device pixels; scale back to display pixels
1102 // if that's what this widget uses for the Move/Resize APIs
1103 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
1104 ? GetDefaultScale()
1105 : CSSToLayoutDeviceScale(1.0);
1106 double invScale = 1.0 / scale.scale;
1107 aWidth = mBounds.width * invScale + (aWidth - clientBounds.width * invScale);
1108 aHeight = mBounds.height * invScale + (aHeight - clientBounds.height * invScale);
1110 return Resize(aWidth, aHeight, aRepaint);
1113 NS_METHOD nsBaseWidget::ResizeClient(double aX,
1114 double aY,
1115 double aWidth,
1116 double aHeight,
1117 bool aRepaint)
1119 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1120 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1122 nsIntRect clientBounds;
1123 GetClientBounds(clientBounds);
1125 double scale = BoundsUseDisplayPixels() ? 1.0 / GetDefaultScale().scale : 1.0;
1126 aWidth = mBounds.width * scale + (aWidth - clientBounds.width * scale);
1127 aHeight = mBounds.height * scale + (aHeight - clientBounds.height * scale);
1129 nsIntPoint clientOffset(GetClientOffset());
1130 aX -= clientOffset.x * scale;
1131 aY -= clientOffset.y * scale;
1133 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1136 //-------------------------------------------------------------------------
1138 // Bounds
1140 //-------------------------------------------------------------------------
1143 * If the implementation of nsWindow supports borders this method MUST be overridden
1146 NS_METHOD nsBaseWidget::GetClientBounds(nsIntRect &aRect)
1148 return GetBounds(aRect);
1152 * If the implementation of nsWindow supports borders this method MUST be overridden
1155 NS_METHOD nsBaseWidget::GetBounds(nsIntRect &aRect)
1157 aRect = mBounds;
1158 return NS_OK;
1162 * If the implementation of nsWindow uses a local coordinate system within the window,
1163 * this method must be overridden
1166 NS_METHOD nsBaseWidget::GetScreenBounds(nsIntRect &aRect)
1168 return GetBounds(aRect);
1171 NS_METHOD nsBaseWidget::GetRestoredBounds(nsIntRect &aRect)
1173 if (SizeMode() != nsSizeMode_Normal) {
1174 return NS_ERROR_FAILURE;
1176 return GetScreenBounds(aRect);
1179 nsIntPoint nsBaseWidget::GetClientOffset()
1181 return nsIntPoint(0, 0);
1184 NS_IMETHODIMP
1185 nsBaseWidget::GetNonClientMargins(nsIntMargin &margins)
1187 return NS_ERROR_NOT_IMPLEMENTED;
1190 NS_IMETHODIMP
1191 nsBaseWidget::SetNonClientMargins(nsIntMargin &margins)
1193 return NS_ERROR_NOT_IMPLEMENTED;
1196 NS_METHOD nsBaseWidget::EnableDragDrop(bool aEnable)
1198 return NS_OK;
1201 uint32_t nsBaseWidget::GetMaxTouchPoints() const
1203 return 0;
1206 NS_METHOD nsBaseWidget::SetModal(bool aModal)
1208 return NS_ERROR_FAILURE;
1211 NS_IMETHODIMP
1212 nsBaseWidget::GetAttention(int32_t aCycleCount) {
1213 return NS_OK;
1216 bool
1217 nsBaseWidget::HasPendingInputEvent()
1219 return false;
1222 NS_IMETHODIMP
1223 nsBaseWidget::SetIcon(const nsAString&)
1225 return NS_OK;
1228 NS_IMETHODIMP
1229 nsBaseWidget::SetWindowTitlebarColor(nscolor aColor, bool aActive)
1231 return NS_ERROR_NOT_IMPLEMENTED;
1234 bool
1235 nsBaseWidget::ShowsResizeIndicator(nsIntRect* aResizerRect)
1237 return false;
1240 NS_IMETHODIMP
1241 nsBaseWidget::SetLayersAcceleration(bool aEnabled)
1243 if (mUseLayersAcceleration == aEnabled) {
1244 return NS_OK;
1247 bool usedAcceleration = mUseLayersAcceleration;
1249 mUseLayersAcceleration = ComputeShouldAccelerate(aEnabled);
1250 // ComputeShouldAccelerate may have set mUseLayersAcceleration to a value
1251 // different from aEnabled.
1252 if (usedAcceleration == mUseLayersAcceleration) {
1253 return NS_OK;
1255 if (mLayerManager) {
1256 mLayerManager->Destroy();
1258 mLayerManager = nullptr;
1259 return NS_OK;
1262 NS_METHOD nsBaseWidget::RegisterTouchWindow()
1264 return NS_ERROR_NOT_IMPLEMENTED;
1267 NS_METHOD nsBaseWidget::UnregisterTouchWindow()
1269 return NS_ERROR_NOT_IMPLEMENTED;
1272 NS_IMETHODIMP
1273 nsBaseWidget::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX,
1274 double aOriginalDeltaY,
1275 double& aOverriddenDeltaX,
1276 double& aOverriddenDeltaY)
1278 aOverriddenDeltaX = aOriginalDeltaX;
1279 aOverriddenDeltaY = aOriginalDeltaY;
1281 static bool sInitialized = false;
1282 static bool sIsOverrideEnabled = false;
1283 static int32_t sIntFactorX = 0;
1284 static int32_t sIntFactorY = 0;
1286 if (!sInitialized) {
1287 Preferences::AddBoolVarCache(&sIsOverrideEnabled,
1288 "mousewheel.system_scroll_override_on_root_content.enabled", false);
1289 Preferences::AddIntVarCache(&sIntFactorX,
1290 "mousewheel.system_scroll_override_on_root_content.horizontal.factor", 0);
1291 Preferences::AddIntVarCache(&sIntFactorY,
1292 "mousewheel.system_scroll_override_on_root_content.vertical.factor", 0);
1293 sIntFactorX = std::max(sIntFactorX, 0);
1294 sIntFactorY = std::max(sIntFactorY, 0);
1295 sInitialized = true;
1298 if (!sIsOverrideEnabled) {
1299 return NS_OK;
1302 // The pref value must be larger than 100, otherwise, we don't override the
1303 // delta value.
1304 if (sIntFactorX > 100) {
1305 double factor = static_cast<double>(sIntFactorX) / 100;
1306 aOverriddenDeltaX *= factor;
1308 if (sIntFactorY > 100) {
1309 double factor = static_cast<double>(sIntFactorY) / 100;
1310 aOverriddenDeltaY *= factor;
1313 return NS_OK;
1318 * Modifies aFile to point at an icon file with the given name and suffix. The
1319 * suffix may correspond to a file extension with leading '.' if appropriate.
1320 * Returns true if the icon file exists and can be read.
1322 static bool
1323 ResolveIconNameHelper(nsIFile *aFile,
1324 const nsAString &aIconName,
1325 const nsAString &aIconSuffix)
1327 aFile->Append(NS_LITERAL_STRING("icons"));
1328 aFile->Append(NS_LITERAL_STRING("default"));
1329 aFile->Append(aIconName + aIconSuffix);
1331 bool readable;
1332 return NS_SUCCEEDED(aFile->IsReadable(&readable)) && readable;
1336 * Resolve the given icon name into a local file object. This method is
1337 * intended to be called by subclasses of nsBaseWidget. aIconSuffix is a
1338 * platform specific icon file suffix (e.g., ".ico" under Win32).
1340 * If no file is found matching the given parameters, then null is returned.
1342 void
1343 nsBaseWidget::ResolveIconName(const nsAString &aIconName,
1344 const nsAString &aIconSuffix,
1345 nsIFile **aResult)
1347 *aResult = nullptr;
1349 nsCOMPtr<nsIProperties> dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
1350 if (!dirSvc)
1351 return;
1353 // first check auxilary chrome directories
1355 nsCOMPtr<nsISimpleEnumerator> dirs;
1356 dirSvc->Get(NS_APP_CHROME_DIR_LIST, NS_GET_IID(nsISimpleEnumerator),
1357 getter_AddRefs(dirs));
1358 if (dirs) {
1359 bool hasMore;
1360 while (NS_SUCCEEDED(dirs->HasMoreElements(&hasMore)) && hasMore) {
1361 nsCOMPtr<nsISupports> element;
1362 dirs->GetNext(getter_AddRefs(element));
1363 if (!element)
1364 continue;
1365 nsCOMPtr<nsIFile> file = do_QueryInterface(element);
1366 if (!file)
1367 continue;
1368 if (ResolveIconNameHelper(file, aIconName, aIconSuffix)) {
1369 NS_ADDREF(*aResult = file);
1370 return;
1375 // then check the main app chrome directory
1377 nsCOMPtr<nsIFile> file;
1378 dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
1379 getter_AddRefs(file));
1380 if (file && ResolveIconNameHelper(file, aIconName, aIconSuffix))
1381 NS_ADDREF(*aResult = file);
1384 NS_IMETHODIMP
1385 nsBaseWidget::BeginResizeDrag(WidgetGUIEvent* aEvent,
1386 int32_t aHorizontal,
1387 int32_t aVertical)
1389 return NS_ERROR_NOT_IMPLEMENTED;
1392 NS_IMETHODIMP
1393 nsBaseWidget::BeginMoveDrag(WidgetMouseEvent* aEvent)
1395 return NS_ERROR_NOT_IMPLEMENTED;
1398 uint32_t
1399 nsBaseWidget::GetGLFrameBufferFormat()
1401 return LOCAL_GL_RGBA;
1404 void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints)
1406 mSizeConstraints = aConstraints;
1407 // We can't ensure that the size is honored at this point because we're
1408 // probably in the middle of a reflow.
1411 const widget::SizeConstraints& nsBaseWidget::GetSizeConstraints() const
1413 return mSizeConstraints;
1416 // static
1417 nsIRollupListener*
1418 nsBaseWidget::GetActiveRollupListener()
1420 // If set, then this is likely an <html:select> dropdown.
1421 if (gRollupListener)
1422 return gRollupListener;
1424 return nsXULPopupManager::GetInstance();
1427 void
1428 nsBaseWidget::NotifyWindowDestroyed()
1430 if (!mWidgetListener)
1431 return;
1433 nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
1434 nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
1435 if (xulWindow) {
1436 xulWindow->Destroy();
1440 void
1441 nsBaseWidget::NotifySizeMoveDone()
1443 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1444 return;
1446 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1447 if (presShell) {
1448 presShell->WindowSizeMoveDone();
1452 void
1453 nsBaseWidget::NotifyWindowMoved(int32_t aX, int32_t aY)
1455 if (mWidgetListener) {
1456 mWidgetListener->WindowMoved(this, aX, aY);
1459 if (GetIMEUpdatePreference().WantPositionChanged()) {
1460 NotifyIME(IMENotification(IMEMessage::NOTIFY_IME_OF_POSITION_CHANGE));
1464 void
1465 nsBaseWidget::NotifySysColorChanged()
1467 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1468 return;
1470 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1471 if (presShell) {
1472 presShell->SysColorChanged();
1476 void
1477 nsBaseWidget::NotifyThemeChanged()
1479 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1480 return;
1482 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1483 if (presShell) {
1484 presShell->ThemeChanged();
1488 void
1489 nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
1490 UIStateChangeType aShowFocusRings)
1492 if (!mWidgetListener)
1493 return;
1495 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1496 if (!presShell)
1497 return;
1499 nsIDocument* doc = presShell->GetDocument();
1500 if (doc) {
1501 nsPIDOMWindow* win = doc->GetWindow();
1502 if (win) {
1503 win->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
1508 #ifdef ACCESSIBILITY
1510 a11y::Accessible*
1511 nsBaseWidget::GetRootAccessible()
1513 NS_ENSURE_TRUE(mWidgetListener, nullptr);
1515 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1516 NS_ENSURE_TRUE(presShell, nullptr);
1518 // If container is null then the presshell is not active. This often happens
1519 // when a preshell is being held onto for fastback.
1520 nsPresContext* presContext = presShell->GetPresContext();
1521 NS_ENSURE_TRUE(presContext->GetContainerWeak(), nullptr);
1523 // Accessible creation might be not safe so use IsSafeToRunScript to
1524 // make sure it's not created at unsafe times.
1525 nsCOMPtr<nsIAccessibilityService> accService =
1526 services::GetAccessibilityService();
1527 if (accService) {
1528 return accService->GetRootDocumentAccessible(presShell, nsContentUtils::IsSafeToRunScript());
1531 return nullptr;
1534 #endif // ACCESSIBILITY
1536 nsresult
1537 nsIWidget::SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint, bool aLongTap)
1539 if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
1540 sPointerIdCounter = 0;
1542 int pointerId = sPointerIdCounter;
1543 sPointerIdCounter++;
1544 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_CONTACT,
1545 aPointerScreenPoint, 1.0, 90);
1546 if (NS_FAILED(rv)) {
1547 return rv;
1550 if (!aLongTap) {
1551 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_REMOVE,
1552 aPointerScreenPoint, 0, 0);
1553 return rv;
1556 // initiate a long tap
1557 int elapse = Preferences::GetInt("ui.click_hold_context_menus.delay",
1558 TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC);
1559 if (!mLongTapTimer) {
1560 mLongTapTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1561 if (NS_FAILED(rv)) {
1562 SynthesizeNativeTouchPoint(pointerId, TOUCH_CANCEL,
1563 aPointerScreenPoint, 0, 0);
1564 return NS_ERROR_UNEXPECTED;
1566 // Windows requires recuring events, so we set this to a smaller window
1567 // than the pref value.
1568 int timeout = elapse;
1569 if (timeout > TOUCH_INJECT_PUMP_TIMER_MSEC) {
1570 timeout = TOUCH_INJECT_PUMP_TIMER_MSEC;
1572 mLongTapTimer->InitWithFuncCallback(OnLongTapTimerCallback, this,
1573 timeout,
1574 nsITimer::TYPE_REPEATING_SLACK);
1577 // If we already have a long tap pending, cancel it. We only allow one long
1578 // tap to be active at a time.
1579 if (mLongTapTouchPoint) {
1580 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
1581 mLongTapTouchPoint->mPosition, 0, 0);
1584 mLongTapTouchPoint = new LongTapInfo(pointerId, aPointerScreenPoint,
1585 TimeDuration::FromMilliseconds(elapse));
1586 return NS_OK;
1589 // static
1590 void
1591 nsIWidget::OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure)
1593 nsIWidget *self = static_cast<nsIWidget *>(aClosure);
1595 if ((self->mLongTapTouchPoint->mStamp + self->mLongTapTouchPoint->mDuration) >
1596 TimeStamp::Now()) {
1597 #ifdef XP_WIN
1598 // Windows needs us to keep pumping feedback to the digitizer, so update
1599 // the pointer id with the same position.
1600 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
1601 TOUCH_CONTACT,
1602 self->mLongTapTouchPoint->mPosition,
1603 1.0, 90);
1604 #endif
1605 return;
1608 // finished, remove the touch point
1609 self->mLongTapTimer->Cancel();
1610 self->mLongTapTimer = nullptr;
1611 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
1612 TOUCH_REMOVE,
1613 self->mLongTapTouchPoint->mPosition,
1614 0, 0);
1615 self->mLongTapTouchPoint = nullptr;
1618 nsresult
1619 nsIWidget::ClearNativeTouchSequence()
1621 if (!mLongTapTimer) {
1622 return NS_OK;
1624 mLongTapTimer->Cancel();
1625 mLongTapTimer = nullptr;
1626 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
1627 mLongTapTouchPoint->mPosition, 0, 0);
1628 mLongTapTouchPoint = nullptr;
1629 return NS_OK;
1632 #ifdef DEBUG
1633 //////////////////////////////////////////////////////////////
1635 // Convert a GUI event message code to a string.
1636 // Makes it a lot easier to debug events.
1638 // See gtk/nsWidget.cpp and windows/nsWindow.cpp
1639 // for a DebugPrintEvent() function that uses
1640 // this.
1642 //////////////////////////////////////////////////////////////
1643 /* static */ nsAutoString
1644 nsBaseWidget::debug_GuiEventToString(WidgetGUIEvent* aGuiEvent)
1646 NS_ASSERTION(nullptr != aGuiEvent,"cmon, null gui event.");
1648 nsAutoString eventName(NS_LITERAL_STRING("UNKNOWN"));
1650 #define _ASSIGN_eventName(_value,_name)\
1651 case _value: eventName.AssignLiteral(_name) ; break
1653 switch(aGuiEvent->message)
1655 _ASSIGN_eventName(NS_BLUR_CONTENT,"NS_BLUR_CONTENT");
1656 _ASSIGN_eventName(NS_DRAGDROP_GESTURE,"NS_DND_GESTURE");
1657 _ASSIGN_eventName(NS_DRAGDROP_DROP,"NS_DND_DROP");
1658 _ASSIGN_eventName(NS_DRAGDROP_ENTER,"NS_DND_ENTER");
1659 _ASSIGN_eventName(NS_DRAGDROP_EXIT,"NS_DND_EXIT");
1660 _ASSIGN_eventName(NS_DRAGDROP_OVER,"NS_DND_OVER");
1661 _ASSIGN_eventName(NS_EDITOR_INPUT,"NS_EDITOR_INPUT");
1662 _ASSIGN_eventName(NS_FOCUS_CONTENT,"NS_FOCUS_CONTENT");
1663 _ASSIGN_eventName(NS_FORM_SELECTED,"NS_FORM_SELECTED");
1664 _ASSIGN_eventName(NS_FORM_CHANGE,"NS_FORM_CHANGE");
1665 _ASSIGN_eventName(NS_FORM_RESET,"NS_FORM_RESET");
1666 _ASSIGN_eventName(NS_FORM_SUBMIT,"NS_FORM_SUBMIT");
1667 _ASSIGN_eventName(NS_IMAGE_ABORT,"NS_IMAGE_ABORT");
1668 _ASSIGN_eventName(NS_LOAD_ERROR,"NS_LOAD_ERROR");
1669 _ASSIGN_eventName(NS_KEY_DOWN,"NS_KEY_DOWN");
1670 _ASSIGN_eventName(NS_KEY_PRESS,"NS_KEY_PRESS");
1671 _ASSIGN_eventName(NS_KEY_UP,"NS_KEY_UP");
1672 _ASSIGN_eventName(NS_MOUSE_ENTER,"NS_MOUSE_ENTER");
1673 _ASSIGN_eventName(NS_MOUSE_EXIT,"NS_MOUSE_EXIT");
1674 _ASSIGN_eventName(NS_MOUSE_BUTTON_DOWN,"NS_MOUSE_BUTTON_DOWN");
1675 _ASSIGN_eventName(NS_MOUSE_BUTTON_UP,"NS_MOUSE_BUTTON_UP");
1676 _ASSIGN_eventName(NS_MOUSE_CLICK,"NS_MOUSE_CLICK");
1677 _ASSIGN_eventName(NS_MOUSE_DOUBLECLICK,"NS_MOUSE_DBLCLICK");
1678 _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE");
1679 _ASSIGN_eventName(NS_LOAD,"NS_LOAD");
1680 _ASSIGN_eventName(NS_POPSTATE,"NS_POPSTATE");
1681 _ASSIGN_eventName(NS_BEFORE_SCRIPT_EXECUTE,"NS_BEFORE_SCRIPT_EXECUTE");
1682 _ASSIGN_eventName(NS_AFTER_SCRIPT_EXECUTE,"NS_AFTER_SCRIPT_EXECUTE");
1683 _ASSIGN_eventName(NS_PAGE_UNLOAD,"NS_PAGE_UNLOAD");
1684 _ASSIGN_eventName(NS_HASHCHANGE,"NS_HASHCHANGE");
1685 _ASSIGN_eventName(NS_READYSTATECHANGE,"NS_READYSTATECHANGE");
1686 _ASSIGN_eventName(NS_XUL_BROADCAST, "NS_XUL_BROADCAST");
1687 _ASSIGN_eventName(NS_XUL_COMMAND_UPDATE, "NS_XUL_COMMAND_UPDATE");
1689 #undef _ASSIGN_eventName
1691 default:
1693 char buf[32];
1695 sprintf(buf,"UNKNOWN: %d",aGuiEvent->message);
1697 CopyASCIItoUTF16(buf, eventName);
1699 break;
1702 return nsAutoString(eventName);
1704 //////////////////////////////////////////////////////////////
1706 // Code to deal with paint and event debug prefs.
1708 //////////////////////////////////////////////////////////////
1709 struct PrefPair
1711 const char * name;
1712 bool value;
1715 static PrefPair debug_PrefValues[] =
1717 { "nglayout.debug.crossing_event_dumping", false },
1718 { "nglayout.debug.event_dumping", false },
1719 { "nglayout.debug.invalidate_dumping", false },
1720 { "nglayout.debug.motion_event_dumping", false },
1721 { "nglayout.debug.paint_dumping", false },
1722 { "nglayout.debug.paint_flashing", false }
1725 //////////////////////////////////////////////////////////////
1726 bool
1727 nsBaseWidget::debug_GetCachedBoolPref(const char * aPrefName)
1729 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
1731 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
1733 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
1735 return debug_PrefValues[i].value;
1739 return false;
1741 //////////////////////////////////////////////////////////////
1742 static void debug_SetCachedBoolPref(const char * aPrefName,bool aValue)
1744 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
1746 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
1748 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
1750 debug_PrefValues[i].value = aValue;
1752 return;
1756 NS_ASSERTION(false, "cmon, this code is not reached dude.");
1759 //////////////////////////////////////////////////////////////
1760 class Debug_PrefObserver MOZ_FINAL : public nsIObserver {
1761 ~Debug_PrefObserver() {}
1763 public:
1764 NS_DECL_ISUPPORTS
1765 NS_DECL_NSIOBSERVER
1768 NS_IMPL_ISUPPORTS(Debug_PrefObserver, nsIObserver)
1770 NS_IMETHODIMP
1771 Debug_PrefObserver::Observe(nsISupports* subject, const char* topic,
1772 const char16_t* data)
1774 NS_ConvertUTF16toUTF8 prefName(data);
1776 bool value = Preferences::GetBool(prefName.get(), false);
1777 debug_SetCachedBoolPref(prefName.get(), value);
1778 return NS_OK;
1781 //////////////////////////////////////////////////////////////
1782 /* static */ void
1783 debug_RegisterPrefCallbacks()
1785 static bool once = true;
1787 if (!once) {
1788 return;
1791 once = false;
1793 nsCOMPtr<nsIObserver> obs(new Debug_PrefObserver());
1794 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++) {
1795 // Initialize the pref values
1796 debug_PrefValues[i].value =
1797 Preferences::GetBool(debug_PrefValues[i].name, false);
1799 if (obs) {
1800 // Register callbacks for when these change
1801 Preferences::AddStrongObserver(obs, debug_PrefValues[i].name);
1805 //////////////////////////////////////////////////////////////
1806 static int32_t
1807 _GetPrintCount()
1809 static int32_t sCount = 0;
1811 return ++sCount;
1813 //////////////////////////////////////////////////////////////
1814 /* static */ bool
1815 nsBaseWidget::debug_WantPaintFlashing()
1817 return debug_GetCachedBoolPref("nglayout.debug.paint_flashing");
1819 //////////////////////////////////////////////////////////////
1820 /* static */ void
1821 nsBaseWidget::debug_DumpEvent(FILE * aFileOut,
1822 nsIWidget * aWidget,
1823 WidgetGUIEvent* aGuiEvent,
1824 const nsAutoCString & aWidgetName,
1825 int32_t aWindowID)
1827 if (aGuiEvent->message == NS_MOUSE_MOVE)
1829 if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping"))
1830 return;
1833 if (aGuiEvent->message == NS_MOUSE_ENTER ||
1834 aGuiEvent->message == NS_MOUSE_EXIT)
1836 if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping"))
1837 return;
1840 if (!debug_GetCachedBoolPref("nglayout.debug.event_dumping"))
1841 return;
1843 NS_LossyConvertUTF16toASCII tempString(debug_GuiEventToString(aGuiEvent).get());
1845 fprintf(aFileOut,
1846 "%4d %-26s widget=%-8p name=%-12s id=0x%-6x refpt=%d,%d\n",
1847 _GetPrintCount(),
1848 tempString.get(),
1849 (void *) aWidget,
1850 aWidgetName.get(),
1851 aWindowID,
1852 aGuiEvent->refPoint.x,
1853 aGuiEvent->refPoint.y);
1855 //////////////////////////////////////////////////////////////
1856 /* static */ void
1857 nsBaseWidget::debug_DumpPaintEvent(FILE * aFileOut,
1858 nsIWidget * aWidget,
1859 const nsIntRegion & aRegion,
1860 const nsAutoCString & aWidgetName,
1861 int32_t aWindowID)
1863 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
1864 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
1866 if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
1867 return;
1869 nsIntRect rect = aRegion.GetBounds();
1870 fprintf(aFileOut,
1871 "%4d PAINT widget=%p name=%-12s id=0x%-6x bounds-rect=%3d,%-3d %3d,%-3d",
1872 _GetPrintCount(),
1873 (void *) aWidget,
1874 aWidgetName.get(),
1875 aWindowID,
1876 rect.x, rect.y, rect.width, rect.height
1879 fprintf(aFileOut,"\n");
1881 //////////////////////////////////////////////////////////////
1882 /* static */ void
1883 nsBaseWidget::debug_DumpInvalidate(FILE * aFileOut,
1884 nsIWidget * aWidget,
1885 const nsIntRect * aRect,
1886 const nsAutoCString & aWidgetName,
1887 int32_t aWindowID)
1889 if (!debug_GetCachedBoolPref("nglayout.debug.invalidate_dumping"))
1890 return;
1892 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
1893 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
1895 fprintf(aFileOut,
1896 "%4d Invalidate widget=%p name=%-12s id=0x%-6x",
1897 _GetPrintCount(),
1898 (void *) aWidget,
1899 aWidgetName.get(),
1900 aWindowID);
1902 if (aRect)
1904 fprintf(aFileOut,
1905 " rect=%3d,%-3d %3d,%-3d",
1906 aRect->x,
1907 aRect->y,
1908 aRect->width,
1909 aRect->height);
1911 else
1913 fprintf(aFileOut,
1914 " rect=%-15s",
1915 "none");
1918 fprintf(aFileOut,"\n");
1920 //////////////////////////////////////////////////////////////
1922 #endif // DEBUG