Bumping manifests a=b2g-bump
[gecko.git] / widget / nsBaseWidget.cpp
blob6948c9b77ef0888d7cedbf7355f14a9c4d5a5005
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 "mozilla/unused.h"
46 #include "mozilla/VsyncDispatcher.h"
47 #include "mozilla/layers/APZCTreeManager.h"
48 #include "mozilla/layers/APZEventState.h"
49 #include "mozilla/layers/APZThreadUtils.h"
50 #include "mozilla/layers/ChromeProcessController.h"
51 #include "mozilla/layers/InputAPZContext.h"
52 #include "mozilla/layers/APZCCallbackHelper.h"
53 #include "mozilla/dom/TabParent.h"
54 #include "TouchEvents.h"
55 #ifdef ACCESSIBILITY
56 #include "nsAccessibilityService.h"
57 #endif
59 #ifdef DEBUG
60 #include "nsIObserver.h"
62 static void debug_RegisterPrefCallbacks();
64 #endif
66 #ifdef NOISY_WIDGET_LEAKS
67 static int32_t gNumWidgets;
68 #endif
70 #ifdef XP_MACOSX
71 #include "nsCocoaFeatures.h"
72 #endif
74 nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
76 using namespace mozilla::layers;
77 using namespace mozilla::ipc;
78 using namespace mozilla;
79 using base::Thread;
81 nsIContent* nsBaseWidget::mLastRollup = nullptr;
82 // Global user preference for disabling native theme. Used
83 // in NativeWindowTheme.
84 bool gDisableNativeTheme = false;
86 // Async pump timer during injected long touch taps
87 #define TOUCH_INJECT_PUMP_TIMER_MSEC 50
88 #define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
89 int32_t nsIWidget::sPointerIdCounter = 0;
91 // nsBaseWidget
92 NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidget)
95 nsAutoRollup::nsAutoRollup()
97 // remember if mLastRollup was null, and only clear it upon destruction
98 // if so. This prevents recursive usage of nsAutoRollup from clearing
99 // mLastRollup when it shouldn't.
100 wasClear = !nsBaseWidget::mLastRollup;
103 nsAutoRollup::~nsAutoRollup()
105 if (nsBaseWidget::mLastRollup && wasClear) {
106 NS_RELEASE(nsBaseWidget::mLastRollup);
110 //-------------------------------------------------------------------------
112 // nsBaseWidget constructor
114 //-------------------------------------------------------------------------
116 nsBaseWidget::nsBaseWidget()
117 : mWidgetListener(nullptr)
118 , mAttachedWidgetListener(nullptr)
119 , mContext(nullptr)
120 , mCompositorVsyncDispatcher(nullptr)
121 , mCursor(eCursor_standard)
122 , mUpdateCursor(true)
123 , mBorderStyle(eBorderStyle_none)
124 , mUseLayersAcceleration(false)
125 , mForceLayersAcceleration(false)
126 , mTemporarilyUseBasicLayerManager(false)
127 , mUseAttachedEvents(false)
128 , mContextInitialized(false)
129 , mBounds(0,0,0,0)
130 , mOriginalBounds(nullptr)
131 , mClipRectCount(0)
132 , mSizeMode(nsSizeMode_Normal)
133 , mPopupLevel(ePopupLevelTop)
134 , mPopupType(ePopupTypeAny)
136 #ifdef NOISY_WIDGET_LEAKS
137 gNumWidgets++;
138 printf("WIDGETS+ = %d\n", gNumWidgets);
139 #endif
141 #ifdef DEBUG
142 debug_RegisterPrefCallbacks();
143 #endif
145 mShutdownObserver = new WidgetShutdownObserver(this);
146 nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
149 NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
151 NS_IMETHODIMP
152 WidgetShutdownObserver::Observe(nsISupports *aSubject,
153 const char *aTopic,
154 const char16_t *aData)
156 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0 &&
157 mWidget) {
158 mWidget->Shutdown();
159 nsContentUtils::UnregisterShutdownObserver(this);
161 return NS_OK;
164 void
165 nsBaseWidget::Shutdown()
167 DestroyCompositor();
168 mShutdownObserver = nullptr;
171 static void DeferredDestroyCompositor(nsRefPtr<CompositorParent> aCompositorParent,
172 nsRefPtr<CompositorChild> aCompositorChild)
174 // Bug 848949 needs to be fixed before
175 // we can close the channel properly
176 //aCompositorChild->Close();
179 void nsBaseWidget::DestroyCompositor()
181 if (mCompositorChild) {
182 nsRefPtr<CompositorChild> compositorChild = mCompositorChild.forget();
183 nsRefPtr<CompositorParent> compositorParent = mCompositorParent.forget();
185 compositorChild->SendWillStop();
186 // New LayerManager, CompositorParent and CompositorChild might be created
187 // as a result of internal GetLayerManager() call.
188 compositorChild->Destroy();
190 // The call just made to SendWillStop can result in IPC from the
191 // CompositorParent to the CompositorChild (e.g. caused by the destruction
192 // of shared memory). We need to ensure this gets processed by the
193 // CompositorChild before it gets destroyed. It suffices to ensure that
194 // events already in the MessageLoop get processed before the
195 // CompositorChild is destroyed, so we add a task to the MessageLoop to
196 // handle compositor desctruction.
198 // The DefferedDestroyCompositor task takes ownership of compositorParent and
199 // will release them when it runs.
200 MessageLoop::current()->PostTask(FROM_HERE,
201 NewRunnableFunction(DeferredDestroyCompositor, compositorParent,
202 compositorChild));
206 //-------------------------------------------------------------------------
208 // nsBaseWidget destructor
210 //-------------------------------------------------------------------------
211 nsBaseWidget::~nsBaseWidget()
213 if (mLayerManager &&
214 mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
215 static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
218 if (mLayerManager) {
219 mLayerManager->Destroy();
220 mLayerManager = nullptr;
223 if (mShutdownObserver) {
224 // If the shutdown observer is currently processing observers,
225 // then UnregisterShutdownObserver won't stop our Observer
226 // function from being called. Make sure we don't try
227 // to reference the dead widget.
228 mShutdownObserver->mWidget = nullptr;
229 nsContentUtils::UnregisterShutdownObserver(mShutdownObserver);
232 DestroyCompositor();
234 #ifdef NOISY_WIDGET_LEAKS
235 gNumWidgets--;
236 printf("WIDGETS- = %d\n", gNumWidgets);
237 #endif
239 NS_IF_RELEASE(mContext);
240 delete mOriginalBounds;
242 // Can have base widgets that are things like tooltips which don't have CompositorVsyncDispatchers
243 if (mCompositorVsyncDispatcher) {
244 mCompositorVsyncDispatcher->Shutdown();
248 //-------------------------------------------------------------------------
250 // Basic create.
252 //-------------------------------------------------------------------------
253 void nsBaseWidget::BaseCreate(nsIWidget *aParent,
254 const nsIntRect &aRect,
255 nsDeviceContext *aContext,
256 nsWidgetInitData *aInitData)
258 static bool gDisableNativeThemeCached = false;
259 if (!gDisableNativeThemeCached) {
260 Preferences::AddBoolVarCache(&gDisableNativeTheme,
261 "mozilla.widget.disable-native-theme",
262 gDisableNativeTheme);
263 gDisableNativeThemeCached = true;
266 // keep a reference to the device context
267 if (aContext) {
268 mContext = aContext;
269 NS_ADDREF(mContext);
271 else {
272 mContext = new nsDeviceContext();
273 NS_ADDREF(mContext);
274 mContext->Init(nullptr);
277 if (nullptr != aInitData) {
278 mWindowType = aInitData->mWindowType;
279 mBorderStyle = aInitData->mBorderStyle;
280 mPopupLevel = aInitData->mPopupLevel;
281 mPopupType = aInitData->mPopupHint;
282 mRequireOffMainThreadCompositing = aInitData->mRequireOffMainThreadCompositing;
285 if (aParent) {
286 aParent->AddChild(this);
290 NS_IMETHODIMP nsBaseWidget::CaptureMouse(bool aCapture)
292 return NS_OK;
295 //-------------------------------------------------------------------------
297 // Accessor functions to get/set the client data
299 //-------------------------------------------------------------------------
301 nsIWidgetListener* nsBaseWidget::GetWidgetListener()
303 return mWidgetListener;
306 void nsBaseWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
308 mWidgetListener = aWidgetListener;
311 already_AddRefed<nsIWidget>
312 nsBaseWidget::CreateChild(const nsIntRect &aRect,
313 nsDeviceContext *aContext,
314 nsWidgetInitData *aInitData,
315 bool aForceUseIWidgetParent)
317 nsIWidget* parent = this;
318 nsNativeWidget nativeParent = nullptr;
320 if (!aForceUseIWidgetParent) {
321 // Use only either parent or nativeParent, not both, to match
322 // existing code. Eventually Create() should be divested of its
323 // nativeWidget parameter.
324 nativeParent = parent ? parent->GetNativeData(NS_NATIVE_WIDGET) : nullptr;
325 parent = nativeParent ? nullptr : parent;
326 NS_ABORT_IF_FALSE(!parent || !nativeParent, "messed up logic");
329 nsCOMPtr<nsIWidget> widget;
330 if (aInitData && aInitData->mWindowType == eWindowType_popup) {
331 widget = AllocateChildPopupWidget();
332 } else {
333 static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
334 widget = do_CreateInstance(kCChildCID);
337 if (widget &&
338 NS_SUCCEEDED(widget->Create(parent, nativeParent, aRect,
339 aContext, aInitData))) {
340 return widget.forget();
343 return nullptr;
346 // Attach a view to our widget which we'll send events to.
347 NS_IMETHODIMP
348 nsBaseWidget::AttachViewToTopLevel(bool aUseAttachedEvents,
349 nsDeviceContext *aContext)
351 NS_ASSERTION((mWindowType == eWindowType_toplevel ||
352 mWindowType == eWindowType_dialog ||
353 mWindowType == eWindowType_invisible ||
354 mWindowType == eWindowType_child),
355 "Can't attach to window of that type");
357 mUseAttachedEvents = aUseAttachedEvents;
359 if (aContext) {
360 if (mContext) {
361 NS_IF_RELEASE(mContext);
363 mContext = aContext;
364 NS_ADDREF(mContext);
367 return NS_OK;
370 nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener()
372 return mAttachedWidgetListener;
375 void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener)
377 mAttachedWidgetListener = aListener;
380 //-------------------------------------------------------------------------
382 // Close this nsBaseWidget
384 //-------------------------------------------------------------------------
385 NS_METHOD nsBaseWidget::Destroy()
387 // Just in case our parent is the only ref to us
388 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
389 // disconnect from the parent
390 nsIWidget *parent = GetParent();
391 if (parent) {
392 parent->RemoveChild(this);
395 return NS_OK;
399 //-------------------------------------------------------------------------
401 // Set this nsBaseWidget's parent
403 //-------------------------------------------------------------------------
404 NS_IMETHODIMP nsBaseWidget::SetParent(nsIWidget* aNewParent)
406 return NS_ERROR_NOT_IMPLEMENTED;
410 //-------------------------------------------------------------------------
412 // Get this nsBaseWidget parent
414 //-------------------------------------------------------------------------
415 nsIWidget* nsBaseWidget::GetParent(void)
417 return nullptr;
420 //-------------------------------------------------------------------------
422 // Get this nsBaseWidget top level widget
424 //-------------------------------------------------------------------------
425 nsIWidget* nsBaseWidget::GetTopLevelWidget()
427 nsIWidget *topLevelWidget = nullptr, *widget = this;
428 while (widget) {
429 topLevelWidget = widget;
430 widget = widget->GetParent();
432 return topLevelWidget;
435 //-------------------------------------------------------------------------
437 // Get this nsBaseWidget's top (non-sheet) parent (if it's a sheet)
439 //-------------------------------------------------------------------------
440 nsIWidget* nsBaseWidget::GetSheetWindowParent(void)
442 return nullptr;
445 float nsBaseWidget::GetDPI()
447 return 96.0f;
450 CSSToLayoutDeviceScale nsIWidget::GetDefaultScale()
452 double devPixelsPerCSSPixel = DefaultScaleOverride();
454 if (devPixelsPerCSSPixel <= 0.0) {
455 devPixelsPerCSSPixel = GetDefaultScaleInternal();
458 return CSSToLayoutDeviceScale(devPixelsPerCSSPixel);
461 /* static */
462 double nsIWidget::DefaultScaleOverride()
464 // The number of device pixels per CSS pixel. A value <= 0 means choose
465 // automatically based on the DPI. A positive value is used as-is. This effectively
466 // controls the size of a CSS "px".
467 double devPixelsPerCSSPixel = -1.0;
469 nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
470 if (!prefString.IsEmpty()) {
471 devPixelsPerCSSPixel = PR_strtod(prefString, nullptr);
474 return devPixelsPerCSSPixel;
477 //-------------------------------------------------------------------------
479 // Add a child to the list of children
481 //-------------------------------------------------------------------------
482 void nsBaseWidget::AddChild(nsIWidget* aChild)
484 NS_PRECONDITION(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
485 "aChild not properly removed from its old child list");
487 if (!mFirstChild) {
488 mFirstChild = mLastChild = aChild;
489 } else {
490 // append to the list
491 NS_ASSERTION(mLastChild, "Bogus state");
492 NS_ASSERTION(!mLastChild->GetNextSibling(), "Bogus state");
493 mLastChild->SetNextSibling(aChild);
494 aChild->SetPrevSibling(mLastChild);
495 mLastChild = aChild;
500 //-------------------------------------------------------------------------
502 // Remove a child from the list of children
504 //-------------------------------------------------------------------------
505 void nsBaseWidget::RemoveChild(nsIWidget* aChild)
507 #ifdef DEBUG
508 #ifdef XP_MACOSX
509 // nsCocoaWindow doesn't implement GetParent, so in that case parent will be
510 // null and we'll just have to do without this assertion.
511 nsIWidget* parent = aChild->GetParent();
512 NS_ASSERTION(!parent || parent == this, "Not one of our kids!");
513 #else
514 NS_ASSERTION(aChild->GetParent() == this, "Not one of our kids!");
515 #endif
516 #endif
518 if (mLastChild == aChild) {
519 mLastChild = mLastChild->GetPrevSibling();
521 if (mFirstChild == aChild) {
522 mFirstChild = mFirstChild->GetNextSibling();
525 // Now remove from the list. Make sure that we pass ownership of the tail
526 // of the list correctly before we have aChild let go of it.
527 nsIWidget* prev = aChild->GetPrevSibling();
528 nsIWidget* next = aChild->GetNextSibling();
529 if (prev) {
530 prev->SetNextSibling(next);
532 if (next) {
533 next->SetPrevSibling(prev);
536 aChild->SetNextSibling(nullptr);
537 aChild->SetPrevSibling(nullptr);
541 //-------------------------------------------------------------------------
543 // Sets widget's position within its parent's child list.
545 //-------------------------------------------------------------------------
546 void nsBaseWidget::SetZIndex(int32_t aZIndex)
548 // Hold a ref to ourselves just in case, since we're going to remove
549 // from our parent.
550 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
552 mZIndex = aZIndex;
554 // reorder this child in its parent's list.
555 nsBaseWidget* parent = static_cast<nsBaseWidget*>(GetParent());
556 if (parent) {
557 parent->RemoveChild(this);
558 // Scope sib outside the for loop so we can check it afterward
559 nsIWidget* sib = parent->GetFirstChild();
560 for ( ; sib; sib = sib->GetNextSibling()) {
561 int32_t childZIndex = GetZIndex();
562 if (aZIndex < childZIndex) {
563 // Insert ourselves before sib
564 nsIWidget* prev = sib->GetPrevSibling();
565 mNextSibling = sib;
566 mPrevSibling = prev;
567 sib->SetPrevSibling(this);
568 if (prev) {
569 prev->SetNextSibling(this);
570 } else {
571 NS_ASSERTION(sib == parent->mFirstChild, "Broken child list");
572 // We've taken ownership of sib, so it's safe to have parent let
573 // go of it
574 parent->mFirstChild = this;
576 PlaceBehind(eZPlacementBelow, sib, false);
577 break;
580 // were we added to the list?
581 if (!sib) {
582 parent->AddChild(this);
587 //-------------------------------------------------------------------------
589 // Places widget behind the given widget (platforms must override)
591 //-------------------------------------------------------------------------
592 NS_IMETHODIMP nsBaseWidget::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
593 nsIWidget *aWidget, bool aActivate)
595 return NS_OK;
598 //-------------------------------------------------------------------------
600 // Maximize, minimize or restore the window. The BaseWidget implementation
601 // merely stores the state.
603 //-------------------------------------------------------------------------
604 NS_IMETHODIMP nsBaseWidget::SetSizeMode(int32_t aMode)
606 if (aMode == nsSizeMode_Normal ||
607 aMode == nsSizeMode_Minimized ||
608 aMode == nsSizeMode_Maximized ||
609 aMode == nsSizeMode_Fullscreen) {
611 mSizeMode = (nsSizeMode) aMode;
612 return NS_OK;
614 return NS_ERROR_ILLEGAL_VALUE;
617 //-------------------------------------------------------------------------
619 // Get this component cursor
621 //-------------------------------------------------------------------------
622 nsCursor nsBaseWidget::GetCursor()
624 return mCursor;
627 NS_METHOD nsBaseWidget::SetCursor(nsCursor aCursor)
629 mCursor = aCursor;
630 return NS_OK;
633 NS_IMETHODIMP nsBaseWidget::SetCursor(imgIContainer* aCursor,
634 uint32_t aHotspotX, uint32_t aHotspotY)
636 return NS_ERROR_NOT_IMPLEMENTED;
639 //-------------------------------------------------------------------------
641 // Window transparency methods
643 //-------------------------------------------------------------------------
645 void nsBaseWidget::SetTransparencyMode(nsTransparencyMode aMode) {
648 nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
649 return eTransparencyOpaque;
652 bool
653 nsBaseWidget::IsWindowClipRegionEqual(const nsTArray<nsIntRect>& aRects)
655 return mClipRects &&
656 mClipRectCount == aRects.Length() &&
657 memcmp(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount) == 0;
660 void
661 nsBaseWidget::StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects)
663 mClipRectCount = aRects.Length();
664 mClipRects = new nsIntRect[mClipRectCount];
665 if (mClipRects) {
666 memcpy(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount);
670 void
671 nsBaseWidget::GetWindowClipRegion(nsTArray<nsIntRect>* aRects)
673 if (mClipRects) {
674 aRects->AppendElements(mClipRects.get(), mClipRectCount);
675 } else {
676 aRects->AppendElement(nsIntRect(0, 0, mBounds.width, mBounds.height));
680 const nsIntRegion
681 nsBaseWidget::RegionFromArray(const nsTArray<nsIntRect>& aRects)
683 nsIntRegion region;
684 for (uint32_t i = 0; i < aRects.Length(); ++i) {
685 region.Or(region, aRects[i]);
687 return region;
690 void
691 nsBaseWidget::ArrayFromRegion(const nsIntRegion& aRegion, nsTArray<nsIntRect>& aRects)
693 const nsIntRect* r;
694 for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) {
695 aRects.AppendElement(*r);
699 nsresult
700 nsBaseWidget::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
701 bool aIntersectWithExisting)
703 if (!aIntersectWithExisting) {
704 StoreWindowClipRegion(aRects);
705 } else {
706 // get current rects
707 nsTArray<nsIntRect> currentRects;
708 GetWindowClipRegion(&currentRects);
709 // create region from them
710 nsIntRegion currentRegion = RegionFromArray(currentRects);
711 // create region from new rects
712 nsIntRegion newRegion = RegionFromArray(aRects);
713 // intersect regions
714 nsIntRegion intersection;
715 intersection.And(currentRegion, newRegion);
716 // create int rect array from intersection
717 nsTArray<nsIntRect> rects;
718 ArrayFromRegion(intersection, rects);
719 // store
720 StoreWindowClipRegion(rects);
722 return NS_OK;
725 //-------------------------------------------------------------------------
727 // Set window shadow style
729 //-------------------------------------------------------------------------
731 NS_IMETHODIMP nsBaseWidget::SetWindowShadowStyle(int32_t aMode)
733 return NS_ERROR_NOT_IMPLEMENTED;
736 //-------------------------------------------------------------------------
738 // Hide window borders/decorations for this widget
740 //-------------------------------------------------------------------------
741 NS_IMETHODIMP nsBaseWidget::HideWindowChrome(bool aShouldHide)
743 return NS_ERROR_NOT_IMPLEMENTED;
746 //-------------------------------------------------------------------------
748 // Put the window into full-screen mode
750 //-------------------------------------------------------------------------
751 NS_IMETHODIMP nsBaseWidget::MakeFullScreen(bool aFullScreen, nsIScreen* aScreen)
753 HideWindowChrome(aFullScreen);
755 if (aFullScreen) {
756 if (!mOriginalBounds)
757 mOriginalBounds = new nsIntRect();
758 GetScreenBounds(*mOriginalBounds);
759 // convert dev pix to display pix for window manipulation
760 CSSToLayoutDeviceScale scale = GetDefaultScale();
761 mOriginalBounds->x = NSToIntRound(mOriginalBounds->x / scale.scale);
762 mOriginalBounds->y = NSToIntRound(mOriginalBounds->y / scale.scale);
763 mOriginalBounds->width = NSToIntRound(mOriginalBounds->width / scale.scale);
764 mOriginalBounds->height = NSToIntRound(mOriginalBounds->height / scale.scale);
766 // Move to top-left corner of screen and size to the screen dimensions
767 nsCOMPtr<nsIScreenManager> screenManager;
768 screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
769 NS_ASSERTION(screenManager, "Unable to grab screenManager.");
770 if (screenManager) {
771 nsCOMPtr<nsIScreen> screen = aScreen;
772 if (!screen) {
773 // no screen was passed in, use the one that the window is on
774 screenManager->ScreenForRect(mOriginalBounds->x,
775 mOriginalBounds->y,
776 mOriginalBounds->width,
777 mOriginalBounds->height,
778 getter_AddRefs(screen));
781 if (screen) {
782 int32_t left, top, width, height;
783 if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
784 Resize(left, top, width, height, true);
789 } else if (mOriginalBounds) {
790 Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
791 mOriginalBounds->height, true);
794 return NS_OK;
797 nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
798 nsBaseWidget* aWidget, gfxContext* aTarget,
799 BufferMode aDoubleBuffering, ScreenRotation aRotation)
800 : mWidget(aWidget)
802 mLayerManager = static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
803 if (mLayerManager) {
804 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
805 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
806 mLayerManager->SetDefaultTarget(aTarget);
807 mLayerManager->SetDefaultTargetConfiguration(aDoubleBuffering, aRotation);
811 nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
813 if (mLayerManager) {
814 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
815 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
816 mLayerManager->SetDefaultTarget(nullptr);
817 mLayerManager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, ROTATION_0);
821 nsBaseWidget::AutoUseBasicLayerManager::AutoUseBasicLayerManager(nsBaseWidget* aWidget)
822 : mWidget(aWidget)
824 mPreviousTemporarilyUseBasicLayerManager =
825 mWidget->mTemporarilyUseBasicLayerManager;
826 mWidget->mTemporarilyUseBasicLayerManager = true;
829 nsBaseWidget::AutoUseBasicLayerManager::~AutoUseBasicLayerManager()
831 mWidget->mTemporarilyUseBasicLayerManager =
832 mPreviousTemporarilyUseBasicLayerManager;
835 bool
836 nsBaseWidget::ComputeShouldAccelerate(bool aDefault)
838 #if defined(XP_WIN) || defined(ANDROID) || \
839 defined(MOZ_GL_PROVIDER) || defined(XP_MACOSX) || defined(MOZ_WIDGET_QT)
840 bool accelerateByDefault = true;
841 #else
842 bool accelerateByDefault = false;
843 #endif
845 #ifdef XP_MACOSX
846 // 10.6.2 and lower have a bug involving textures and pixel buffer objects
847 // that caused bug 629016, so we don't allow OpenGL-accelerated layers on
848 // those versions of the OS.
849 // This will still let full-screen video be accelerated on OpenGL, because
850 // that XUL widget opts in to acceleration, but that's probably OK.
851 accelerateByDefault = nsCocoaFeatures::AccelerateByDefault();
852 #endif
854 // we should use AddBoolPrefVarCache
855 bool disableAcceleration = gfxPrefs::LayersAccelerationDisabled();
856 mForceLayersAcceleration = gfxPrefs::LayersAccelerationForceEnabled();
858 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
859 accelerateByDefault = accelerateByDefault ||
860 (acceleratedEnv && (*acceleratedEnv != '0'));
862 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
863 bool safeMode = false;
864 if (xr)
865 xr->GetInSafeMode(&safeMode);
867 bool whitelisted = false;
869 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
870 if (gfxInfo) {
871 // bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
872 // as that's what causes GfxInfo initialization which kills the zombie 'glxtest' process.
873 // initially we relied on the fact that GetFeatureStatus calls GetData for us, but bug 681026 showed
874 // that assumption to be unsafe.
875 gfxInfo->GetData();
877 int32_t status;
878 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) {
879 if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
880 whitelisted = true;
885 if (disableAcceleration || safeMode)
886 return false;
888 if (mForceLayersAcceleration)
889 return true;
891 if (!whitelisted) {
892 static int tell_me_once = 0;
893 if (!tell_me_once) {
894 NS_WARNING("OpenGL-accelerated layers are not supported on this system");
895 tell_me_once = 1;
897 #ifdef MOZ_WIDGET_ANDROID
898 NS_RUNTIMEABORT("OpenGL-accelerated layers are a hard requirement on this platform. "
899 "Cannot continue without support for them");
900 #endif
901 return false;
904 if (accelerateByDefault)
905 return true;
907 /* use the window acceleration flag */
908 return aDefault;
911 CompositorParent* nsBaseWidget::NewCompositorParent(int aSurfaceWidth,
912 int aSurfaceHeight)
914 return new CompositorParent(this, false, aSurfaceWidth, aSurfaceHeight);
917 void nsBaseWidget::CreateCompositor()
919 nsIntRect rect;
920 GetBounds(rect);
921 CreateCompositor(rect.width, rect.height);
924 already_AddRefed<GeckoContentController>
925 nsBaseWidget::CreateRootContentController()
927 nsRefPtr<GeckoContentController> controller = new ChromeProcessController(this, mAPZEventState);
928 return controller.forget();
931 class ChromeProcessSetTargetAPZCCallback : public SetTargetAPZCCallback {
932 public:
933 explicit ChromeProcessSetTargetAPZCCallback(APZCTreeManager* aTreeManager)
934 : mTreeManager(aTreeManager)
937 void Run(uint64_t aInputBlockId, const nsTArray<ScrollableLayerGuid>& aTargets) const MOZ_OVERRIDE {
938 MOZ_ASSERT(NS_IsMainThread());
939 // need a local var to disambiguate between the SetTargetAPZC overloads.
940 void (APZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray<ScrollableLayerGuid>&)
941 = &APZCTreeManager::SetTargetAPZC;
942 APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
943 mTreeManager.get(), setTargetApzcFunc, aInputBlockId, aTargets));
946 private:
947 nsRefPtr<APZCTreeManager> mTreeManager;
950 class ChromeProcessContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback {
951 public:
952 explicit ChromeProcessContentReceivedInputBlockCallback(APZCTreeManager* aTreeManager)
953 : mTreeManager(aTreeManager)
956 void Run(const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) const MOZ_OVERRIDE {
957 MOZ_ASSERT(NS_IsMainThread());
958 APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
959 mTreeManager.get(), &APZCTreeManager::ContentReceivedInputBlock,
960 aInputBlockId, aPreventDefault));
963 private:
964 nsRefPtr<APZCTreeManager> mTreeManager;
968 void nsBaseWidget::ConfigureAPZCTreeManager()
970 uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
971 mAPZC = CompositorParent::GetAPZCTreeManager(rootLayerTreeId);
972 MOZ_ASSERT(mAPZC);
974 mAPZC->SetDPI(GetDPI());
975 mAPZEventState = new APZEventState(this,
976 new ChromeProcessContentReceivedInputBlockCallback(mAPZC));
977 mSetTargetAPZCCallback = new ChromeProcessSetTargetAPZCCallback(mAPZC);
979 nsRefPtr<GeckoContentController> controller = CreateRootContentController();
980 if (controller) {
981 CompositorParent::SetControllerForLayerTree(rootLayerTreeId, controller);
985 nsEventStatus
986 nsBaseWidget::DispatchEventForAPZ(WidgetGUIEvent* aEvent,
987 const ScrollableLayerGuid& aGuid,
988 uint64_t aInputBlockId)
990 MOZ_ASSERT(NS_IsMainThread());
991 InputAPZContext context(aGuid, aInputBlockId);
993 // If this is a touch event and APZ has targeted it to an APZC in the root
994 // process, apply that APZC's callback-transform before dispatching the
995 // event. If the event is instead targeted to an APZC in the child process,
996 // the transform will be applied in the child process before dispatching
997 // the event there (see e.g. TabChild::RecvRealTouchEvent()).
998 // TODO: Do other types of events (than touch) need this?
999 if (aEvent->AsTouchEvent() && aGuid.mLayersId == mCompositorParent->RootLayerTreeId()) {
1000 APZCCallbackHelper::ApplyCallbackTransform(*aEvent->AsTouchEvent(), aGuid,
1001 GetDefaultScale(), 1.0f);
1004 nsEventStatus status;
1005 DispatchEvent(aEvent, status);
1007 if (mAPZC && !context.WasRoutedToChildProcess()) {
1008 // EventStateManager did not route the event into the child process.
1009 // It's safe to communicate to APZ that the event has been processed.
1010 // TODO: Eventually we'll be able to move the SendSetTargetAPZCNotification
1011 // call into APZEventState::Process*Event() as well.
1012 if (WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent()) {
1013 if (touchEvent->message == NS_TOUCH_START) {
1014 APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(), *aEvent,
1015 aGuid, aInputBlockId, mSetTargetAPZCCallback);
1017 mAPZEventState->ProcessTouchEvent(*touchEvent, aGuid, aInputBlockId);
1018 } else if (WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent()) {
1019 APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(), *aEvent,
1020 aGuid, aInputBlockId, mSetTargetAPZCCallback);
1021 mAPZEventState->ProcessWheelEvent(*wheelEvent, aGuid, aInputBlockId);
1025 return status;
1028 void
1029 nsBaseWidget::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints)
1031 if (mUseLayersAcceleration) {
1032 aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
1035 aHints.AppendElement(LayersBackend::LAYERS_BASIC);
1038 nsIDocument*
1039 nsBaseWidget::GetDocument() const
1041 if (mWidgetListener) {
1042 if (nsIPresShell* presShell = mWidgetListener->GetPresShell()) {
1043 return presShell->GetDocument();
1046 return nullptr;
1049 void nsBaseWidget::CreateCompositorVsyncDispatcher()
1051 if (gfxPrefs::HardwareVsyncEnabled()) {
1052 // Parent directly listens to the vsync source whereas
1053 // child process communicate via IPC
1054 // Should be called AFTER gfxPlatform is initialized
1055 if (XRE_IsParentProcess()) {
1056 mCompositorVsyncDispatcher = new CompositorVsyncDispatcher();
1061 CompositorVsyncDispatcher*
1062 nsBaseWidget::GetCompositorVsyncDispatcher()
1064 return mCompositorVsyncDispatcher;
1067 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
1069 // This makes sure that gfxPlatforms gets initialized if it hasn't by now.
1070 gfxPlatform::GetPlatform();
1072 MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(),
1073 "This function assumes OMTC");
1075 MOZ_ASSERT(!mCompositorParent,
1076 "Should have properly cleaned up the previous CompositorParent beforehand");
1078 // Recreating this is tricky, as we may still have an old and we need
1079 // to make sure it's properly destroyed by calling DestroyCompositor!
1081 // If we've already received a shutdown notification, don't try
1082 // create a new compositor.
1083 if (!mShutdownObserver) {
1084 return;
1087 CreateCompositorVsyncDispatcher();
1088 mCompositorParent = NewCompositorParent(aWidth, aHeight);
1089 MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
1090 nsRefPtr<ClientLayerManager> lm = new ClientLayerManager(this);
1091 MessageLoop *childMessageLoop = CompositorParent::CompositorLoop();
1092 mCompositorChild = new CompositorChild(lm);
1093 mCompositorChild->Open(parentChannel, childMessageLoop, ipc::ChildSide);
1095 if (gfxPrefs::AsyncPanZoomEnabled() &&
1096 (WindowType() == eWindowType_toplevel || WindowType() == eWindowType_child)) {
1097 ConfigureAPZCTreeManager();
1100 TextureFactoryIdentifier textureFactoryIdentifier;
1101 PLayerTransactionChild* shadowManager = nullptr;
1102 nsTArray<LayersBackend> backendHints;
1103 GetPreferredCompositorBackends(backendHints);
1105 #if !defined(MOZ_X11) && !defined(XP_WIN)
1106 if (!mRequireOffMainThreadCompositing &&
1107 !Preferences::GetBool("layers.offmainthreadcomposition.force-basic", false)) {
1108 for (size_t i = 0; i < backendHints.Length(); ++i) {
1109 if (backendHints[i] == LayersBackend::LAYERS_BASIC) {
1110 backendHints[i] = LayersBackend::LAYERS_NONE;
1114 #endif
1116 bool success = false;
1117 if (!backendHints.IsEmpty()) {
1118 shadowManager = mCompositorChild->SendPLayerTransactionConstructor(
1119 backendHints, 0, &textureFactoryIdentifier, &success);
1122 if (success) {
1123 ShadowLayerForwarder* lf = lm->AsShadowForwarder();
1124 if (!lf) {
1125 lm = nullptr;
1126 mCompositorChild = nullptr;
1127 return;
1129 lf->SetShadowManager(shadowManager);
1130 lf->IdentifyTextureHost(textureFactoryIdentifier);
1131 ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
1132 WindowUsesOMTC();
1134 mLayerManager = lm.forget();
1135 return;
1138 NS_WARNING("Failed to create an OMT compositor.");
1139 DestroyCompositor();
1140 // Compositor child had the only reference to LayerManager and will have
1141 // deallocated it when being freed.
1144 bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
1146 return gfxPlatform::UsesOffMainThreadCompositing();
1149 LayerManager* nsBaseWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
1150 LayersBackend aBackendHint,
1151 LayerManagerPersistence aPersistence,
1152 bool* aAllowRetaining)
1154 if (!mLayerManager) {
1156 mUseLayersAcceleration = ComputeShouldAccelerate(mUseLayersAcceleration);
1158 // Try to use an async compositor first, if possible
1159 if (ShouldUseOffMainThreadCompositing()) {
1160 // e10s uses the parameter to pass in the shadow manager from the TabChild
1161 // so we don't expect to see it there since this doesn't support e10s.
1162 NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
1163 CreateCompositor();
1166 if (!mLayerManager) {
1167 mLayerManager = CreateBasicLayerManager();
1170 if (mTemporarilyUseBasicLayerManager && !mBasicLayerManager) {
1171 mBasicLayerManager = CreateBasicLayerManager();
1173 LayerManager* usedLayerManager = mTemporarilyUseBasicLayerManager ?
1174 mBasicLayerManager : mLayerManager;
1175 if (aAllowRetaining) {
1176 *aAllowRetaining = (usedLayerManager == mLayerManager);
1178 return usedLayerManager;
1181 LayerManager* nsBaseWidget::CreateBasicLayerManager()
1183 return new BasicLayerManager(this);
1186 CompositorChild* nsBaseWidget::GetRemoteRenderer()
1188 return mCompositorChild;
1191 TemporaryRef<mozilla::gfx::DrawTarget> nsBaseWidget::StartRemoteDrawing()
1193 return nullptr;
1196 //-------------------------------------------------------------------------
1198 // Return the used device context
1200 //-------------------------------------------------------------------------
1201 nsDeviceContext* nsBaseWidget::GetDeviceContext()
1203 if (!mContextInitialized) {
1204 mContext->Init(this);
1205 mContextInitialized = true;
1207 return mContext;
1210 //-------------------------------------------------------------------------
1212 // Destroy the window
1214 //-------------------------------------------------------------------------
1215 void nsBaseWidget::OnDestroy()
1217 // release references to device context and app shell
1218 NS_IF_RELEASE(mContext);
1221 NS_METHOD nsBaseWidget::SetWindowClass(const nsAString& xulWinType)
1223 return NS_ERROR_NOT_IMPLEMENTED;
1226 NS_METHOD nsBaseWidget::MoveClient(double aX, double aY)
1228 nsIntPoint clientOffset(GetClientOffset());
1230 // GetClientOffset returns device pixels; scale back to display pixels
1231 // if that's what this widget uses for the Move/Resize APIs
1232 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
1233 ? GetDefaultScale()
1234 : CSSToLayoutDeviceScale(1.0);
1235 aX -= clientOffset.x * 1.0 / scale.scale;
1236 aY -= clientOffset.y * 1.0 / scale.scale;
1238 return Move(aX, aY);
1241 NS_METHOD nsBaseWidget::ResizeClient(double aWidth,
1242 double aHeight,
1243 bool aRepaint)
1245 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1246 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1248 nsIntRect clientBounds;
1249 GetClientBounds(clientBounds);
1251 // GetClientBounds and mBounds are device pixels; scale back to display pixels
1252 // if that's what this widget uses for the Move/Resize APIs
1253 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
1254 ? GetDefaultScale()
1255 : CSSToLayoutDeviceScale(1.0);
1256 double invScale = 1.0 / scale.scale;
1257 aWidth = mBounds.width * invScale + (aWidth - clientBounds.width * invScale);
1258 aHeight = mBounds.height * invScale + (aHeight - clientBounds.height * invScale);
1260 return Resize(aWidth, aHeight, aRepaint);
1263 NS_METHOD nsBaseWidget::ResizeClient(double aX,
1264 double aY,
1265 double aWidth,
1266 double aHeight,
1267 bool aRepaint)
1269 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
1270 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
1272 nsIntRect clientBounds;
1273 GetClientBounds(clientBounds);
1275 double scale = BoundsUseDisplayPixels() ? 1.0 / GetDefaultScale().scale : 1.0;
1276 aWidth = mBounds.width * scale + (aWidth - clientBounds.width * scale);
1277 aHeight = mBounds.height * scale + (aHeight - clientBounds.height * scale);
1279 nsIntPoint clientOffset(GetClientOffset());
1280 aX -= clientOffset.x * scale;
1281 aY -= clientOffset.y * scale;
1283 return Resize(aX, aY, aWidth, aHeight, aRepaint);
1286 //-------------------------------------------------------------------------
1288 // Bounds
1290 //-------------------------------------------------------------------------
1293 * If the implementation of nsWindow supports borders this method MUST be overridden
1296 NS_METHOD nsBaseWidget::GetClientBounds(nsIntRect &aRect)
1298 return GetBounds(aRect);
1302 * If the implementation of nsWindow supports borders this method MUST be overridden
1305 NS_METHOD nsBaseWidget::GetBounds(nsIntRect &aRect)
1307 aRect = mBounds;
1308 return NS_OK;
1312 * If the implementation of nsWindow uses a local coordinate system within the window,
1313 * this method must be overridden
1316 NS_METHOD nsBaseWidget::GetScreenBounds(nsIntRect &aRect)
1318 return GetBounds(aRect);
1321 NS_METHOD nsBaseWidget::GetRestoredBounds(nsIntRect &aRect)
1323 if (SizeMode() != nsSizeMode_Normal) {
1324 return NS_ERROR_FAILURE;
1326 return GetScreenBounds(aRect);
1329 nsIntPoint nsBaseWidget::GetClientOffset()
1331 return nsIntPoint(0, 0);
1334 NS_IMETHODIMP
1335 nsBaseWidget::GetNonClientMargins(nsIntMargin &margins)
1337 return NS_ERROR_NOT_IMPLEMENTED;
1340 NS_IMETHODIMP
1341 nsBaseWidget::SetNonClientMargins(nsIntMargin &margins)
1343 return NS_ERROR_NOT_IMPLEMENTED;
1346 NS_METHOD nsBaseWidget::EnableDragDrop(bool aEnable)
1348 return NS_OK;
1351 uint32_t nsBaseWidget::GetMaxTouchPoints() const
1353 return 0;
1356 NS_METHOD nsBaseWidget::SetModal(bool aModal)
1358 return NS_ERROR_FAILURE;
1361 NS_IMETHODIMP
1362 nsBaseWidget::GetAttention(int32_t aCycleCount) {
1363 return NS_OK;
1366 bool
1367 nsBaseWidget::HasPendingInputEvent()
1369 return false;
1372 NS_IMETHODIMP
1373 nsBaseWidget::SetIcon(const nsAString&)
1375 return NS_OK;
1378 NS_IMETHODIMP
1379 nsBaseWidget::SetWindowTitlebarColor(nscolor aColor, bool aActive)
1381 return NS_ERROR_NOT_IMPLEMENTED;
1384 bool
1385 nsBaseWidget::ShowsResizeIndicator(nsIntRect* aResizerRect)
1387 return false;
1390 NS_METHOD nsBaseWidget::RegisterTouchWindow()
1392 return NS_ERROR_NOT_IMPLEMENTED;
1395 NS_METHOD nsBaseWidget::UnregisterTouchWindow()
1397 return NS_ERROR_NOT_IMPLEMENTED;
1400 NS_IMETHODIMP
1401 nsBaseWidget::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX,
1402 double aOriginalDeltaY,
1403 double& aOverriddenDeltaX,
1404 double& aOverriddenDeltaY)
1406 aOverriddenDeltaX = aOriginalDeltaX;
1407 aOverriddenDeltaY = aOriginalDeltaY;
1409 static bool sInitialized = false;
1410 static bool sIsOverrideEnabled = false;
1411 static int32_t sIntFactorX = 0;
1412 static int32_t sIntFactorY = 0;
1414 if (!sInitialized) {
1415 Preferences::AddBoolVarCache(&sIsOverrideEnabled,
1416 "mousewheel.system_scroll_override_on_root_content.enabled", false);
1417 Preferences::AddIntVarCache(&sIntFactorX,
1418 "mousewheel.system_scroll_override_on_root_content.horizontal.factor", 0);
1419 Preferences::AddIntVarCache(&sIntFactorY,
1420 "mousewheel.system_scroll_override_on_root_content.vertical.factor", 0);
1421 sIntFactorX = std::max(sIntFactorX, 0);
1422 sIntFactorY = std::max(sIntFactorY, 0);
1423 sInitialized = true;
1426 if (!sIsOverrideEnabled) {
1427 return NS_OK;
1430 // The pref value must be larger than 100, otherwise, we don't override the
1431 // delta value.
1432 if (sIntFactorX > 100) {
1433 double factor = static_cast<double>(sIntFactorX) / 100;
1434 aOverriddenDeltaX *= factor;
1436 if (sIntFactorY > 100) {
1437 double factor = static_cast<double>(sIntFactorY) / 100;
1438 aOverriddenDeltaY *= factor;
1441 return NS_OK;
1446 * Modifies aFile to point at an icon file with the given name and suffix. The
1447 * suffix may correspond to a file extension with leading '.' if appropriate.
1448 * Returns true if the icon file exists and can be read.
1450 static bool
1451 ResolveIconNameHelper(nsIFile *aFile,
1452 const nsAString &aIconName,
1453 const nsAString &aIconSuffix)
1455 aFile->Append(NS_LITERAL_STRING("icons"));
1456 aFile->Append(NS_LITERAL_STRING("default"));
1457 aFile->Append(aIconName + aIconSuffix);
1459 bool readable;
1460 return NS_SUCCEEDED(aFile->IsReadable(&readable)) && readable;
1464 * Resolve the given icon name into a local file object. This method is
1465 * intended to be called by subclasses of nsBaseWidget. aIconSuffix is a
1466 * platform specific icon file suffix (e.g., ".ico" under Win32).
1468 * If no file is found matching the given parameters, then null is returned.
1470 void
1471 nsBaseWidget::ResolveIconName(const nsAString &aIconName,
1472 const nsAString &aIconSuffix,
1473 nsIFile **aResult)
1475 *aResult = nullptr;
1477 nsCOMPtr<nsIProperties> dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
1478 if (!dirSvc)
1479 return;
1481 // first check auxilary chrome directories
1483 nsCOMPtr<nsISimpleEnumerator> dirs;
1484 dirSvc->Get(NS_APP_CHROME_DIR_LIST, NS_GET_IID(nsISimpleEnumerator),
1485 getter_AddRefs(dirs));
1486 if (dirs) {
1487 bool hasMore;
1488 while (NS_SUCCEEDED(dirs->HasMoreElements(&hasMore)) && hasMore) {
1489 nsCOMPtr<nsISupports> element;
1490 dirs->GetNext(getter_AddRefs(element));
1491 if (!element)
1492 continue;
1493 nsCOMPtr<nsIFile> file = do_QueryInterface(element);
1494 if (!file)
1495 continue;
1496 if (ResolveIconNameHelper(file, aIconName, aIconSuffix)) {
1497 NS_ADDREF(*aResult = file);
1498 return;
1503 // then check the main app chrome directory
1505 nsCOMPtr<nsIFile> file;
1506 dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
1507 getter_AddRefs(file));
1508 if (file && ResolveIconNameHelper(file, aIconName, aIconSuffix))
1509 NS_ADDREF(*aResult = file);
1512 NS_IMETHODIMP
1513 nsBaseWidget::BeginResizeDrag(WidgetGUIEvent* aEvent,
1514 int32_t aHorizontal,
1515 int32_t aVertical)
1517 return NS_ERROR_NOT_IMPLEMENTED;
1520 NS_IMETHODIMP
1521 nsBaseWidget::BeginMoveDrag(WidgetMouseEvent* aEvent)
1523 return NS_ERROR_NOT_IMPLEMENTED;
1526 uint32_t
1527 nsBaseWidget::GetGLFrameBufferFormat()
1529 return LOCAL_GL_RGBA;
1532 void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints)
1534 mSizeConstraints = aConstraints;
1535 // We can't ensure that the size is honored at this point because we're
1536 // probably in the middle of a reflow.
1539 const widget::SizeConstraints& nsBaseWidget::GetSizeConstraints() const
1541 return mSizeConstraints;
1544 // static
1545 nsIRollupListener*
1546 nsBaseWidget::GetActiveRollupListener()
1548 // If set, then this is likely an <html:select> dropdown.
1549 if (gRollupListener)
1550 return gRollupListener;
1552 return nsXULPopupManager::GetInstance();
1555 void
1556 nsBaseWidget::NotifyWindowDestroyed()
1558 if (!mWidgetListener)
1559 return;
1561 nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
1562 nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
1563 if (xulWindow) {
1564 xulWindow->Destroy();
1568 void
1569 nsBaseWidget::NotifySizeMoveDone()
1571 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1572 return;
1574 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1575 if (presShell) {
1576 presShell->WindowSizeMoveDone();
1580 void
1581 nsBaseWidget::NotifyWindowMoved(int32_t aX, int32_t aY)
1583 if (mWidgetListener) {
1584 mWidgetListener->WindowMoved(this, aX, aY);
1587 if (GetIMEUpdatePreference().WantPositionChanged()) {
1588 NotifyIME(IMENotification(IMEMessage::NOTIFY_IME_OF_POSITION_CHANGE));
1592 void
1593 nsBaseWidget::NotifySysColorChanged()
1595 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1596 return;
1598 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1599 if (presShell) {
1600 presShell->SysColorChanged();
1604 void
1605 nsBaseWidget::NotifyThemeChanged()
1607 if (!mWidgetListener || mWidgetListener->GetXULWindow())
1608 return;
1610 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1611 if (presShell) {
1612 presShell->ThemeChanged();
1616 void
1617 nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
1618 UIStateChangeType aShowFocusRings)
1620 if (nsIDocument* doc = GetDocument()) {
1621 nsPIDOMWindow* win = doc->GetWindow();
1622 if (win) {
1623 win->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
1628 #ifdef ACCESSIBILITY
1630 a11y::Accessible*
1631 nsBaseWidget::GetRootAccessible()
1633 NS_ENSURE_TRUE(mWidgetListener, nullptr);
1635 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1636 NS_ENSURE_TRUE(presShell, nullptr);
1638 // If container is null then the presshell is not active. This often happens
1639 // when a preshell is being held onto for fastback.
1640 nsPresContext* presContext = presShell->GetPresContext();
1641 NS_ENSURE_TRUE(presContext->GetContainerWeak(), nullptr);
1643 // Accessible creation might be not safe so use IsSafeToRunScript to
1644 // make sure it's not created at unsafe times.
1645 nsCOMPtr<nsIAccessibilityService> accService =
1646 services::GetAccessibilityService();
1647 if (accService) {
1648 return accService->GetRootDocumentAccessible(presShell, nsContentUtils::IsSafeToRunScript());
1651 return nullptr;
1654 #endif // ACCESSIBILITY
1656 nsresult
1657 nsIWidget::SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint, bool aLongTap)
1659 if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
1660 sPointerIdCounter = 0;
1662 int pointerId = sPointerIdCounter;
1663 sPointerIdCounter++;
1664 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_CONTACT,
1665 aPointerScreenPoint, 1.0, 90);
1666 if (NS_FAILED(rv)) {
1667 return rv;
1670 if (!aLongTap) {
1671 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_REMOVE,
1672 aPointerScreenPoint, 0, 0);
1673 return rv;
1676 // initiate a long tap
1677 int elapse = Preferences::GetInt("ui.click_hold_context_menus.delay",
1678 TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC);
1679 if (!mLongTapTimer) {
1680 mLongTapTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1681 if (NS_FAILED(rv)) {
1682 SynthesizeNativeTouchPoint(pointerId, TOUCH_CANCEL,
1683 aPointerScreenPoint, 0, 0);
1684 return NS_ERROR_UNEXPECTED;
1686 // Windows requires recuring events, so we set this to a smaller window
1687 // than the pref value.
1688 int timeout = elapse;
1689 if (timeout > TOUCH_INJECT_PUMP_TIMER_MSEC) {
1690 timeout = TOUCH_INJECT_PUMP_TIMER_MSEC;
1692 mLongTapTimer->InitWithFuncCallback(OnLongTapTimerCallback, this,
1693 timeout,
1694 nsITimer::TYPE_REPEATING_SLACK);
1697 // If we already have a long tap pending, cancel it. We only allow one long
1698 // tap to be active at a time.
1699 if (mLongTapTouchPoint) {
1700 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
1701 mLongTapTouchPoint->mPosition, 0, 0);
1704 mLongTapTouchPoint = new LongTapInfo(pointerId, aPointerScreenPoint,
1705 TimeDuration::FromMilliseconds(elapse));
1706 return NS_OK;
1709 // static
1710 void
1711 nsIWidget::OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure)
1713 nsIWidget *self = static_cast<nsIWidget *>(aClosure);
1715 if ((self->mLongTapTouchPoint->mStamp + self->mLongTapTouchPoint->mDuration) >
1716 TimeStamp::Now()) {
1717 #ifdef XP_WIN
1718 // Windows needs us to keep pumping feedback to the digitizer, so update
1719 // the pointer id with the same position.
1720 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
1721 TOUCH_CONTACT,
1722 self->mLongTapTouchPoint->mPosition,
1723 1.0, 90);
1724 #endif
1725 return;
1728 // finished, remove the touch point
1729 self->mLongTapTimer->Cancel();
1730 self->mLongTapTimer = nullptr;
1731 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
1732 TOUCH_REMOVE,
1733 self->mLongTapTouchPoint->mPosition,
1734 0, 0);
1735 self->mLongTapTouchPoint = nullptr;
1738 nsresult
1739 nsIWidget::ClearNativeTouchSequence()
1741 if (!mLongTapTimer) {
1742 return NS_OK;
1744 mLongTapTimer->Cancel();
1745 mLongTapTimer = nullptr;
1746 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
1747 mLongTapTouchPoint->mPosition, 0, 0);
1748 mLongTapTouchPoint = nullptr;
1749 return NS_OK;
1752 #ifdef DEBUG
1753 //////////////////////////////////////////////////////////////
1755 // Convert a GUI event message code to a string.
1756 // Makes it a lot easier to debug events.
1758 // See gtk/nsWidget.cpp and windows/nsWindow.cpp
1759 // for a DebugPrintEvent() function that uses
1760 // this.
1762 //////////////////////////////////////////////////////////////
1763 /* static */ nsAutoString
1764 nsBaseWidget::debug_GuiEventToString(WidgetGUIEvent* aGuiEvent)
1766 NS_ASSERTION(nullptr != aGuiEvent,"cmon, null gui event.");
1768 nsAutoString eventName(NS_LITERAL_STRING("UNKNOWN"));
1770 #define _ASSIGN_eventName(_value,_name)\
1771 case _value: eventName.AssignLiteral(_name) ; break
1773 switch(aGuiEvent->message)
1775 _ASSIGN_eventName(NS_BLUR_CONTENT,"NS_BLUR_CONTENT");
1776 _ASSIGN_eventName(NS_DRAGDROP_GESTURE,"NS_DND_GESTURE");
1777 _ASSIGN_eventName(NS_DRAGDROP_DROP,"NS_DND_DROP");
1778 _ASSIGN_eventName(NS_DRAGDROP_ENTER,"NS_DND_ENTER");
1779 _ASSIGN_eventName(NS_DRAGDROP_EXIT,"NS_DND_EXIT");
1780 _ASSIGN_eventName(NS_DRAGDROP_OVER,"NS_DND_OVER");
1781 _ASSIGN_eventName(NS_EDITOR_INPUT,"NS_EDITOR_INPUT");
1782 _ASSIGN_eventName(NS_FOCUS_CONTENT,"NS_FOCUS_CONTENT");
1783 _ASSIGN_eventName(NS_FORM_SELECTED,"NS_FORM_SELECTED");
1784 _ASSIGN_eventName(NS_FORM_CHANGE,"NS_FORM_CHANGE");
1785 _ASSIGN_eventName(NS_FORM_RESET,"NS_FORM_RESET");
1786 _ASSIGN_eventName(NS_FORM_SUBMIT,"NS_FORM_SUBMIT");
1787 _ASSIGN_eventName(NS_IMAGE_ABORT,"NS_IMAGE_ABORT");
1788 _ASSIGN_eventName(NS_LOAD_ERROR,"NS_LOAD_ERROR");
1789 _ASSIGN_eventName(NS_KEY_DOWN,"NS_KEY_DOWN");
1790 _ASSIGN_eventName(NS_KEY_PRESS,"NS_KEY_PRESS");
1791 _ASSIGN_eventName(NS_KEY_UP,"NS_KEY_UP");
1792 _ASSIGN_eventName(NS_MOUSE_ENTER,"NS_MOUSE_ENTER");
1793 _ASSIGN_eventName(NS_MOUSE_EXIT,"NS_MOUSE_EXIT");
1794 _ASSIGN_eventName(NS_MOUSE_BUTTON_DOWN,"NS_MOUSE_BUTTON_DOWN");
1795 _ASSIGN_eventName(NS_MOUSE_BUTTON_UP,"NS_MOUSE_BUTTON_UP");
1796 _ASSIGN_eventName(NS_MOUSE_CLICK,"NS_MOUSE_CLICK");
1797 _ASSIGN_eventName(NS_MOUSE_DOUBLECLICK,"NS_MOUSE_DBLCLICK");
1798 _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE");
1799 _ASSIGN_eventName(NS_LOAD,"NS_LOAD");
1800 _ASSIGN_eventName(NS_POPSTATE,"NS_POPSTATE");
1801 _ASSIGN_eventName(NS_BEFORE_SCRIPT_EXECUTE,"NS_BEFORE_SCRIPT_EXECUTE");
1802 _ASSIGN_eventName(NS_AFTER_SCRIPT_EXECUTE,"NS_AFTER_SCRIPT_EXECUTE");
1803 _ASSIGN_eventName(NS_PAGE_UNLOAD,"NS_PAGE_UNLOAD");
1804 _ASSIGN_eventName(NS_HASHCHANGE,"NS_HASHCHANGE");
1805 _ASSIGN_eventName(NS_READYSTATECHANGE,"NS_READYSTATECHANGE");
1806 _ASSIGN_eventName(NS_XUL_BROADCAST, "NS_XUL_BROADCAST");
1807 _ASSIGN_eventName(NS_XUL_COMMAND_UPDATE, "NS_XUL_COMMAND_UPDATE");
1809 #undef _ASSIGN_eventName
1811 default:
1813 char buf[32];
1815 sprintf(buf,"UNKNOWN: %d",aGuiEvent->message);
1817 CopyASCIItoUTF16(buf, eventName);
1819 break;
1822 return nsAutoString(eventName);
1824 //////////////////////////////////////////////////////////////
1826 // Code to deal with paint and event debug prefs.
1828 //////////////////////////////////////////////////////////////
1829 struct PrefPair
1831 const char * name;
1832 bool value;
1835 static PrefPair debug_PrefValues[] =
1837 { "nglayout.debug.crossing_event_dumping", false },
1838 { "nglayout.debug.event_dumping", false },
1839 { "nglayout.debug.invalidate_dumping", false },
1840 { "nglayout.debug.motion_event_dumping", false },
1841 { "nglayout.debug.paint_dumping", false },
1842 { "nglayout.debug.paint_flashing", false }
1845 //////////////////////////////////////////////////////////////
1846 bool
1847 nsBaseWidget::debug_GetCachedBoolPref(const char * aPrefName)
1849 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
1851 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
1853 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
1855 return debug_PrefValues[i].value;
1859 return false;
1861 //////////////////////////////////////////////////////////////
1862 static void debug_SetCachedBoolPref(const char * aPrefName,bool aValue)
1864 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
1866 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
1868 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
1870 debug_PrefValues[i].value = aValue;
1872 return;
1876 NS_ASSERTION(false, "cmon, this code is not reached dude.");
1879 //////////////////////////////////////////////////////////////
1880 class Debug_PrefObserver MOZ_FINAL : public nsIObserver {
1881 ~Debug_PrefObserver() {}
1883 public:
1884 NS_DECL_ISUPPORTS
1885 NS_DECL_NSIOBSERVER
1888 NS_IMPL_ISUPPORTS(Debug_PrefObserver, nsIObserver)
1890 NS_IMETHODIMP
1891 Debug_PrefObserver::Observe(nsISupports* subject, const char* topic,
1892 const char16_t* data)
1894 NS_ConvertUTF16toUTF8 prefName(data);
1896 bool value = Preferences::GetBool(prefName.get(), false);
1897 debug_SetCachedBoolPref(prefName.get(), value);
1898 return NS_OK;
1901 //////////////////////////////////////////////////////////////
1902 /* static */ void
1903 debug_RegisterPrefCallbacks()
1905 static bool once = true;
1907 if (!once) {
1908 return;
1911 once = false;
1913 nsCOMPtr<nsIObserver> obs(new Debug_PrefObserver());
1914 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++) {
1915 // Initialize the pref values
1916 debug_PrefValues[i].value =
1917 Preferences::GetBool(debug_PrefValues[i].name, false);
1919 if (obs) {
1920 // Register callbacks for when these change
1921 Preferences::AddStrongObserver(obs, debug_PrefValues[i].name);
1925 //////////////////////////////////////////////////////////////
1926 static int32_t
1927 _GetPrintCount()
1929 static int32_t sCount = 0;
1931 return ++sCount;
1933 //////////////////////////////////////////////////////////////
1934 /* static */ bool
1935 nsBaseWidget::debug_WantPaintFlashing()
1937 return debug_GetCachedBoolPref("nglayout.debug.paint_flashing");
1939 //////////////////////////////////////////////////////////////
1940 /* static */ void
1941 nsBaseWidget::debug_DumpEvent(FILE * aFileOut,
1942 nsIWidget * aWidget,
1943 WidgetGUIEvent* aGuiEvent,
1944 const nsAutoCString & aWidgetName,
1945 int32_t aWindowID)
1947 if (aGuiEvent->message == NS_MOUSE_MOVE)
1949 if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping"))
1950 return;
1953 if (aGuiEvent->message == NS_MOUSE_ENTER ||
1954 aGuiEvent->message == NS_MOUSE_EXIT)
1956 if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping"))
1957 return;
1960 if (!debug_GetCachedBoolPref("nglayout.debug.event_dumping"))
1961 return;
1963 NS_LossyConvertUTF16toASCII tempString(debug_GuiEventToString(aGuiEvent).get());
1965 fprintf(aFileOut,
1966 "%4d %-26s widget=%-8p name=%-12s id=0x%-6x refpt=%d,%d\n",
1967 _GetPrintCount(),
1968 tempString.get(),
1969 (void *) aWidget,
1970 aWidgetName.get(),
1971 aWindowID,
1972 aGuiEvent->refPoint.x,
1973 aGuiEvent->refPoint.y);
1975 //////////////////////////////////////////////////////////////
1976 /* static */ void
1977 nsBaseWidget::debug_DumpPaintEvent(FILE * aFileOut,
1978 nsIWidget * aWidget,
1979 const nsIntRegion & aRegion,
1980 const nsAutoCString & aWidgetName,
1981 int32_t aWindowID)
1983 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
1984 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
1986 if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
1987 return;
1989 nsIntRect rect = aRegion.GetBounds();
1990 fprintf(aFileOut,
1991 "%4d PAINT widget=%p name=%-12s id=0x%-6x bounds-rect=%3d,%-3d %3d,%-3d",
1992 _GetPrintCount(),
1993 (void *) aWidget,
1994 aWidgetName.get(),
1995 aWindowID,
1996 rect.x, rect.y, rect.width, rect.height
1999 fprintf(aFileOut,"\n");
2001 //////////////////////////////////////////////////////////////
2002 /* static */ void
2003 nsBaseWidget::debug_DumpInvalidate(FILE * aFileOut,
2004 nsIWidget * aWidget,
2005 const nsIntRect * aRect,
2006 const nsAutoCString & aWidgetName,
2007 int32_t aWindowID)
2009 if (!debug_GetCachedBoolPref("nglayout.debug.invalidate_dumping"))
2010 return;
2012 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
2013 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
2015 fprintf(aFileOut,
2016 "%4d Invalidate widget=%p name=%-12s id=0x%-6x",
2017 _GetPrintCount(),
2018 (void *) aWidget,
2019 aWidgetName.get(),
2020 aWindowID);
2022 if (aRect)
2024 fprintf(aFileOut,
2025 " rect=%3d,%-3d %3d,%-3d",
2026 aRect->x,
2027 aRect->y,
2028 aRect->width,
2029 aRect->height);
2031 else
2033 fprintf(aFileOut,
2034 " rect=%-15s",
2035 "none");
2038 fprintf(aFileOut,"\n");
2040 //////////////////////////////////////////////////////////////
2042 #endif // DEBUG