LCOV - code coverage report
Current view: top level - widget - nsBaseWidget.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 287 1332 21.5 %
Date: 2017-07-14 16:53:18 Functions: 61 172 35.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : 
       2             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       3             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       4             : /* This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       7             : 
       8             : #include "mozilla/ArrayUtils.h"
       9             : #include "mozilla/UniquePtr.h"
      10             : #include "mozilla/TextEventDispatcher.h"
      11             : #include "mozilla/TextEventDispatcherListener.h"
      12             : 
      13             : #include "mozilla/layers/CompositorBridgeChild.h"
      14             : #include "mozilla/layers/CompositorBridgeParent.h"
      15             : #include "mozilla/layers/PLayerTransactionChild.h"
      16             : #include "mozilla/layers/ImageBridgeChild.h"
      17             : #include "LiveResizeListener.h"
      18             : #include "nsBaseWidget.h"
      19             : #include "nsDeviceContext.h"
      20             : #include "nsCOMPtr.h"
      21             : #include "nsGfxCIID.h"
      22             : #include "nsWidgetsCID.h"
      23             : #include "nsServiceManagerUtils.h"
      24             : #include "nsIKeyEventInPluginCallback.h"
      25             : #include "nsIScreenManager.h"
      26             : #include "nsAppDirectoryServiceDefs.h"
      27             : #include "nsISimpleEnumerator.h"
      28             : #include "nsIContent.h"
      29             : #include "nsIDocument.h"
      30             : #include "nsIPresShell.h"
      31             : #include "nsIServiceManager.h"
      32             : #include "mozilla/Preferences.h"
      33             : #include "BasicLayers.h"
      34             : #include "ClientLayerManager.h"
      35             : #include "mozilla/layers/Compositor.h"
      36             : #include "nsIXULRuntime.h"
      37             : #include "nsIXULWindow.h"
      38             : #include "nsIBaseWindow.h"
      39             : #include "nsXULPopupManager.h"
      40             : #include "nsXBLWindowKeyHandler.h"
      41             : #include "nsIWidgetListener.h"
      42             : #include "nsIGfxInfo.h"
      43             : #include "npapi.h"
      44             : #include "X11UndefineNone.h"
      45             : #include "base/thread.h"
      46             : #include "prdtoa.h"
      47             : #include "prenv.h"
      48             : #include "mozilla/Attributes.h"
      49             : #include "mozilla/Unused.h"
      50             : #include "nsContentUtils.h"
      51             : #include "gfxPrefs.h"
      52             : #include "mozilla/gfx/2D.h"
      53             : #include "mozilla/MouseEvents.h"
      54             : #include "GLConsts.h"
      55             : #include "mozilla/Unused.h"
      56             : #include "mozilla/IMEStateManager.h"
      57             : #include "mozilla/VsyncDispatcher.h"
      58             : #include "mozilla/layers/IAPZCTreeManager.h"
      59             : #include "mozilla/layers/APZEventState.h"
      60             : #include "mozilla/layers/APZThreadUtils.h"
      61             : #include "mozilla/layers/ChromeProcessController.h"
      62             : #include "mozilla/layers/CompositorOptions.h"
      63             : #include "mozilla/layers/InputAPZContext.h"
      64             : #include "mozilla/layers/APZCCallbackHelper.h"
      65             : #include "mozilla/layers/WebRenderLayerManager.h"
      66             : #include "mozilla/dom/ContentChild.h"
      67             : #include "mozilla/dom/TabParent.h"
      68             : #include "mozilla/gfx/GPUProcessManager.h"
      69             : #include "mozilla/gfx/gfxVars.h"
      70             : #include "mozilla/Move.h"
      71             : #include "mozilla/Services.h"
      72             : #include "mozilla/Sprintf.h"
      73             : #include "nsRefPtrHashtable.h"
      74             : #include "TouchEvents.h"
      75             : #include "WritingModes.h"
      76             : #include "InputData.h"
      77             : #include "FrameLayerBuilder.h"
      78             : #ifdef ACCESSIBILITY
      79             : #include "nsAccessibilityService.h"
      80             : #endif
      81             : #include "gfxConfig.h"
      82             : #include "mozilla/layers/CompositorSession.h"
      83             : #include "VRManagerChild.h"
      84             : #include "gfxConfig.h"
      85             : 
      86             : #ifdef DEBUG
      87             : #include "nsIObserver.h"
      88             : 
      89             : static void debug_RegisterPrefCallbacks();
      90             : 
      91             : #endif
      92             : 
      93             : #ifdef NOISY_WIDGET_LEAKS
      94             : static int32_t gNumWidgets;
      95             : #endif
      96             : 
      97             : #ifdef XP_MACOSX
      98             : #include "nsCocoaFeatures.h"
      99             : #endif
     100             : 
     101             : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
     102             : static nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>* sPluginWidgetList;
     103             : #endif
     104             : 
     105             : nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
     106             : 
     107             : using namespace mozilla::dom;
     108             : using namespace mozilla::layers;
     109             : using namespace mozilla::ipc;
     110             : using namespace mozilla::widget;
     111             : using namespace mozilla;
     112             : using base::Thread;
     113             : 
     114             : // Global user preference for disabling native theme. Used
     115             : // in NativeWindowTheme.
     116             : bool            gDisableNativeTheme               = false;
     117             : 
     118             : // Async pump timer during injected long touch taps
     119             : #define TOUCH_INJECT_PUMP_TIMER_MSEC 50
     120             : #define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
     121             : int32_t nsIWidget::sPointerIdCounter = 0;
     122             : 
     123             : // Some statics from nsIWidget.h
     124             : /*static*/ uint64_t AutoObserverNotifier::sObserverId = 0;
     125           3 : /*static*/ nsDataHashtable<nsUint64HashKey, nsCOMPtr<nsIObserver>> AutoObserverNotifier::sSavedObservers;
     126             : 
     127             : namespace mozilla {
     128             : namespace widget {
     129             : 
     130             : void
     131           0 : IMENotification::SelectionChangeDataBase::SetWritingMode(
     132             :                                         const WritingMode& aWritingMode)
     133             : {
     134           0 :   mWritingMode = aWritingMode.mWritingMode;
     135           0 : }
     136             : 
     137             : WritingMode
     138           0 : IMENotification::SelectionChangeDataBase::GetWritingMode() const
     139             : {
     140           0 :   return WritingMode(mWritingMode);
     141             : }
     142             : 
     143             : } // namespace widget
     144             : } // namespace mozilla
     145             : 
     146        2949 : NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidget, nsISupportsWeakReference)
     147             : 
     148             : //-------------------------------------------------------------------------
     149             : //
     150             : // nsBaseWidget constructor
     151             : //
     152             : //-------------------------------------------------------------------------
     153             : 
     154           3 : nsBaseWidget::nsBaseWidget()
     155             : : mWidgetListener(nullptr)
     156             : , mAttachedWidgetListener(nullptr)
     157             : , mPreviouslyAttachedWidgetListener(nullptr)
     158             : , mLayerManager(nullptr)
     159             : , mCompositorVsyncDispatcher(nullptr)
     160             : , mCursor(eCursor_standard)
     161             : , mBorderStyle(eBorderStyle_none)
     162             : , mBounds(0,0,0,0)
     163             : , mOriginalBounds(nullptr)
     164             : , mClipRectCount(0)
     165             : , mSizeMode(nsSizeMode_Normal)
     166             : , mPopupLevel(ePopupLevelTop)
     167             : , mPopupType(ePopupTypeAny)
     168             : , mHasRemoteContent(false)
     169             : , mCompositorWidgetDelegate(nullptr)
     170             : , mUpdateCursor(true)
     171             : , mUseAttachedEvents(false)
     172             : , mIMEHasFocus(false)
     173             : , mIsFullyOccluded(false)
     174             : #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
     175           3 : , mAccessibilityInUseFlag(false)
     176             : #endif
     177             : {
     178             : #ifdef NOISY_WIDGET_LEAKS
     179             :   gNumWidgets++;
     180             :   printf("WIDGETS+ = %d\n", gNumWidgets);
     181             : #endif
     182             : 
     183             : #ifdef DEBUG
     184           3 :   debug_RegisterPrefCallbacks();
     185             : #endif
     186             : 
     187             : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
     188           3 :   if (!sPluginWidgetList) {
     189           2 :     sPluginWidgetList = new nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>();
     190             :   }
     191             : #endif
     192           3 :   mShutdownObserver = new WidgetShutdownObserver(this);
     193           3 : }
     194             : 
     195           6 : NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
     196             : 
     197           3 : WidgetShutdownObserver::WidgetShutdownObserver(nsBaseWidget* aWidget) :
     198             :   mWidget(aWidget),
     199           3 :   mRegistered(false)
     200             : {
     201           3 :   Register();
     202           3 : }
     203             : 
     204           0 : WidgetShutdownObserver::~WidgetShutdownObserver()
     205             : {
     206             :   // No need to call Unregister(), we can't be destroyed until nsBaseWidget
     207             :   // gets torn down. The observer service and nsBaseWidget have a ref on us
     208             :   // so nsBaseWidget has to call Unregister and then clear its ref.
     209           0 : }
     210             : 
     211             : NS_IMETHODIMP
     212           0 : WidgetShutdownObserver::Observe(nsISupports *aSubject,
     213             :                                 const char *aTopic,
     214             :                                 const char16_t *aData)
     215             : {
     216           0 :   if (mWidget && !strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     217           0 :     RefPtr<nsBaseWidget> widget(mWidget);
     218           0 :     widget->Shutdown();
     219             :   }
     220           0 :   return NS_OK;
     221             : }
     222             : 
     223             : void
     224           3 : WidgetShutdownObserver::Register()
     225             : {
     226           3 :   if (!mRegistered) {
     227           3 :     mRegistered = true;
     228           3 :     nsContentUtils::RegisterShutdownObserver(this);
     229             :   }
     230           3 : }
     231             : 
     232             : void
     233           0 : WidgetShutdownObserver::Unregister()
     234             : {
     235           0 :   if (mRegistered) {
     236           0 :     mWidget = nullptr;
     237           0 :     nsContentUtils::UnregisterShutdownObserver(this);
     238           0 :     mRegistered = false;
     239             :   }
     240           0 : }
     241             : 
     242             : void
     243           0 : nsBaseWidget::Shutdown()
     244             : {
     245           0 :   NotifyLiveResizeStopped();
     246           0 :   RevokeTransactionIdAllocator();
     247           0 :   DestroyCompositor();
     248           0 :   FreeShutdownObserver();
     249             : #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
     250           0 :   if (sPluginWidgetList) {
     251           0 :     delete sPluginWidgetList;
     252           0 :     sPluginWidgetList = nullptr;
     253             :   }
     254             : #endif
     255           0 : }
     256             : 
     257           0 : void nsBaseWidget::DestroyCompositor()
     258             : {
     259             :   // We release this before releasing the compositor, since it may hold the
     260             :   // last reference to our ClientLayerManager. ClientLayerManager's dtor can
     261             :   // trigger a paint, creating a new compositor, and we don't want to re-use
     262             :   // the old vsync dispatcher.
     263           0 :   if (mCompositorVsyncDispatcher) {
     264           0 :     mCompositorVsyncDispatcher->Shutdown();
     265           0 :     mCompositorVsyncDispatcher = nullptr;
     266             :   }
     267             : 
     268             :   // The compositor shutdown sequence looks like this:
     269             :   //  1. CompositorSession calls CompositorBridgeChild::Destroy.
     270             :   //  2. CompositorBridgeChild synchronously sends WillClose.
     271             :   //  3. CompositorBridgeParent releases some resources (such as the layer
     272             :   //     manager, compositor, and widget).
     273             :   //  4. CompositorBridgeChild::Destroy returns.
     274             :   //  5. Asynchronously, CompositorBridgeParent::ActorDestroy will fire on the
     275             :   //     compositor thread when the I/O thread closes the IPC channel.
     276             :   //  6. Step 5 will schedule DeferredDestroy on the compositor thread, which
     277             :   //     releases the reference CompositorBridgeParent holds to itself.
     278             :   //
     279             :   // When CompositorSession::Shutdown returns, we assume the compositor is gone
     280             :   // or will be gone very soon.
     281           0 :   if (mCompositorSession) {
     282           0 :     ReleaseContentController();
     283           0 :     mAPZC = nullptr;
     284           0 :     mCompositorWidgetDelegate = nullptr;
     285           0 :     mCompositorBridgeChild = nullptr;
     286             : 
     287             :     // XXX CompositorBridgeChild and CompositorBridgeParent might be re-created in
     288             :     // ClientLayerManager destructor. See bug 1133426.
     289           0 :     RefPtr<CompositorSession> session = mCompositorSession.forget();
     290           0 :     session->Shutdown();
     291             :   }
     292           0 : }
     293             : 
     294             : // This prevents the layer manager from starting a new transaction during
     295             : // shutdown.
     296             : void
     297           0 : nsBaseWidget::RevokeTransactionIdAllocator()
     298             : {
     299           0 :   if (!mLayerManager) {
     300           0 :     return;
     301             :   }
     302           0 :   mLayerManager->SetTransactionIdAllocator(nullptr);
     303             : }
     304             : 
     305           0 : void nsBaseWidget::ReleaseContentController()
     306             : {
     307           0 :   if (mRootContentController) {
     308           0 :     mRootContentController->Destroy();
     309           0 :     mRootContentController = nullptr;
     310             :   }
     311           0 : }
     312             : 
     313           0 : void nsBaseWidget::DestroyLayerManager()
     314             : {
     315           0 :   if (mLayerManager) {
     316           0 :     mLayerManager->Destroy();
     317           0 :     mLayerManager = nullptr;
     318             :   }
     319           0 :   DestroyCompositor();
     320           0 : }
     321             : 
     322             : void
     323           0 : nsBaseWidget::OnRenderingDeviceReset()
     324             : {
     325           0 :   DestroyLayerManager();
     326           0 : }
     327             : 
     328             : void
     329           0 : nsBaseWidget::FreeShutdownObserver()
     330             : {
     331           0 :   if (mShutdownObserver) {
     332           0 :     mShutdownObserver->Unregister();
     333             :   }
     334           0 :   mShutdownObserver = nullptr;
     335           0 : }
     336             : 
     337             : //-------------------------------------------------------------------------
     338             : //
     339             : // nsBaseWidget destructor
     340             : //
     341             : //-------------------------------------------------------------------------
     342             : 
     343           0 : nsBaseWidget::~nsBaseWidget()
     344             : {
     345           0 :   IMEStateManager::WidgetDestroyed(this);
     346             : 
     347           0 :   if (mLayerManager) {
     348           0 :     if (BasicLayerManager* mgr = mLayerManager->AsBasicLayerManager()) {
     349           0 :       mgr->ClearRetainerWidget();
     350             :     }
     351             :   }
     352             : 
     353           0 :   FreeShutdownObserver();
     354           0 :   RevokeTransactionIdAllocator();
     355           0 :   DestroyLayerManager();
     356             : 
     357             : #ifdef NOISY_WIDGET_LEAKS
     358             :   gNumWidgets--;
     359             :   printf("WIDGETS- = %d\n", gNumWidgets);
     360             : #endif
     361             : 
     362           0 :   delete mOriginalBounds;
     363           0 : }
     364             : 
     365             : //-------------------------------------------------------------------------
     366             : //
     367             : // Basic create.
     368             : //
     369             : //-------------------------------------------------------------------------
     370           3 : void nsBaseWidget::BaseCreate(nsIWidget* aParent,
     371             :                               nsWidgetInitData* aInitData)
     372             : {
     373             :   static bool gDisableNativeThemeCached = false;
     374           3 :   if (!gDisableNativeThemeCached) {
     375           2 :     Preferences::AddBoolVarCache(&gDisableNativeTheme,
     376             :                                  "mozilla.widget.disable-native-theme",
     377           2 :                                  gDisableNativeTheme);
     378           2 :     gDisableNativeThemeCached = true;
     379             :   }
     380             : 
     381             :   // keep a reference to the device context
     382           3 :   if (nullptr != aInitData) {
     383           2 :     mWindowType = aInitData->mWindowType;
     384           2 :     mBorderStyle = aInitData->mBorderStyle;
     385           2 :     mPopupLevel = aInitData->mPopupLevel;
     386           2 :     mPopupType = aInitData->mPopupHint;
     387           2 :     mHasRemoteContent = aInitData->mHasRemoteContent;
     388             :   }
     389             : 
     390           3 :   if (aParent) {
     391           0 :     aParent->AddChild(this);
     392             :   }
     393           3 : }
     394             : 
     395             : //-------------------------------------------------------------------------
     396             : //
     397             : // Accessor functions to get/set the client data
     398             : //
     399             : //-------------------------------------------------------------------------
     400             : 
     401         227 : nsIWidgetListener* nsBaseWidget::GetWidgetListener()
     402             : {
     403         227 :   return mWidgetListener;
     404             : }
     405             : 
     406           2 : void nsBaseWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
     407             : {
     408           2 :   mWidgetListener = aWidgetListener;
     409           2 : }
     410             : 
     411             : already_AddRefed<nsIWidget>
     412           0 : nsBaseWidget::CreateChild(const LayoutDeviceIntRect& aRect,
     413             :                           nsWidgetInitData* aInitData,
     414             :                           bool aForceUseIWidgetParent)
     415             : {
     416           0 :   nsIWidget* parent = this;
     417           0 :   nsNativeWidget nativeParent = nullptr;
     418             : 
     419           0 :   if (!aForceUseIWidgetParent) {
     420             :     // Use only either parent or nativeParent, not both, to match
     421             :     // existing code.  Eventually Create() should be divested of its
     422             :     // nativeWidget parameter.
     423           0 :     nativeParent = parent ? parent->GetNativeData(NS_NATIVE_WIDGET) : nullptr;
     424           0 :     parent = nativeParent ? nullptr : parent;
     425           0 :     MOZ_ASSERT(!parent || !nativeParent, "messed up logic");
     426             :   }
     427             : 
     428           0 :   nsCOMPtr<nsIWidget> widget;
     429           0 :   if (aInitData && aInitData->mWindowType == eWindowType_popup) {
     430           0 :     widget = AllocateChildPopupWidget();
     431             :   } else {
     432             :     static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
     433           0 :     widget = do_CreateInstance(kCChildCID);
     434             :   }
     435             : 
     436           0 :   if (widget &&
     437           0 :       NS_SUCCEEDED(widget->Create(parent, nativeParent, aRect, aInitData))) {
     438           0 :     return widget.forget();
     439             :   }
     440             : 
     441           0 :   return nullptr;
     442             : }
     443             : 
     444             : // Attach a view to our widget which we'll send events to.
     445             : void
     446           6 : nsBaseWidget::AttachViewToTopLevel(bool aUseAttachedEvents)
     447             : {
     448           6 :   NS_ASSERTION((mWindowType == eWindowType_toplevel ||
     449             :                 mWindowType == eWindowType_dialog ||
     450             :                 mWindowType == eWindowType_invisible ||
     451             :                 mWindowType == eWindowType_child),
     452             :                "Can't attach to window of that type");
     453             : 
     454           6 :   mUseAttachedEvents = aUseAttachedEvents;
     455           6 : }
     456             : 
     457         239 : nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener()
     458             :  {
     459         239 :    return mAttachedWidgetListener;
     460             :  }
     461             : 
     462          32 : nsIWidgetListener* nsBaseWidget::GetPreviouslyAttachedWidgetListener()
     463             :  {
     464          32 :    return mPreviouslyAttachedWidgetListener;
     465             :  }
     466             : 
     467           6 : void nsBaseWidget::SetPreviouslyAttachedWidgetListener(nsIWidgetListener* aListener)
     468             :  {
     469           6 :    mPreviouslyAttachedWidgetListener = aListener;
     470           6 :  }
     471             : 
     472           9 : void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener)
     473             :  {
     474           9 :    mAttachedWidgetListener = aListener;
     475           9 :  }
     476             : 
     477             : //-------------------------------------------------------------------------
     478             : //
     479             : // Close this nsBaseWidget
     480             : //
     481             : //-------------------------------------------------------------------------
     482           0 : void nsBaseWidget::Destroy()
     483             : {
     484             :   // Just in case our parent is the only ref to us
     485           0 :   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
     486             :   // disconnect from the parent
     487           0 :   nsIWidget *parent = GetParent();
     488           0 :   if (parent) {
     489           0 :     parent->RemoveChild(this);
     490             :   }
     491             : 
     492             : #if defined(XP_WIN)
     493             :   // Allow our scroll capture container to be cleaned up, if we have one.
     494             :   mScrollCaptureContainer = nullptr;
     495             : #endif
     496           0 : }
     497             : 
     498             : //-------------------------------------------------------------------------
     499             : //
     500             : // Get this nsBaseWidget parent
     501             : //
     502             : //-------------------------------------------------------------------------
     503           2 : nsIWidget* nsBaseWidget::GetParent(void)
     504             : {
     505           2 :   return nullptr;
     506             : }
     507             : 
     508             : //-------------------------------------------------------------------------
     509             : //
     510             : // Get this nsBaseWidget top level widget
     511             : //
     512             : //-------------------------------------------------------------------------
     513          11 : nsIWidget* nsBaseWidget::GetTopLevelWidget()
     514             : {
     515          11 :   nsIWidget *topLevelWidget = nullptr, *widget = this;
     516          33 :   while (widget) {
     517          11 :     topLevelWidget = widget;
     518          11 :     widget = widget->GetParent();
     519             :   }
     520          11 :   return topLevelWidget;
     521             : }
     522             : 
     523             : //-------------------------------------------------------------------------
     524             : //
     525             : // Get this nsBaseWidget's top (non-sheet) parent (if it's a sheet)
     526             : //
     527             : //-------------------------------------------------------------------------
     528           1 : nsIWidget* nsBaseWidget::GetSheetWindowParent(void)
     529             : {
     530           1 :   return nullptr;
     531             : }
     532             : 
     533           0 : float nsBaseWidget::GetDPI()
     534             : {
     535           0 :   return 96.0f;
     536             : }
     537             : 
     538          70 : CSSToLayoutDeviceScale nsIWidget::GetDefaultScale()
     539             : {
     540          70 :   double devPixelsPerCSSPixel = DefaultScaleOverride();
     541             : 
     542          70 :   if (devPixelsPerCSSPixel <= 0.0) {
     543          70 :     devPixelsPerCSSPixel = GetDefaultScaleInternal();
     544             :   }
     545             : 
     546          70 :   return CSSToLayoutDeviceScale(devPixelsPerCSSPixel);
     547             : }
     548             : 
     549             : /* static */
     550          70 : double nsIWidget::DefaultScaleOverride()
     551             : {
     552             :   // The number of device pixels per CSS pixel. A value <= 0 means choose
     553             :   // automatically based on the DPI. A positive value is used as-is. This effectively
     554             :   // controls the size of a CSS "px".
     555             :   static float devPixelsPerCSSPixel = -1.0f;
     556             : 
     557             :   static bool valueCached = false;
     558          70 :   if (!valueCached) {
     559             :     Preferences::AddFloatVarCache(&devPixelsPerCSSPixel,
     560           2 :                                   "layout.css.devPixelsPerPx", -1.0f);
     561           2 :     valueCached = true;
     562             :   }
     563             : 
     564          70 :   return devPixelsPerCSSPixel;
     565             : }
     566             : 
     567             : //-------------------------------------------------------------------------
     568             : //
     569             : // Add a child to the list of children
     570             : //
     571             : //-------------------------------------------------------------------------
     572           0 : void nsBaseWidget::AddChild(nsIWidget* aChild)
     573             : {
     574           0 :   MOZ_ASSERT(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
     575             :              "aChild not properly removed from its old child list");
     576             : 
     577           0 :   if (!mFirstChild) {
     578           0 :     mFirstChild = mLastChild = aChild;
     579             :   } else {
     580             :     // append to the list
     581           0 :     MOZ_ASSERT(mLastChild);
     582           0 :     MOZ_ASSERT(!mLastChild->GetNextSibling());
     583           0 :     mLastChild->SetNextSibling(aChild);
     584           0 :     aChild->SetPrevSibling(mLastChild);
     585           0 :     mLastChild = aChild;
     586             :   }
     587           0 : }
     588             : 
     589             : 
     590             : //-------------------------------------------------------------------------
     591             : //
     592             : // Remove a child from the list of children
     593             : //
     594             : //-------------------------------------------------------------------------
     595           0 : void nsBaseWidget::RemoveChild(nsIWidget* aChild)
     596             : {
     597             : #ifdef DEBUG
     598             : #ifdef XP_MACOSX
     599             :   // nsCocoaWindow doesn't implement GetParent, so in that case parent will be
     600             :   // null and we'll just have to do without this assertion.
     601             :   nsIWidget* parent = aChild->GetParent();
     602             :   NS_ASSERTION(!parent || parent == this, "Not one of our kids!");
     603             : #else
     604           0 :   MOZ_RELEASE_ASSERT(aChild->GetParent() == this, "Not one of our kids!");
     605             : #endif
     606             : #endif
     607             : 
     608           0 :   if (mLastChild == aChild) {
     609           0 :     mLastChild = mLastChild->GetPrevSibling();
     610             :   }
     611           0 :   if (mFirstChild == aChild) {
     612           0 :     mFirstChild = mFirstChild->GetNextSibling();
     613             :   }
     614             : 
     615             :   // Now remove from the list.  Make sure that we pass ownership of the tail
     616             :   // of the list correctly before we have aChild let go of it.
     617           0 :   nsIWidget* prev = aChild->GetPrevSibling();
     618           0 :   nsIWidget* next = aChild->GetNextSibling();
     619           0 :   if (prev) {
     620           0 :     prev->SetNextSibling(next);
     621             :   }
     622           0 :   if (next) {
     623           0 :     next->SetPrevSibling(prev);
     624             :   }
     625             : 
     626           0 :   aChild->SetNextSibling(nullptr);
     627           0 :   aChild->SetPrevSibling(nullptr);
     628           0 : }
     629             : 
     630             : 
     631             : //-------------------------------------------------------------------------
     632             : //
     633             : // Sets widget's position within its parent's child list.
     634             : //
     635             : //-------------------------------------------------------------------------
     636           0 : void nsBaseWidget::SetZIndex(int32_t aZIndex)
     637             : {
     638             :   // Hold a ref to ourselves just in case, since we're going to remove
     639             :   // from our parent.
     640           0 :   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
     641             : 
     642           0 :   mZIndex = aZIndex;
     643             : 
     644             :   // reorder this child in its parent's list.
     645           0 :   auto* parent = static_cast<nsBaseWidget*>(GetParent());
     646           0 :   if (parent) {
     647           0 :     parent->RemoveChild(this);
     648             :     // Scope sib outside the for loop so we can check it afterward
     649           0 :     nsIWidget* sib = parent->GetFirstChild();
     650           0 :     for ( ; sib; sib = sib->GetNextSibling()) {
     651           0 :       int32_t childZIndex = GetZIndex();
     652           0 :       if (aZIndex < childZIndex) {
     653             :         // Insert ourselves before sib
     654           0 :         nsIWidget* prev = sib->GetPrevSibling();
     655           0 :         mNextSibling = sib;
     656           0 :         mPrevSibling = prev;
     657           0 :         sib->SetPrevSibling(this);
     658           0 :         if (prev) {
     659           0 :           prev->SetNextSibling(this);
     660             :         } else {
     661           0 :           NS_ASSERTION(sib == parent->mFirstChild, "Broken child list");
     662             :           // We've taken ownership of sib, so it's safe to have parent let
     663             :           // go of it
     664           0 :           parent->mFirstChild = this;
     665             :         }
     666           0 :         PlaceBehind(eZPlacementBelow, sib, false);
     667           0 :         break;
     668             :       }
     669             :     }
     670             :     // were we added to the list?
     671           0 :     if (!sib) {
     672           0 :       parent->AddChild(this);
     673             :     }
     674             :   }
     675           0 : }
     676             : 
     677             : //-------------------------------------------------------------------------
     678             : //
     679             : // Maximize, minimize or restore the window. The BaseWidget implementation
     680             : // merely stores the state.
     681             : //
     682             : //-------------------------------------------------------------------------
     683             : void
     684           5 : nsBaseWidget::SetSizeMode(nsSizeMode aMode)
     685             : {
     686           5 :   MOZ_ASSERT(aMode == nsSizeMode_Normal ||
     687             :              aMode == nsSizeMode_Minimized ||
     688             :              aMode == nsSizeMode_Maximized ||
     689             :              aMode == nsSizeMode_Fullscreen);
     690           5 :   mSizeMode = aMode;
     691           5 : }
     692             : 
     693             : //-------------------------------------------------------------------------
     694             : //
     695             : // Get this component cursor
     696             : //
     697             : //-------------------------------------------------------------------------
     698           0 : nsCursor nsBaseWidget::GetCursor()
     699             : {
     700           0 :   return mCursor;
     701             : }
     702             : 
     703             : void
     704           0 : nsBaseWidget::SetCursor(nsCursor aCursor)
     705             : {
     706           0 :   mCursor = aCursor;
     707           0 : }
     708             : 
     709             : nsresult
     710           0 : nsBaseWidget::SetCursor(imgIContainer* aCursor,
     711             :                         uint32_t aHotspotX, uint32_t aHotspotY)
     712             : {
     713           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     714             : }
     715             : 
     716             : //-------------------------------------------------------------------------
     717             : //
     718             : // Window transparency methods
     719             : //
     720             : //-------------------------------------------------------------------------
     721             : 
     722           0 : void nsBaseWidget::SetTransparencyMode(nsTransparencyMode aMode) {
     723           0 : }
     724             : 
     725           0 : nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
     726           0 :   return eTransparencyOpaque;
     727             : }
     728             : 
     729             : bool
     730           0 : nsBaseWidget::IsWindowClipRegionEqual(const nsTArray<LayoutDeviceIntRect>& aRects)
     731             : {
     732           0 :   return mClipRects &&
     733           0 :          mClipRectCount == aRects.Length() &&
     734           0 :          memcmp(mClipRects.get(), aRects.Elements(), sizeof(LayoutDeviceIntRect)*mClipRectCount) == 0;
     735             : }
     736             : 
     737             : void
     738           0 : nsBaseWidget::StoreWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects)
     739             : {
     740           0 :   mClipRectCount = aRects.Length();
     741           0 :   mClipRects = MakeUnique<LayoutDeviceIntRect[]>(mClipRectCount);
     742           0 :   if (mClipRects) {
     743           0 :     memcpy(mClipRects.get(), aRects.Elements(), sizeof(LayoutDeviceIntRect)*mClipRectCount);
     744             :   }
     745           0 : }
     746             : 
     747             : void
     748           0 : nsBaseWidget::GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects)
     749             : {
     750           0 :   if (mClipRects) {
     751           0 :     aRects->AppendElements(mClipRects.get(), mClipRectCount);
     752             :   } else {
     753           0 :     aRects->AppendElement(LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height));
     754             :   }
     755           0 : }
     756             : 
     757             : const LayoutDeviceIntRegion
     758           0 : nsBaseWidget::RegionFromArray(const nsTArray<LayoutDeviceIntRect>& aRects)
     759             : {
     760           0 :   LayoutDeviceIntRegion region;
     761           0 :   for (uint32_t i = 0; i < aRects.Length(); ++i) {
     762           0 :     region.Or(region, aRects[i]);
     763             :   }
     764           0 :   return region;
     765             : }
     766             : 
     767             : void
     768           0 : nsBaseWidget::ArrayFromRegion(const LayoutDeviceIntRegion& aRegion,
     769             :                               nsTArray<LayoutDeviceIntRect>& aRects)
     770             : {
     771           0 :   for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
     772           0 :     aRects.AppendElement(iter.Get());
     773             :   }
     774           0 : }
     775             : 
     776             : nsresult
     777           0 : nsBaseWidget::SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
     778             :                                   bool aIntersectWithExisting)
     779             : {
     780           0 :   if (!aIntersectWithExisting) {
     781           0 :     StoreWindowClipRegion(aRects);
     782             :   } else {
     783             :     // get current rects
     784           0 :     nsTArray<LayoutDeviceIntRect> currentRects;
     785           0 :     GetWindowClipRegion(&currentRects);
     786             :     // create region from them
     787           0 :     LayoutDeviceIntRegion currentRegion = RegionFromArray(currentRects);
     788             :     // create region from new rects
     789           0 :     LayoutDeviceIntRegion newRegion = RegionFromArray(aRects);
     790             :     // intersect regions
     791           0 :     LayoutDeviceIntRegion intersection;
     792           0 :     intersection.And(currentRegion, newRegion);
     793             :     // create int rect array from intersection
     794           0 :     nsTArray<LayoutDeviceIntRect> rects;
     795           0 :     ArrayFromRegion(intersection, rects);
     796             :     // store
     797           0 :     StoreWindowClipRegion(rects);
     798             :   }
     799           0 :   return NS_OK;
     800             : }
     801             : 
     802             : /* virtual */ void
     803           0 : nsBaseWidget::PerformFullscreenTransition(FullscreenTransitionStage aStage,
     804             :                                           uint16_t aDuration,
     805             :                                           nsISupports* aData,
     806             :                                           nsIRunnable* aCallback)
     807             : {
     808           0 :   MOZ_ASSERT_UNREACHABLE(
     809             :     "Should never call PerformFullscreenTransition on nsBaseWidget");
     810             : }
     811             : 
     812             : //-------------------------------------------------------------------------
     813             : //
     814             : // Put the window into full-screen mode
     815             : //
     816             : //-------------------------------------------------------------------------
     817             : void
     818           0 : nsBaseWidget::InfallibleMakeFullScreen(bool aFullScreen, nsIScreen* aScreen)
     819             : {
     820           0 :   HideWindowChrome(aFullScreen);
     821             : 
     822           0 :   if (aFullScreen) {
     823           0 :     if (!mOriginalBounds) {
     824           0 :       mOriginalBounds = new LayoutDeviceIntRect();
     825             :     }
     826           0 :     *mOriginalBounds = GetScreenBounds();
     827             : 
     828             :     // Move to top-left corner of screen and size to the screen dimensions
     829           0 :     nsCOMPtr<nsIScreen> screen = aScreen;
     830           0 :     if (!screen) {
     831           0 :       screen = GetWidgetScreen();
     832             :     }
     833           0 :     if (screen) {
     834             :       int32_t left, top, width, height;
     835           0 :       if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
     836           0 :         Resize(left, top, width, height, true);
     837             :       }
     838             :     }
     839           0 :   } else if (mOriginalBounds) {
     840           0 :     if (BoundsUseDesktopPixels()) {
     841           0 :       DesktopRect deskRect = *mOriginalBounds / GetDesktopToDeviceScale();
     842           0 :       Resize(deskRect.x, deskRect.y, deskRect.width, deskRect.height, true);
     843             :     } else {
     844           0 :       Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
     845           0 :              mOriginalBounds->height, true);
     846             :     }
     847             :   }
     848           0 : }
     849             : 
     850             : nsresult
     851           0 : nsBaseWidget::MakeFullScreen(bool aFullScreen, nsIScreen* aScreen)
     852             : {
     853           0 :   InfallibleMakeFullScreen(aFullScreen, aScreen);
     854           0 :   return NS_OK;
     855             : }
     856             : 
     857           0 : nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
     858             :     nsBaseWidget* aWidget, gfxContext* aTarget,
     859           0 :     BufferMode aDoubleBuffering, ScreenRotation aRotation)
     860           0 :   : mWidget(aWidget)
     861             : {
     862           0 :   LayerManager* lm = mWidget->GetLayerManager();
     863           0 :   NS_ASSERTION(!lm || lm->GetBackendType() == LayersBackend::LAYERS_BASIC,
     864             :     "AutoLayerManagerSetup instantiated for non-basic layer backend!");
     865           0 :   if (lm) {
     866           0 :     mLayerManager = lm->AsBasicLayerManager();
     867           0 :     if (mLayerManager) {
     868           0 :       mLayerManager->SetDefaultTarget(aTarget);
     869           0 :       mLayerManager->SetDefaultTargetConfiguration(aDoubleBuffering, aRotation);
     870             :     }
     871             :   }
     872           0 : }
     873             : 
     874           0 : nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
     875             : {
     876           0 :   if (mLayerManager) {
     877           0 :     mLayerManager->SetDefaultTarget(nullptr);
     878           0 :     mLayerManager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, ROTATION_0);
     879             :   }
     880           0 : }
     881             : 
     882           2 : bool nsBaseWidget::IsSmallPopup() const
     883             : {
     884           2 :   return mWindowType == eWindowType_popup && mPopupType != ePopupTypePanel;
     885             : }
     886             : 
     887             : bool
     888           1 : nsBaseWidget::ComputeShouldAccelerate()
     889             : {
     890           1 :   return gfx::gfxConfig::IsEnabled(gfx::Feature::HW_COMPOSITING) &&
     891           1 :          WidgetTypeSupportsAcceleration();
     892             : }
     893             : 
     894             : bool
     895           1 : nsBaseWidget::UseAPZ()
     896             : {
     897           3 :   return (gfxPlatform::AsyncPanZoomEnabled() &&
     898           1 :           (WindowType() == eWindowType_toplevel ||
     899           0 :            WindowType() == eWindowType_child ||
     900           1 :            (WindowType() == eWindowType_popup && HasRemoteContent())));
     901             : }
     902             : 
     903           1 : void nsBaseWidget::CreateCompositor()
     904             : {
     905           1 :   LayoutDeviceIntRect rect = GetBounds();
     906           1 :   CreateCompositor(rect.width, rect.height);
     907           1 : }
     908             : 
     909             : already_AddRefed<GeckoContentController>
     910           1 : nsBaseWidget::CreateRootContentController()
     911             : {
     912           3 :   RefPtr<GeckoContentController> controller = new ChromeProcessController(this, mAPZEventState, mAPZC);
     913           2 :   return controller.forget();
     914             : }
     915             : 
     916           1 : void nsBaseWidget::ConfigureAPZCTreeManager()
     917             : {
     918           1 :   MOZ_ASSERT(mAPZC);
     919             : 
     920           1 :   ConfigureAPZControllerThread();
     921             : 
     922           1 :   mAPZC->SetDPI(GetDPI());
     923             : 
     924           1 :   if (gfxPrefs::APZKeyboardEnabled()) {
     925           0 :     mAPZC->SetKeyboardMap(nsXBLWindowKeyHandler::CollectKeyboardShortcuts());
     926             :   }
     927             : 
     928           2 :   RefPtr<IAPZCTreeManager> treeManager = mAPZC;  // for capture by the lambdas
     929             : 
     930             :   ContentReceivedInputBlockCallback callback(
     931           2 :       [treeManager](const ScrollableLayerGuid& aGuid,
     932             :                     uint64_t aInputBlockId,
     933           0 :                     bool aPreventDefault)
     934             :       {
     935           0 :         MOZ_ASSERT(NS_IsMainThread());
     936           0 :         APZThreadUtils::RunOnControllerThread(NewRunnableMethod<uint64_t, bool>(
     937             :           "layers::IAPZCTreeManager::ContentReceivedInputBlock",
     938             :           treeManager,
     939             :           &IAPZCTreeManager::ContentReceivedInputBlock,
     940             :           aInputBlockId,
     941           0 :           aPreventDefault));
     942           2 :       });
     943           2 :   mAPZEventState = new APZEventState(this, mozilla::Move(callback));
     944             : 
     945           4 :   mSetAllowedTouchBehaviorCallback = [treeManager](uint64_t aInputBlockId,
     946           0 :                                                    const nsTArray<TouchBehaviorFlags>& aFlags)
     947             :   {
     948           0 :     MOZ_ASSERT(NS_IsMainThread());
     949           0 :     APZThreadUtils::RunOnControllerThread(
     950             :       NewRunnableMethod<uint64_t,
     951           0 :                         StoreCopyPassByLRef<nsTArray<TouchBehaviorFlags>>>(
     952             :         "layers::IAPZCTreeManager::SetAllowedTouchBehavior",
     953             :         treeManager,
     954             :         &IAPZCTreeManager::SetAllowedTouchBehavior,
     955             :         aInputBlockId,
     956           0 :         aFlags));
     957           1 :   };
     958             : 
     959           1 :   mRootContentController = CreateRootContentController();
     960           1 :   if (mRootContentController) {
     961           1 :     mCompositorSession->SetContentController(mRootContentController);
     962             :   }
     963             : 
     964             :   // When APZ is enabled, we can actually enable raw touch events because we
     965             :   // have code that can deal with them properly. If APZ is not enabled, this
     966             :   // function doesn't get called.
     967           1 :   if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) ||
     968           0 :       Preferences::GetBool("dom.w3c_pointer_events.enabled", false)) {
     969           1 :     RegisterTouchWindow();
     970             :   }
     971           1 : }
     972             : 
     973           1 : void nsBaseWidget::ConfigureAPZControllerThread()
     974             : {
     975             :   // By default the controller thread is the main thread.
     976           1 :   APZThreadUtils::SetControllerThread(MessageLoop::current());
     977           1 : }
     978             : 
     979             : void
     980           0 : nsBaseWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
     981             :                                      const nsTArray<ScrollableLayerGuid>& aTargets) const
     982             : {
     983           0 :   APZThreadUtils::RunOnControllerThread(
     984             :     NewRunnableMethod<uint64_t,
     985           0 :                       StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>(
     986             :       "layers::IAPZCTreeManager::SetTargetAPZC",
     987             :       mAPZC,
     988             :       &IAPZCTreeManager::SetTargetAPZC,
     989             :       aInputBlockId,
     990           0 :       aTargets));
     991           0 : }
     992             : 
     993             : void
     994           0 : nsBaseWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
     995             :                                     const FrameMetrics::ViewID& aViewId,
     996             :                                     const Maybe<ZoomConstraints>& aConstraints)
     997             : {
     998           0 :   if (!mCompositorSession || !mAPZC) {
     999           0 :     if (mInitialZoomConstraints) {
    1000           0 :       MOZ_ASSERT(mInitialZoomConstraints->mPresShellID == aPresShellId);
    1001           0 :       MOZ_ASSERT(mInitialZoomConstraints->mViewID == aViewId);
    1002           0 :       if (!aConstraints) {
    1003           0 :         mInitialZoomConstraints.reset();
    1004             :       }
    1005             :     }
    1006             : 
    1007           0 :     if (aConstraints) {
    1008             :       // We have some constraints, but the compositor and APZC aren't created yet.
    1009             :       // Save these so we can use them later.
    1010           0 :       mInitialZoomConstraints = Some(InitialZoomConstraints(aPresShellId, aViewId, aConstraints.ref()));
    1011             :     }
    1012           0 :     return;
    1013             :   }
    1014           0 :   uint64_t layersId = mCompositorSession->RootLayerTreeId();
    1015           0 :   mAPZC->UpdateZoomConstraints(ScrollableLayerGuid(layersId, aPresShellId, aViewId),
    1016           0 :                                aConstraints);
    1017             : }
    1018             : 
    1019             : bool
    1020         598 : nsBaseWidget::AsyncPanZoomEnabled() const
    1021             : {
    1022         598 :   return !!mAPZC;
    1023             : }
    1024             : 
    1025             : nsEventStatus
    1026           6 : nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent,
    1027             :                                            const ScrollableLayerGuid& aGuid,
    1028             :                                            uint64_t aInputBlockId,
    1029             :                                            nsEventStatus aApzResponse)
    1030             : {
    1031           6 :   MOZ_ASSERT(NS_IsMainThread());
    1032          12 :   InputAPZContext context(aGuid, aInputBlockId, aApzResponse);
    1033             : 
    1034             :   // If this is an event that the APZ has targeted to an APZC in the root
    1035             :   // process, apply that APZC's callback-transform before dispatching the
    1036             :   // event. If the event is instead targeted to an APZC in the child process,
    1037             :   // the transform will be applied in the child process before dispatching
    1038             :   // the event there (see e.g. TabChild::RecvRealTouchEvent()).
    1039           6 :   if (aGuid.mLayersId == mCompositorSession->RootLayerTreeId()) {
    1040           5 :     APZCCallbackHelper::ApplyCallbackTransform(*aEvent, aGuid,
    1041          10 :         GetDefaultScale());
    1042             :   }
    1043             : 
    1044             :   // Make a copy of the original event for the APZCCallbackHelper helpers that
    1045             :   // we call later, because the event passed to DispatchEvent can get mutated in
    1046             :   // ways that we don't want (i.e. touch points can get stripped out).
    1047             :   nsEventStatus status;
    1048          12 :   UniquePtr<WidgetEvent> original(aEvent->Duplicate());
    1049           6 :   DispatchEvent(aEvent, status);
    1050             : 
    1051           6 :   if (mAPZC && !context.WasRoutedToChildProcess() && aInputBlockId) {
    1052             :     // EventStateManager did not route the event into the child process.
    1053             :     // It's safe to communicate to APZ that the event has been processed.
    1054             :     // TODO: Eventually we'll be able to move the SendSetTargetAPZCNotification
    1055             :     // call into APZEventState::Process*Event() as well.
    1056           0 :     if (WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent()) {
    1057           0 :       if (touchEvent->mMessage == eTouchStart) {
    1058           0 :         if (gfxPrefs::TouchActionEnabled()) {
    1059           0 :           APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(this,
    1060           0 :               GetDocument(), *(original->AsTouchEvent()), aInputBlockId,
    1061           0 :               mSetAllowedTouchBehaviorCallback);
    1062             :         }
    1063           0 :         APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(),
    1064           0 :             *(original->AsTouchEvent()), aGuid, aInputBlockId);
    1065             :       }
    1066           0 :       mAPZEventState->ProcessTouchEvent(*touchEvent, aGuid, aInputBlockId,
    1067           0 :           aApzResponse, status);
    1068           0 :     } else if (WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent()) {
    1069           0 :       MOZ_ASSERT(wheelEvent->mFlags.mHandledByAPZ);
    1070           0 :       APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(),
    1071           0 :           *(original->AsWheelEvent()), aGuid, aInputBlockId);
    1072           0 :       if (wheelEvent->mCanTriggerSwipe) {
    1073           0 :         ReportSwipeStarted(aInputBlockId, wheelEvent->TriggersSwipe());
    1074             :       }
    1075           0 :       mAPZEventState->ProcessWheelEvent(*wheelEvent, aGuid, aInputBlockId);
    1076           0 :     } else if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
    1077           0 :       MOZ_ASSERT(mouseEvent->mFlags.mHandledByAPZ);
    1078           0 :       APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(),
    1079           0 :           *(original->AsMouseEvent()), aGuid, aInputBlockId);
    1080           0 :       mAPZEventState->ProcessMouseEvent(*mouseEvent, aGuid, aInputBlockId);
    1081             :     }
    1082             :   }
    1083             : 
    1084          12 :   return status;
    1085             : }
    1086             : 
    1087           0 : class DispatchWheelEventOnMainThread : public Runnable
    1088             : {
    1089             : public:
    1090           0 :   DispatchWheelEventOnMainThread(const ScrollWheelInput& aWheelInput,
    1091             :                                  nsBaseWidget* aWidget,
    1092             :                                  nsEventStatus aAPZResult,
    1093             :                                  uint64_t aInputBlockId,
    1094             :                                  ScrollableLayerGuid aGuid)
    1095           0 :     : mozilla::Runnable("DispatchWheelEventOnMainThread")
    1096             :     , mWheelInput(aWheelInput)
    1097             :     , mWidget(aWidget)
    1098             :     , mAPZResult(aAPZResult)
    1099             :     , mInputBlockId(aInputBlockId)
    1100           0 :     , mGuid(aGuid)
    1101             :   {
    1102           0 :   }
    1103             : 
    1104           0 :   NS_IMETHOD Run() override
    1105             :   {
    1106           0 :     WidgetWheelEvent wheelEvent = mWheelInput.ToWidgetWheelEvent(mWidget);
    1107           0 :     mWidget->ProcessUntransformedAPZEvent(&wheelEvent, mGuid, mInputBlockId, mAPZResult);
    1108           0 :     return NS_OK;
    1109             :   }
    1110             : 
    1111             : private:
    1112             :   ScrollWheelInput mWheelInput;
    1113             :   nsBaseWidget* mWidget;
    1114             :   nsEventStatus mAPZResult;
    1115             :   uint64_t mInputBlockId;
    1116             :   ScrollableLayerGuid mGuid;
    1117             : };
    1118             : 
    1119           0 : class DispatchWheelInputOnControllerThread : public Runnable
    1120             : {
    1121             : public:
    1122           0 :   DispatchWheelInputOnControllerThread(const WidgetWheelEvent& aWheelEvent,
    1123             :                                        IAPZCTreeManager* aAPZC,
    1124             :                                        nsBaseWidget* aWidget)
    1125           0 :     : mozilla::Runnable("DispatchWheelInputOnControllerThread")
    1126           0 :     , mMainMessageLoop(MessageLoop::current())
    1127             :     , mWheelInput(aWheelEvent)
    1128             :     , mAPZC(aAPZC)
    1129             :     , mWidget(aWidget)
    1130           0 :     , mInputBlockId(0)
    1131             :   {
    1132           0 :   }
    1133             : 
    1134           0 :   NS_IMETHOD Run() override
    1135             :   {
    1136           0 :     nsEventStatus result = mAPZC->ReceiveInputEvent(mWheelInput, &mGuid, &mInputBlockId);
    1137           0 :     if (result == nsEventStatus_eConsumeNoDefault) {
    1138           0 :       return NS_OK;
    1139             :     }
    1140           0 :     RefPtr<Runnable> r = new DispatchWheelEventOnMainThread(mWheelInput, mWidget, result, mInputBlockId, mGuid);
    1141           0 :     mMainMessageLoop->PostTask(r.forget());
    1142           0 :     return NS_OK;
    1143             :   }
    1144             : 
    1145             : private:
    1146             :   MessageLoop* mMainMessageLoop;
    1147             :   ScrollWheelInput mWheelInput;
    1148             :   RefPtr<IAPZCTreeManager> mAPZC;
    1149             :   nsBaseWidget* mWidget;
    1150             :   uint64_t mInputBlockId;
    1151             :   ScrollableLayerGuid mGuid;
    1152             : };
    1153             : 
    1154             : void
    1155           0 : nsBaseWidget::DispatchTouchInput(MultiTouchInput& aInput)
    1156             : {
    1157           0 :   MOZ_ASSERT(NS_IsMainThread());
    1158           0 :   if (mAPZC) {
    1159           0 :     MOZ_ASSERT(APZThreadUtils::IsControllerThread());
    1160           0 :     uint64_t inputBlockId = 0;
    1161           0 :     ScrollableLayerGuid guid;
    1162             : 
    1163           0 :     nsEventStatus result = mAPZC->ReceiveInputEvent(aInput, &guid, &inputBlockId);
    1164           0 :     if (result == nsEventStatus_eConsumeNoDefault) {
    1165           0 :       return;
    1166             :     }
    1167             : 
    1168           0 :     WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this);
    1169           0 :     ProcessUntransformedAPZEvent(&event, guid, inputBlockId, result);
    1170             :   } else {
    1171           0 :     WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this);
    1172             : 
    1173             :     nsEventStatus status;
    1174           0 :     DispatchEvent(&event, status);
    1175             :   }
    1176             : }
    1177             : 
    1178             : nsEventStatus
    1179           6 : nsBaseWidget::DispatchInputEvent(WidgetInputEvent* aEvent)
    1180             : {
    1181           6 :   MOZ_ASSERT(NS_IsMainThread());
    1182           6 :   if (mAPZC) {
    1183           6 :     if (APZThreadUtils::IsControllerThread()) {
    1184           6 :       uint64_t inputBlockId = 0;
    1185          12 :       ScrollableLayerGuid guid;
    1186             : 
    1187             :       nsEventStatus result =
    1188           6 :         mAPZC->ReceiveInputEvent(*aEvent, &guid, &inputBlockId);
    1189           6 :       if (result == nsEventStatus_eConsumeNoDefault) {
    1190           0 :         return result;
    1191             :       }
    1192           6 :       return ProcessUntransformedAPZEvent(aEvent, guid, inputBlockId, result);
    1193             :     }
    1194           0 :     WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
    1195           0 :     if (wheelEvent) {
    1196             :       RefPtr<Runnable> r =
    1197           0 :         new DispatchWheelInputOnControllerThread(*wheelEvent, mAPZC, this);
    1198           0 :       APZThreadUtils::RunOnControllerThread(r.forget());
    1199           0 :       return nsEventStatus_eConsumeDoDefault;
    1200             :     }
    1201             :     // Allow dispatching keyboard events on Gecko thread.
    1202           0 :     MOZ_ASSERT(aEvent->AsKeyboardEvent());
    1203             :   }
    1204             : 
    1205             :   nsEventStatus status;
    1206           0 :   DispatchEvent(aEvent, status);
    1207           0 :   return status;
    1208             : }
    1209             : 
    1210             : void
    1211           0 : nsBaseWidget::DispatchEventToAPZOnly(mozilla::WidgetInputEvent* aEvent)
    1212             : {
    1213           0 :   MOZ_ASSERT(NS_IsMainThread());
    1214           0 :   if (mAPZC) {
    1215           0 :     MOZ_ASSERT(APZThreadUtils::IsControllerThread());
    1216           0 :     uint64_t inputBlockId = 0;
    1217           0 :     ScrollableLayerGuid guid;
    1218           0 :     mAPZC->ReceiveInputEvent(*aEvent, &guid, &inputBlockId);
    1219             :   }
    1220           0 : }
    1221             : 
    1222             : nsIDocument*
    1223           0 : nsBaseWidget::GetDocument() const
    1224             : {
    1225           0 :   if (mWidgetListener) {
    1226           0 :     if (nsIPresShell* presShell = mWidgetListener->GetPresShell()) {
    1227           0 :       return presShell->GetDocument();
    1228             :     }
    1229             :   }
    1230           0 :   return nullptr;
    1231             : }
    1232             : 
    1233           1 : void nsBaseWidget::CreateCompositorVsyncDispatcher()
    1234             : {
    1235             :   // Parent directly listens to the vsync source whereas
    1236             :   // child process communicate via IPC
    1237             :   // Should be called AFTER gfxPlatform is initialized
    1238           1 :   if (XRE_IsParentProcess()) {
    1239           1 :     mCompositorVsyncDispatcher = new CompositorVsyncDispatcher();
    1240             :   }
    1241           1 : }
    1242             : 
    1243             : CompositorVsyncDispatcher*
    1244          17 : nsBaseWidget::GetCompositorVsyncDispatcher()
    1245             : {
    1246          17 :   return mCompositorVsyncDispatcher;
    1247             : }
    1248             : 
    1249           1 : void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
    1250             : {
    1251             :   // This makes sure that gfxPlatforms gets initialized if it hasn't by now.
    1252           1 :   gfxPlatform::GetPlatform();
    1253             : 
    1254           1 :   MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(),
    1255             :              "This function assumes OMTC");
    1256             : 
    1257           1 :   MOZ_ASSERT(!mCompositorSession && !mCompositorBridgeChild,
    1258             :     "Should have properly cleaned up the previous PCompositor pair beforehand");
    1259             : 
    1260           1 :   if (mCompositorBridgeChild) {
    1261           0 :     mCompositorBridgeChild->Destroy();
    1262             :   }
    1263             : 
    1264             :   // Recreating this is tricky, as we may still have an old and we need
    1265             :   // to make sure it's properly destroyed by calling DestroyCompositor!
    1266             : 
    1267             :   // If we've already received a shutdown notification, don't try
    1268             :   // create a new compositor.
    1269           1 :   if (!mShutdownObserver) {
    1270           0 :     return;
    1271             :   }
    1272             : 
    1273           1 :   CreateCompositorVsyncDispatcher();
    1274             : 
    1275           1 :   bool enableWR = gfx::gfxVars::UseWebRender();
    1276           1 :   if (enableWR && !WidgetTypeSupportsAcceleration()) {
    1277             :     // fall back to basic
    1278           0 :     return;
    1279             :   }
    1280           1 :   bool enableAPZ = UseAPZ();
    1281           1 :   CompositorOptions options(enableAPZ, enableWR);
    1282             : 
    1283           1 :   bool enableAL = gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS);
    1284           1 :   options.SetUseAdvancedLayers(enableAL);
    1285             : 
    1286           2 :   RefPtr<LayerManager> lm;
    1287           1 :   if (options.UseWebRender()) {
    1288           0 :     lm = new WebRenderLayerManager(this);
    1289             :   } else {
    1290           1 :     lm = new ClientLayerManager(this);
    1291             :   }
    1292             : 
    1293           1 :   gfx::GPUProcessManager* gpu = gfx::GPUProcessManager::Get();
    1294           3 :   mCompositorSession = gpu->CreateTopLevelCompositor(
    1295             :     this,
    1296             :     lm,
    1297           2 :     GetDefaultScale(),
    1298             :     options,
    1299           1 :     UseExternalCompositingSurface(),
    1300           3 :     gfx::IntSize(aWidth, aHeight));
    1301           1 :   mCompositorBridgeChild = mCompositorSession->GetCompositorBridgeChild();
    1302           1 :   mCompositorWidgetDelegate = mCompositorSession->GetCompositorWidgetDelegate();
    1303             : 
    1304           1 :   if (options.UseAPZ()) {
    1305           1 :     mAPZC = mCompositorSession->GetAPZCTreeManager();
    1306           1 :     ConfigureAPZCTreeManager();
    1307             :   } else {
    1308           0 :     mAPZC = nullptr;
    1309             :   }
    1310             : 
    1311           1 :   if (mInitialZoomConstraints) {
    1312           0 :     UpdateZoomConstraints(mInitialZoomConstraints->mPresShellID,
    1313           0 :                           mInitialZoomConstraints->mViewID,
    1314           0 :                           Some(mInitialZoomConstraints->mConstraints));
    1315           0 :     mInitialZoomConstraints.reset();
    1316             :   }
    1317             : 
    1318           1 :   if (lm->AsWebRenderLayerManager()) {
    1319           0 :     TextureFactoryIdentifier textureFactoryIdentifier;
    1320           0 :     lm->AsWebRenderLayerManager()->Initialize(mCompositorBridgeChild,
    1321           0 :                                               wr::AsPipelineId(mCompositorSession->RootLayerTreeId()),
    1322           0 :                                               &textureFactoryIdentifier);
    1323           0 :     ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
    1324           0 :     gfx::VRManagerChild::IdentifyTextureHost(textureFactoryIdentifier);
    1325             :   }
    1326             : 
    1327           1 :   ShadowLayerForwarder* lf = lm->AsShadowForwarder();
    1328           1 :   if (lf) {
    1329             :     // lf is non-null if we are creating a ClientLayerManager above
    1330           1 :     TextureFactoryIdentifier textureFactoryIdentifier;
    1331           1 :     PLayerTransactionChild* shadowManager = nullptr;
    1332             : 
    1333           2 :     nsTArray<LayersBackend> backendHints;
    1334           1 :     gfxPlatform::GetPlatform()->GetCompositorBackends(ComputeShouldAccelerate(), backendHints);
    1335             : 
    1336           1 :     bool success = false;
    1337           1 :     if (!backendHints.IsEmpty()) {
    1338             :       shadowManager =
    1339           1 :         mCompositorBridgeChild->SendPLayerTransactionConstructor(backendHints, 0);
    1340           2 :       if (shadowManager->SendGetTextureFactoryIdentifier(&textureFactoryIdentifier) &&
    1341           1 :           textureFactoryIdentifier.mParentBackend != LayersBackend::LAYERS_NONE)
    1342             :       {
    1343           1 :         success = true;
    1344             :       }
    1345             :     }
    1346             : 
    1347           1 :     if (!success) {
    1348           0 :       NS_WARNING("Failed to create an OMT compositor.");
    1349           0 :       DestroyCompositor();
    1350           0 :       mLayerManager = nullptr;
    1351           0 :       return;
    1352             :     }
    1353             : 
    1354           1 :     lf->SetShadowManager(shadowManager);
    1355           1 :     lm->UpdateTextureFactoryIdentifier(textureFactoryIdentifier, 0);
    1356             :     // Some popup or transparent widgets may use a different backend than the
    1357             :     // compositors used with ImageBridge and VR (and more generally web content).
    1358           1 :     if (WidgetTypeSupportsAcceleration()) {
    1359           1 :       ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
    1360           1 :       gfx::VRManagerChild::IdentifyTextureHost(textureFactoryIdentifier);
    1361             :     }
    1362             :   }
    1363             : 
    1364           1 :   WindowUsesOMTC();
    1365             : 
    1366           1 :   mLayerManager = lm.forget();
    1367             : 
    1368             :   // Only track compositors for top-level windows, since other window types
    1369             :   // may use the basic compositor.  Except on the OS X - see bug 1306383
    1370             : #if defined(XP_MACOSX)
    1371             :   bool getCompositorFromThisWindow = true;
    1372             : #else
    1373           1 :   bool getCompositorFromThisWindow = (mWindowType == eWindowType_toplevel);
    1374             : #endif
    1375             : 
    1376           1 :   if (getCompositorFromThisWindow) {
    1377           1 :     gfxPlatform::GetPlatform()->NotifyCompositorCreated(mLayerManager->GetCompositorBackendType());
    1378             :   }
    1379             : }
    1380             : 
    1381           0 : void nsBaseWidget::NotifyCompositorSessionLost(CompositorSession* aSession)
    1382             : {
    1383           0 :   MOZ_ASSERT(aSession == mCompositorSession);
    1384           0 :   DestroyLayerManager();
    1385           0 : }
    1386             : 
    1387           1 : bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
    1388             : {
    1389           1 :   return gfxPlatform::UsesOffMainThreadCompositing();
    1390             : }
    1391             : 
    1392         219 : LayerManager* nsBaseWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
    1393             :                                             LayersBackend aBackendHint,
    1394             :                                             LayerManagerPersistence aPersistence)
    1395             : {
    1396         219 :   if (!mLayerManager) {
    1397           1 :     if (!mShutdownObserver) {
    1398             :       // We are shutting down, do not try to re-create a LayerManager
    1399           0 :       return nullptr;
    1400             :     }
    1401             :     // Try to use an async compositor first, if possible
    1402           1 :     if (ShouldUseOffMainThreadCompositing()) {
    1403             :       // e10s uses the parameter to pass in the shadow manager from the TabChild
    1404             :       // so we don't expect to see it there since this doesn't support e10s.
    1405           1 :       NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
    1406           1 :       CreateCompositor();
    1407             :     }
    1408             : 
    1409           1 :     if (!mLayerManager) {
    1410           0 :       mLayerManager = CreateBasicLayerManager();
    1411             :     }
    1412             :   }
    1413         219 :   return mLayerManager;
    1414             : }
    1415             : 
    1416           0 : LayerManager* nsBaseWidget::CreateBasicLayerManager()
    1417             : {
    1418           0 :   return new BasicLayerManager(this);
    1419             : }
    1420             : 
    1421          62 : CompositorBridgeChild* nsBaseWidget::GetRemoteRenderer()
    1422             : {
    1423          62 :   return mCompositorBridgeChild;
    1424             : }
    1425             : 
    1426             : already_AddRefed<gfx::DrawTarget>
    1427           0 : nsBaseWidget::StartRemoteDrawing()
    1428             : {
    1429           0 :   return nullptr;
    1430             : }
    1431             : 
    1432             : uint32_t
    1433           0 : nsBaseWidget::GetGLFrameBufferFormat()
    1434             : {
    1435           0 :   return LOCAL_GL_RGBA;
    1436             : }
    1437             : 
    1438             : //-------------------------------------------------------------------------
    1439             : //
    1440             : // Destroy the window
    1441             : //
    1442             : //-------------------------------------------------------------------------
    1443           0 : void nsBaseWidget::OnDestroy()
    1444             : {
    1445           0 :   if (mTextEventDispatcher) {
    1446           0 :     mTextEventDispatcher->OnDestroyWidget();
    1447             :     // Don't release it until this widget actually released because after this
    1448             :     // is called, TextEventDispatcher() may create it again.
    1449             :   }
    1450             : 
    1451             :   // If this widget is being destroyed, let the APZ code know to drop references
    1452             :   // to this widget. Callers of this function all should be holding a deathgrip
    1453             :   // on this widget already.
    1454           0 :   ReleaseContentController();
    1455           0 : }
    1456             : 
    1457             : void
    1458           0 : nsBaseWidget::MoveClient(double aX, double aY)
    1459             : {
    1460           0 :   LayoutDeviceIntPoint clientOffset(GetClientOffset());
    1461             : 
    1462             :   // GetClientOffset returns device pixels; scale back to desktop pixels
    1463             :   // if that's what this widget uses for the Move/Resize APIs
    1464           0 :   if (BoundsUseDesktopPixels()) {
    1465           0 :     DesktopPoint desktopOffset = clientOffset / GetDesktopToDeviceScale();
    1466           0 :     Move(aX - desktopOffset.x, aY - desktopOffset.y);
    1467             :   } else {
    1468           0 :     Move(aX - clientOffset.x, aY - clientOffset.y);
    1469             :   }
    1470           0 : }
    1471             : 
    1472             : void
    1473           0 : nsBaseWidget::ResizeClient(double aWidth, double aHeight, bool aRepaint)
    1474             : {
    1475           0 :   NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
    1476           0 :   NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
    1477             : 
    1478           0 :   LayoutDeviceIntRect clientBounds = GetClientBounds();
    1479             : 
    1480             :   // GetClientBounds and mBounds are device pixels; scale back to desktop pixels
    1481             :   // if that's what this widget uses for the Move/Resize APIs
    1482           0 :   if (BoundsUseDesktopPixels()) {
    1483             :     DesktopSize desktopDelta =
    1484           0 :       (LayoutDeviceIntSize(mBounds.width, mBounds.height) -
    1485           0 :        clientBounds.Size()) / GetDesktopToDeviceScale();
    1486           0 :     Resize(aWidth + desktopDelta.width, aHeight + desktopDelta.height,
    1487           0 :            aRepaint);
    1488             :   } else {
    1489           0 :     Resize(mBounds.width + (aWidth - clientBounds.width),
    1490           0 :            mBounds.height + (aHeight - clientBounds.height), aRepaint);
    1491             :   }
    1492           0 : }
    1493             : 
    1494             : void
    1495           0 : nsBaseWidget::ResizeClient(double aX,
    1496             :                            double aY,
    1497             :                            double aWidth,
    1498             :                            double aHeight,
    1499             :                            bool aRepaint)
    1500             : {
    1501           0 :   NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
    1502           0 :   NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
    1503             : 
    1504           0 :   LayoutDeviceIntRect clientBounds = GetClientBounds();
    1505           0 :   LayoutDeviceIntPoint clientOffset = GetClientOffset();
    1506             : 
    1507           0 :   if (BoundsUseDesktopPixels()) {
    1508           0 :     DesktopToLayoutDeviceScale scale = GetDesktopToDeviceScale();
    1509           0 :     DesktopPoint desktopOffset = clientOffset / scale;
    1510             :     DesktopSize desktopDelta =
    1511           0 :       (LayoutDeviceIntSize(mBounds.width, mBounds.height) -
    1512           0 :        clientBounds.Size()) / scale;
    1513           0 :     Resize(aX - desktopOffset.x, aY - desktopOffset.y,
    1514           0 :            aWidth + desktopDelta.width, aHeight + desktopDelta.height,
    1515           0 :            aRepaint);
    1516             :   } else {
    1517           0 :     Resize(aX - clientOffset.x, aY - clientOffset.y,
    1518           0 :            aWidth + mBounds.width - clientBounds.width,
    1519           0 :            aHeight + mBounds.height - clientBounds.height,
    1520           0 :            aRepaint);
    1521             :   }
    1522           0 : }
    1523             : 
    1524             : //-------------------------------------------------------------------------
    1525             : //
    1526             : // Bounds
    1527             : //
    1528             : //-------------------------------------------------------------------------
    1529             : 
    1530             : /**
    1531             : * If the implementation of nsWindow supports borders this method MUST be overridden
    1532             : *
    1533             : **/
    1534             : LayoutDeviceIntRect
    1535           0 : nsBaseWidget::GetClientBounds()
    1536             : {
    1537           0 :   return GetBounds();
    1538             : }
    1539             : 
    1540             : /**
    1541             : * If the implementation of nsWindow supports borders this method MUST be overridden
    1542             : *
    1543             : **/
    1544             : LayoutDeviceIntRect
    1545         100 : nsBaseWidget::GetBounds()
    1546             : {
    1547         100 :   return mBounds;
    1548             : }
    1549             : 
    1550             : /**
    1551             : * If the implementation of nsWindow uses a local coordinate system within the window,
    1552             : * this method must be overridden
    1553             : *
    1554             : **/
    1555             : LayoutDeviceIntRect
    1556           0 : nsBaseWidget::GetScreenBounds()
    1557             : {
    1558           0 :   return GetBounds();
    1559             : }
    1560             : 
    1561             : nsresult
    1562           3 : nsBaseWidget::GetRestoredBounds(LayoutDeviceIntRect& aRect)
    1563             : {
    1564           3 :   if (SizeMode() != nsSizeMode_Normal) {
    1565           2 :     return NS_ERROR_FAILURE;
    1566             :   }
    1567           1 :   aRect = GetScreenBounds();
    1568           1 :   return NS_OK;
    1569             : }
    1570             : 
    1571             : LayoutDeviceIntPoint
    1572           0 : nsBaseWidget::GetClientOffset()
    1573             : {
    1574           0 :   return LayoutDeviceIntPoint(0, 0);
    1575             : }
    1576             : 
    1577             : nsresult
    1578           0 : nsBaseWidget::SetNonClientMargins(LayoutDeviceIntMargin &margins)
    1579             : {
    1580           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1581             : }
    1582             : 
    1583           0 : uint32_t nsBaseWidget::GetMaxTouchPoints() const
    1584             : {
    1585           0 :   return 0;
    1586             : }
    1587             : 
    1588             : bool
    1589           0 : nsBaseWidget::HasPendingInputEvent()
    1590             : {
    1591           0 :   return false;
    1592             : }
    1593             : 
    1594             : bool
    1595           0 : nsBaseWidget::ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect)
    1596             : {
    1597           0 :   return false;
    1598             : }
    1599             : 
    1600             : /**
    1601             :  * Modifies aFile to point at an icon file with the given name and suffix.  The
    1602             :  * suffix may correspond to a file extension with leading '.' if appropriate.
    1603             :  * Returns true if the icon file exists and can be read.
    1604             :  */
    1605             : static bool
    1606          31 : ResolveIconNameHelper(nsIFile *aFile,
    1607             :                       const nsAString &aIconName,
    1608             :                       const nsAString &aIconSuffix)
    1609             : {
    1610          31 :   aFile->Append(NS_LITERAL_STRING("icons"));
    1611          31 :   aFile->Append(NS_LITERAL_STRING("default"));
    1612          31 :   aFile->Append(aIconName + aIconSuffix);
    1613             : 
    1614             :   bool readable;
    1615          31 :   return NS_SUCCEEDED(aFile->IsReadable(&readable)) && readable;
    1616             : }
    1617             : 
    1618             : /**
    1619             :  * Resolve the given icon name into a local file object.  This method is
    1620             :  * intended to be called by subclasses of nsBaseWidget.  aIconSuffix is a
    1621             :  * platform specific icon file suffix (e.g., ".ico" under Win32).
    1622             :  *
    1623             :  * If no file is found matching the given parameters, then null is returned.
    1624             :  */
    1625             : void
    1626          10 : nsBaseWidget::ResolveIconName(const nsAString &aIconName,
    1627             :                               const nsAString &aIconSuffix,
    1628             :                               nsIFile **aResult)
    1629             : {
    1630          10 :   *aResult = nullptr;
    1631             : 
    1632          17 :   nsCOMPtr<nsIProperties> dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
    1633          10 :   if (!dirSvc)
    1634           0 :     return;
    1635             : 
    1636             :   // first check auxilary chrome directories
    1637             : 
    1638          17 :   nsCOMPtr<nsISimpleEnumerator> dirs;
    1639          20 :   dirSvc->Get(NS_APP_CHROME_DIR_LIST, NS_GET_IID(nsISimpleEnumerator),
    1640          20 :               getter_AddRefs(dirs));
    1641          10 :   if (dirs) {
    1642             :     bool hasMore;
    1643          52 :     while (NS_SUCCEEDED(dirs->HasMoreElements(&hasMore)) && hasMore) {
    1644          45 :       nsCOMPtr<nsISupports> element;
    1645          24 :       dirs->GetNext(getter_AddRefs(element));
    1646          24 :       if (!element)
    1647           0 :         continue;
    1648          45 :       nsCOMPtr<nsIFile> file = do_QueryInterface(element);
    1649          24 :       if (!file)
    1650           0 :         continue;
    1651          24 :       if (ResolveIconNameHelper(file, aIconName, aIconSuffix)) {
    1652           3 :         NS_ADDREF(*aResult = file);
    1653           3 :         return;
    1654             :       }
    1655             :     }
    1656             :   }
    1657             : 
    1658             :   // then check the main app chrome directory
    1659             : 
    1660          14 :   nsCOMPtr<nsIFile> file;
    1661          14 :   dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
    1662          14 :               getter_AddRefs(file));
    1663           7 :   if (file && ResolveIconNameHelper(file, aIconName, aIconSuffix))
    1664           0 :     NS_ADDREF(*aResult = file);
    1665             : }
    1666             : 
    1667           0 : void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints)
    1668             : {
    1669           0 :   mSizeConstraints = aConstraints;
    1670             :   // We can't ensure that the size is honored at this point because we're
    1671             :   // probably in the middle of a reflow.
    1672           0 : }
    1673             : 
    1674           3 : const widget::SizeConstraints nsBaseWidget::GetSizeConstraints()
    1675             : {
    1676           3 :   return mSizeConstraints;
    1677             : }
    1678             : 
    1679             : // static
    1680             : nsIRollupListener*
    1681           1 : nsBaseWidget::GetActiveRollupListener()
    1682             : {
    1683             :   // If set, then this is likely an <html:select> dropdown.
    1684           1 :   if (gRollupListener)
    1685           0 :     return gRollupListener;
    1686             : 
    1687           1 :   return nsXULPopupManager::GetInstance();
    1688             : }
    1689             : 
    1690             : void
    1691           0 : nsBaseWidget::NotifyWindowDestroyed()
    1692             : {
    1693           0 :   if (!mWidgetListener)
    1694           0 :     return;
    1695             : 
    1696           0 :   nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
    1697           0 :   nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
    1698           0 :   if (xulWindow) {
    1699           0 :     xulWindow->Destroy();
    1700             :   }
    1701             : }
    1702             : 
    1703             : void
    1704           0 : nsBaseWidget::NotifySizeMoveDone()
    1705             : {
    1706           0 :   if (!mWidgetListener || mWidgetListener->GetXULWindow())
    1707           0 :     return;
    1708             : 
    1709           0 :   nsIPresShell* presShell = mWidgetListener->GetPresShell();
    1710           0 :   if (presShell) {
    1711           0 :     presShell->WindowSizeMoveDone();
    1712             :   }
    1713             : }
    1714             : 
    1715             : void
    1716           7 : nsBaseWidget::NotifyWindowMoved(int32_t aX, int32_t aY)
    1717             : {
    1718           7 :   if (mWidgetListener) {
    1719           5 :     mWidgetListener->WindowMoved(this, aX, aY);
    1720             :   }
    1721             : 
    1722           7 :   if (mIMEHasFocus && IMENotificationRequestsRef().WantPositionChanged()) {
    1723           0 :     NotifyIME(IMENotification(IMEMessage::NOTIFY_IME_OF_POSITION_CHANGE));
    1724             :   }
    1725           7 : }
    1726             : 
    1727             : void
    1728           0 : nsBaseWidget::NotifySysColorChanged()
    1729             : {
    1730           0 :   if (!mWidgetListener || mWidgetListener->GetXULWindow())
    1731           0 :     return;
    1732             : 
    1733           0 :   nsIPresShell* presShell = mWidgetListener->GetPresShell();
    1734           0 :   if (presShell) {
    1735           0 :     presShell->SysColorChanged();
    1736             :   }
    1737             : }
    1738             : 
    1739             : void
    1740           0 : nsBaseWidget::NotifyThemeChanged()
    1741             : {
    1742           0 :   if (!mWidgetListener || mWidgetListener->GetXULWindow())
    1743           0 :     return;
    1744             : 
    1745           0 :   nsIPresShell* presShell = mWidgetListener->GetPresShell();
    1746           0 :   if (presShell) {
    1747           0 :     presShell->ThemeChanged();
    1748             :   }
    1749             : }
    1750             : 
    1751             : void
    1752           0 : nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
    1753             :                                    UIStateChangeType aShowFocusRings)
    1754             : {
    1755           0 :   if (nsIDocument* doc = GetDocument()) {
    1756           0 :     nsPIDOMWindowOuter* win = doc->GetWindow();
    1757           0 :     if (win) {
    1758           0 :       win->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
    1759             :     }
    1760             :   }
    1761           0 : }
    1762             : 
    1763             : nsresult
    1764           0 : nsBaseWidget::NotifyIME(const IMENotification& aIMENotification)
    1765             : {
    1766           0 :   switch (aIMENotification.mMessage) {
    1767             :     case REQUEST_TO_COMMIT_COMPOSITION:
    1768             :     case REQUEST_TO_CANCEL_COMPOSITION:
    1769             :       // Currently, if native IME handler doesn't use TextEventDispatcher,
    1770             :       // the request may be notified to mTextEventDispatcher or native IME
    1771             :       // directly.  Therefore, if mTextEventDispatcher has a composition,
    1772             :       // the request should be handled by the mTextEventDispatcher.
    1773           0 :       if (mTextEventDispatcher && mTextEventDispatcher->IsComposing()) {
    1774           0 :         return mTextEventDispatcher->NotifyIME(aIMENotification);
    1775             :       }
    1776             :       // Otherwise, it should be handled by native IME.
    1777           0 :       return NotifyIMEInternal(aIMENotification);
    1778             :     default: {
    1779           0 :       if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
    1780           0 :         mIMEHasFocus = true;
    1781             :       }
    1782           0 :       EnsureTextEventDispatcher();
    1783             :       // If the platform specific widget uses TextEventDispatcher for handling
    1784             :       // native IME and keyboard events, IME event handler should be notified
    1785             :       // of the notification via TextEventDispatcher.  Otherwise, on the other
    1786             :       // platforms which have not used TextEventDispatcher yet, IME event
    1787             :       // handler should be notified by the old path (NotifyIMEInternal).
    1788           0 :       nsresult rv = mTextEventDispatcher->NotifyIME(aIMENotification);
    1789           0 :       nsresult rv2 = NotifyIMEInternal(aIMENotification);
    1790           0 :       if (aIMENotification.mMessage == NOTIFY_IME_OF_BLUR) {
    1791           0 :         mIMEHasFocus = false;
    1792             :       }
    1793           0 :       return rv2 == NS_ERROR_NOT_IMPLEMENTED ? rv : rv2;
    1794             :     }
    1795             :   }
    1796             : }
    1797             : 
    1798             : void
    1799           0 : nsBaseWidget::EnsureTextEventDispatcher()
    1800             : {
    1801           0 :   if (mTextEventDispatcher) {
    1802           0 :     return;
    1803             :   }
    1804           0 :   mTextEventDispatcher = new TextEventDispatcher(this);
    1805             : }
    1806             : 
    1807             : nsIWidget::TextEventDispatcher*
    1808           0 : nsBaseWidget::GetTextEventDispatcher()
    1809             : {
    1810           0 :   EnsureTextEventDispatcher();
    1811           0 :   return mTextEventDispatcher;
    1812             : }
    1813             : 
    1814             : void*
    1815           0 : nsBaseWidget::GetPseudoIMEContext()
    1816             : {
    1817           0 :   TextEventDispatcher* dispatcher = GetTextEventDispatcher();
    1818           0 :   if (!dispatcher) {
    1819           0 :     return nullptr;
    1820             :   }
    1821           0 :   return dispatcher->GetPseudoIMEContext();
    1822             : }
    1823             : 
    1824             : TextEventDispatcherListener*
    1825           0 : nsBaseWidget::GetNativeTextEventDispatcherListener()
    1826             : {
    1827             :   // TODO: If all platforms supported use of TextEventDispatcher for handling
    1828             :   //       native IME and keyboard events, this method should be removed since
    1829             :   //       in such case, this is overridden by all the subclasses.
    1830           0 :   return nullptr;
    1831             : }
    1832             : 
    1833             : void
    1834           0 : nsBaseWidget::ZoomToRect(const uint32_t& aPresShellId,
    1835             :                          const FrameMetrics::ViewID& aViewId,
    1836             :                          const CSSRect& aRect,
    1837             :                          const uint32_t& aFlags)
    1838             : {
    1839           0 :   if (!mCompositorSession || !mAPZC) {
    1840           0 :     return;
    1841             :   }
    1842           0 :   uint64_t layerId = mCompositorSession->RootLayerTreeId();
    1843           0 :   mAPZC->ZoomToRect(ScrollableLayerGuid(layerId, aPresShellId, aViewId), aRect, aFlags);
    1844             : }
    1845             : 
    1846             : #ifdef ACCESSIBILITY
    1847             : 
    1848             : #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
    1849             : // defined in nsAppRunner.cpp
    1850             : extern const char* kAccessibilityLastRunDatePref;
    1851             : 
    1852             : static inline uint32_t
    1853           0 : PRTimeToSeconds(PRTime t_usec)
    1854             : {
    1855           0 :   PRTime usec_per_sec = PR_USEC_PER_SEC;
    1856           0 :   return uint32_t(t_usec /= usec_per_sec);
    1857             : }
    1858             : #endif
    1859             : 
    1860             : a11y::Accessible*
    1861           0 : nsBaseWidget::GetRootAccessible()
    1862             : {
    1863           0 :   NS_ENSURE_TRUE(mWidgetListener, nullptr);
    1864             : 
    1865           0 :   nsIPresShell* presShell = mWidgetListener->GetPresShell();
    1866           0 :   NS_ENSURE_TRUE(presShell, nullptr);
    1867             : 
    1868             :   // If container is null then the presshell is not active. This often happens
    1869             :   // when a preshell is being held onto for fastback.
    1870           0 :   nsPresContext* presContext = presShell->GetPresContext();
    1871           0 :   NS_ENSURE_TRUE(presContext->GetContainerWeak(), nullptr);
    1872             : 
    1873             :   // Accessible creation might be not safe so use IsSafeToRunScript to
    1874             :   // make sure it's not created at unsafe times.
    1875           0 :   nsAccessibilityService* accService = GetOrCreateAccService();
    1876           0 :   if (accService) {
    1877             : #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
    1878           0 :     if (!mAccessibilityInUseFlag) {
    1879           0 :       mAccessibilityInUseFlag = true;
    1880           0 :       uint32_t now = PRTimeToSeconds(PR_Now());
    1881           0 :       Preferences::SetInt(kAccessibilityLastRunDatePref, now);
    1882             :     }
    1883             : #endif
    1884           0 :     return accService->GetRootDocumentAccessible(presShell, nsContentUtils::IsSafeToRunScript());
    1885             :   }
    1886             : 
    1887           0 :   return nullptr;
    1888             : }
    1889             : 
    1890             : #endif // ACCESSIBILITY
    1891             : 
    1892             : void
    1893           0 : nsBaseWidget::StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics)
    1894             : {
    1895           0 :   if (!AsyncPanZoomEnabled()) {
    1896           0 :     return;
    1897             :   }
    1898             : 
    1899           0 :   MOZ_ASSERT(XRE_IsParentProcess() && mCompositorSession);
    1900             : 
    1901           0 :   uint64_t layersId = mCompositorSession->RootLayerTreeId();
    1902           0 :   ScrollableLayerGuid guid(layersId, aDragMetrics.mPresShellId, aDragMetrics.mViewId);
    1903             : 
    1904           0 :   APZThreadUtils::RunOnControllerThread(
    1905           0 :     NewRunnableMethod<ScrollableLayerGuid, AsyncDragMetrics>(
    1906             :       "layers::IAPZCTreeManager::StartScrollbarDrag",
    1907             :       mAPZC,
    1908             :       &IAPZCTreeManager::StartScrollbarDrag,
    1909             :       guid,
    1910           0 :       aDragMetrics));
    1911             : }
    1912             : 
    1913             : already_AddRefed<nsIScreen>
    1914           0 : nsBaseWidget::GetWidgetScreen()
    1915             : {
    1916           0 :   nsCOMPtr<nsIScreenManager> screenManager;
    1917           0 :   screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
    1918           0 :   if (!screenManager) {
    1919           0 :     return nullptr;
    1920             :   }
    1921             : 
    1922           0 :   LayoutDeviceIntRect bounds = GetScreenBounds();
    1923           0 :   DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale());
    1924           0 :   nsCOMPtr<nsIScreen> screen;
    1925           0 :   screenManager->ScreenForRect(deskBounds.x, deskBounds.y,
    1926             :                                deskBounds.width, deskBounds.height,
    1927           0 :                                getter_AddRefs(screen));
    1928           0 :   return screen.forget();
    1929             : }
    1930             : 
    1931             : nsresult
    1932           0 : nsIWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint, bool aLongTap,
    1933             :                                     nsIObserver* aObserver)
    1934             : {
    1935           0 :   AutoObserverNotifier notifier(aObserver, "touchtap");
    1936             : 
    1937           0 :   if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
    1938           0 :     sPointerIdCounter = 0;
    1939             :   }
    1940           0 :   int pointerId = sPointerIdCounter;
    1941           0 :   sPointerIdCounter++;
    1942           0 :   nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_CONTACT,
    1943           0 :                                            aPoint, 1.0, 90, nullptr);
    1944           0 :   if (NS_FAILED(rv)) {
    1945           0 :     return rv;
    1946             :   }
    1947             : 
    1948           0 :   if (!aLongTap) {
    1949           0 :     return SynthesizeNativeTouchPoint(pointerId, TOUCH_REMOVE,
    1950           0 :                                       aPoint, 0, 0, nullptr);
    1951             :   }
    1952             : 
    1953             :   // initiate a long tap
    1954             :   int elapse = Preferences::GetInt("ui.click_hold_context_menus.delay",
    1955           0 :                                    TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC);
    1956           0 :   if (!mLongTapTimer) {
    1957           0 :     mLongTapTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
    1958           0 :     if (NS_FAILED(rv)) {
    1959           0 :       SynthesizeNativeTouchPoint(pointerId, TOUCH_CANCEL,
    1960           0 :                                  aPoint, 0, 0, nullptr);
    1961           0 :       return NS_ERROR_UNEXPECTED;
    1962             :     }
    1963             :     // Windows requires recuring events, so we set this to a smaller window
    1964             :     // than the pref value.
    1965           0 :     int timeout = elapse;
    1966           0 :     if (timeout > TOUCH_INJECT_PUMP_TIMER_MSEC) {
    1967           0 :       timeout = TOUCH_INJECT_PUMP_TIMER_MSEC;
    1968             :     }
    1969           0 :     mLongTapTimer->InitWithNamedFuncCallback(
    1970             :       OnLongTapTimerCallback,
    1971             :       this,
    1972             :       timeout,
    1973             :       nsITimer::TYPE_REPEATING_SLACK,
    1974           0 :       "nsIWidget::SynthesizeNativeTouchTap");
    1975             :   }
    1976             : 
    1977             :   // If we already have a long tap pending, cancel it. We only allow one long
    1978             :   // tap to be active at a time.
    1979           0 :   if (mLongTapTouchPoint) {
    1980           0 :     SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
    1981           0 :                                mLongTapTouchPoint->mPosition, 0, 0, nullptr);
    1982             :   }
    1983             : 
    1984             :   mLongTapTouchPoint =
    1985           0 :     MakeUnique<LongTapInfo>(pointerId, aPoint,
    1986           0 :                             TimeDuration::FromMilliseconds(elapse),
    1987           0 :                             aObserver);
    1988           0 :   notifier.SkipNotification();  // we'll do it in the long-tap callback
    1989           0 :   return NS_OK;
    1990             : }
    1991             : 
    1992             : // static
    1993             : void
    1994           0 : nsIWidget::OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure)
    1995             : {
    1996           0 :   auto *self = static_cast<nsIWidget *>(aClosure);
    1997             : 
    1998           0 :   if ((self->mLongTapTouchPoint->mStamp + self->mLongTapTouchPoint->mDuration) >
    1999           0 :       TimeStamp::Now()) {
    2000             : #ifdef XP_WIN
    2001             :     // Windows needs us to keep pumping feedback to the digitizer, so update
    2002             :     // the pointer id with the same position.
    2003             :     self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
    2004             :                                      TOUCH_CONTACT,
    2005             :                                      self->mLongTapTouchPoint->mPosition,
    2006             :                                      1.0, 90, nullptr);
    2007             : #endif
    2008           0 :     return;
    2009             :   }
    2010             : 
    2011           0 :   AutoObserverNotifier notifier(self->mLongTapTouchPoint->mObserver, "touchtap");
    2012             : 
    2013             :   // finished, remove the touch point
    2014           0 :   self->mLongTapTimer->Cancel();
    2015           0 :   self->mLongTapTimer = nullptr;
    2016           0 :   self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
    2017             :                                    TOUCH_REMOVE,
    2018           0 :                                    self->mLongTapTouchPoint->mPosition,
    2019           0 :                                    0, 0, nullptr);
    2020           0 :   self->mLongTapTouchPoint = nullptr;
    2021             : }
    2022             : 
    2023             : nsresult
    2024           3 : nsIWidget::ClearNativeTouchSequence(nsIObserver* aObserver)
    2025             : {
    2026           6 :   AutoObserverNotifier notifier(aObserver, "cleartouch");
    2027             : 
    2028           3 :   if (!mLongTapTimer) {
    2029           3 :     return NS_OK;
    2030             :   }
    2031           0 :   mLongTapTimer->Cancel();
    2032           0 :   mLongTapTimer = nullptr;
    2033           0 :   SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
    2034           0 :                              mLongTapTouchPoint->mPosition, 0, 0, nullptr);
    2035           0 :   mLongTapTouchPoint = nullptr;
    2036           0 :   return NS_OK;
    2037             : }
    2038             : 
    2039             : MultiTouchInput
    2040           0 : nsBaseWidget::UpdateSynthesizedTouchState(MultiTouchInput* aState,
    2041             :                                           uint32_t aTime,
    2042             :                                           mozilla::TimeStamp aTimeStamp,
    2043             :                                           uint32_t aPointerId,
    2044             :                                           TouchPointerState aPointerState,
    2045             :                                           LayoutDeviceIntPoint aPoint,
    2046             :                                           double aPointerPressure,
    2047             :                                           uint32_t aPointerOrientation)
    2048             : {
    2049             :   ScreenIntPoint pointerScreenPoint = ViewAs<ScreenPixel>(aPoint,
    2050           0 :       PixelCastJustification::LayoutDeviceIsScreenForBounds);
    2051             : 
    2052             :   // We can't dispatch *aState directly because (a) dispatching
    2053             :   // it might inadvertently modify it and (b) in the case of touchend or
    2054             :   // touchcancel events aState will hold the touches that are
    2055             :   // still down whereas the input dispatched needs to hold the removed
    2056             :   // touch(es). We use |inputToDispatch| for this purpose.
    2057           0 :   MultiTouchInput inputToDispatch;
    2058           0 :   inputToDispatch.mInputType = MULTITOUCH_INPUT;
    2059           0 :   inputToDispatch.mTime = aTime;
    2060           0 :   inputToDispatch.mTimeStamp = aTimeStamp;
    2061             : 
    2062           0 :   int32_t index = aState->IndexOfTouch((int32_t)aPointerId);
    2063           0 :   if (aPointerState == TOUCH_CONTACT) {
    2064           0 :     if (index >= 0) {
    2065             :       // found an existing touch point, update it
    2066           0 :       SingleTouchData& point = aState->mTouches[index];
    2067           0 :       point.mScreenPoint = pointerScreenPoint;
    2068           0 :       point.mRotationAngle = (float)aPointerOrientation;
    2069           0 :       point.mForce = (float)aPointerPressure;
    2070           0 :       inputToDispatch.mType = MultiTouchInput::MULTITOUCH_MOVE;
    2071             :     } else {
    2072             :       // new touch point, add it
    2073           0 :       aState->mTouches.AppendElement(SingleTouchData(
    2074             :           (int32_t)aPointerId,
    2075             :           pointerScreenPoint,
    2076             :           ScreenSize(0, 0),
    2077             :           (float)aPointerOrientation,
    2078           0 :           (float)aPointerPressure));
    2079           0 :       inputToDispatch.mType = MultiTouchInput::MULTITOUCH_START;
    2080             :     }
    2081           0 :     inputToDispatch.mTouches = aState->mTouches;
    2082             :   } else {
    2083           0 :     MOZ_ASSERT(aPointerState == TOUCH_REMOVE || aPointerState == TOUCH_CANCEL);
    2084             :     // a touch point is being lifted, so remove it from the stored list
    2085           0 :     if (index >= 0) {
    2086           0 :       aState->mTouches.RemoveElementAt(index);
    2087             :     }
    2088           0 :     inputToDispatch.mType = (aPointerState == TOUCH_REMOVE
    2089           0 :         ? MultiTouchInput::MULTITOUCH_END
    2090             :         : MultiTouchInput::MULTITOUCH_CANCEL);
    2091           0 :     inputToDispatch.mTouches.AppendElement(SingleTouchData(
    2092             :         (int32_t)aPointerId,
    2093             :         pointerScreenPoint,
    2094             :         ScreenSize(0, 0),
    2095             :         (float)aPointerOrientation,
    2096           0 :         (float)aPointerPressure));
    2097             :   }
    2098             : 
    2099           0 :   return inputToDispatch;
    2100             : }
    2101             : 
    2102             : void
    2103           0 : nsBaseWidget::NotifyLiveResizeStarted()
    2104             : {
    2105             :   // If we have mLiveResizeListeners already non-empty, we should notify those
    2106             :   // listeners that the resize stopped before starting anew. In theory this
    2107             :   // should never happen because we shouldn't get nested live resize actions.
    2108           0 :   NotifyLiveResizeStopped();
    2109           0 :   MOZ_ASSERT(mLiveResizeListeners.IsEmpty());
    2110             : 
    2111             :   // If we can get the active tab parent for the current widget, suppress
    2112             :   // the displayport on it during the live resize.
    2113           0 :   if (!mWidgetListener) {
    2114           0 :     return;
    2115             :   }
    2116           0 :   nsCOMPtr<nsIXULWindow> xulWindow = mWidgetListener->GetXULWindow();
    2117           0 :   if (!xulWindow) {
    2118           0 :     return;
    2119             :   }
    2120           0 :   mLiveResizeListeners = xulWindow->GetLiveResizeListeners();
    2121           0 :   for (uint32_t i = 0; i < mLiveResizeListeners.Length(); i++) {
    2122           0 :     mLiveResizeListeners[i]->LiveResizeStarted();
    2123             :   }
    2124             : }
    2125             : 
    2126             : void
    2127           0 : nsBaseWidget::NotifyLiveResizeStopped()
    2128             : {
    2129           0 :   if (!mLiveResizeListeners.IsEmpty()) {
    2130           0 :     for (uint32_t i = 0; i < mLiveResizeListeners.Length(); i++) {
    2131           0 :       mLiveResizeListeners[i]->LiveResizeStopped();
    2132             :     }
    2133           0 :     mLiveResizeListeners.Clear();
    2134             :   }
    2135           0 : }
    2136             : 
    2137             : void
    2138           0 : nsBaseWidget::RegisterPluginWindowForRemoteUpdates()
    2139             : {
    2140             : #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
    2141             :   NS_NOTREACHED("nsBaseWidget::RegisterPluginWindowForRemoteUpdates not implemented!");
    2142             :   return;
    2143             : #else
    2144           0 :   MOZ_ASSERT(NS_IsMainThread());
    2145           0 :   void* id = GetNativeData(NS_NATIVE_PLUGIN_ID);
    2146           0 :   if (!id) {
    2147           0 :     NS_WARNING("This is not a valid native widget!");
    2148           0 :     return;
    2149             :   }
    2150           0 :   MOZ_ASSERT(sPluginWidgetList);
    2151           0 :   sPluginWidgetList->Put(id, this);
    2152             : #endif
    2153             : }
    2154             : 
    2155             : void
    2156           0 : nsBaseWidget::UnregisterPluginWindowForRemoteUpdates()
    2157             : {
    2158             : #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
    2159             :   NS_NOTREACHED("nsBaseWidget::UnregisterPluginWindowForRemoteUpdates not implemented!");
    2160             :   return;
    2161             : #else
    2162           0 :   MOZ_ASSERT(NS_IsMainThread());
    2163           0 :   void* id = GetNativeData(NS_NATIVE_PLUGIN_ID);
    2164           0 :   if (!id) {
    2165           0 :     NS_WARNING("This is not a valid native widget!");
    2166           0 :     return;
    2167             :   }
    2168           0 :   MOZ_ASSERT(sPluginWidgetList);
    2169           0 :   sPluginWidgetList->Remove(id);
    2170             : #endif
    2171             : }
    2172             : 
    2173             : // static
    2174             : nsIWidget*
    2175           0 : nsIWidget::LookupRegisteredPluginWindow(uintptr_t aWindowID)
    2176             : {
    2177             : #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
    2178             :   NS_NOTREACHED("nsBaseWidget::LookupRegisteredPluginWindow not implemented!");
    2179             :   return nullptr;
    2180             : #else
    2181           0 :   MOZ_ASSERT(NS_IsMainThread());
    2182           0 :   MOZ_ASSERT(sPluginWidgetList);
    2183           0 :   return sPluginWidgetList->GetWeak((void*)aWindowID);
    2184             : #endif
    2185             : }
    2186             : 
    2187             : // static
    2188             : void
    2189           0 : nsIWidget::UpdateRegisteredPluginWindowVisibility(uintptr_t aOwnerWidget,
    2190             :                                                   nsTArray<uintptr_t>& aPluginIds)
    2191             : {
    2192             : #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
    2193             :   NS_NOTREACHED("nsBaseWidget::UpdateRegisteredPluginWindowVisibility not implemented!");
    2194             :   return;
    2195             : #else
    2196           0 :   MOZ_ASSERT(NS_IsMainThread());
    2197           0 :   MOZ_ASSERT(sPluginWidgetList);
    2198             : 
    2199             :   // Our visible list is associated with a compositor which is associated with
    2200             :   // a specific top level window. We use the parent widget during iteration
    2201             :   // to skip the plugin widgets owned by other top level windows.
    2202           0 :   for (auto iter = sPluginWidgetList->Iter(); !iter.Done(); iter.Next()) {
    2203           0 :     const void* windowId = iter.Key();
    2204           0 :     nsIWidget* widget = iter.UserData();
    2205             : 
    2206           0 :     MOZ_ASSERT(windowId);
    2207           0 :     MOZ_ASSERT(widget);
    2208             : 
    2209           0 :     if (!widget->Destroyed()) {
    2210           0 :       if ((uintptr_t)widget->GetParent() == aOwnerWidget) {
    2211           0 :         widget->Show(aPluginIds.Contains((uintptr_t)windowId));
    2212             :       }
    2213             :     }
    2214             :   }
    2215             : #endif
    2216           0 : }
    2217             : 
    2218             : #if defined(XP_WIN)
    2219             : // static
    2220             : void
    2221             : nsIWidget::CaptureRegisteredPlugins(uintptr_t aOwnerWidget)
    2222             : {
    2223             :   MOZ_ASSERT(NS_IsMainThread());
    2224             :   MOZ_ASSERT(sPluginWidgetList);
    2225             : 
    2226             :   // Our visible list is associated with a compositor which is associated with
    2227             :   // a specific top level window. We use the parent widget during iteration
    2228             :   // to skip the plugin widgets owned by other top level windows.
    2229             :   for (auto iter = sPluginWidgetList->Iter(); !iter.Done(); iter.Next()) {
    2230             :     const void* windowId = iter.Key();
    2231             :     nsIWidget* widget = iter.UserData();
    2232             : 
    2233             :     MOZ_ASSERT(windowId);
    2234             :     MOZ_ASSERT(widget);
    2235             : 
    2236             :     if (!widget->Destroyed() && widget->IsVisible()) {
    2237             :       if ((uintptr_t)widget->GetParent() == aOwnerWidget) {
    2238             :         widget->UpdateScrollCapture();
    2239             :       }
    2240             :     }
    2241             :   }
    2242             : }
    2243             : 
    2244             : uint64_t
    2245             : nsBaseWidget::CreateScrollCaptureContainer()
    2246             : {
    2247             :   mScrollCaptureContainer =
    2248             :     LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
    2249             :   if (!mScrollCaptureContainer) {
    2250             :     NS_WARNING("Failed to create ImageContainer for widget image capture.");
    2251             :     return ImageContainer::sInvalidAsyncContainerId;
    2252             :   }
    2253             : 
    2254             :   return mScrollCaptureContainer->GetAsyncContainerHandle().Value();
    2255             : }
    2256             : 
    2257             : void
    2258             : nsBaseWidget::UpdateScrollCapture()
    2259             : {
    2260             :   // Don't capture if no container or no size.
    2261             :   if (!mScrollCaptureContainer || mBounds.width <= 0 || mBounds.height <= 0) {
    2262             :     return;
    2263             :   }
    2264             : 
    2265             :   // If the derived class cannot take a snapshot, for example due to clipping,
    2266             :   // then it is responsible for creating a fallback. If null is returned, this
    2267             :   // means that we want to keep the existing snapshot.
    2268             :   RefPtr<gfx::SourceSurface> snapshot = CreateScrollSnapshot();
    2269             :   if (!snapshot) {
    2270             :     return;
    2271             :   }
    2272             : 
    2273             :   ImageContainer::NonOwningImage holder(new SourceSurfaceImage(snapshot));
    2274             : 
    2275             :   AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
    2276             :   imageList.AppendElement(holder);
    2277             : 
    2278             :   mScrollCaptureContainer->SetCurrentImages(imageList);
    2279             : }
    2280             : 
    2281             : void
    2282             : nsBaseWidget::DefaultFillScrollCapture(DrawTarget* aSnapshotDrawTarget)
    2283             : {
    2284             :   gfx::IntSize dtSize = aSnapshotDrawTarget->GetSize();
    2285             :   aSnapshotDrawTarget->FillRect(
    2286             :     gfx::Rect(0, 0, dtSize.width, dtSize.height),
    2287             :     gfx::ColorPattern(gfx::Color::FromABGR(kScrollCaptureFillColor)),
    2288             :     gfx::DrawOptions(1.f, gfx::CompositionOp::OP_SOURCE));
    2289             :   aSnapshotDrawTarget->Flush();
    2290             : }
    2291             : #endif
    2292             : 
    2293             : nsIWidget::NativeIMEContext
    2294           0 : nsIWidget::GetNativeIMEContext()
    2295             : {
    2296           0 :   return NativeIMEContext(this);
    2297             : }
    2298             : 
    2299             : const IMENotificationRequests&
    2300           0 : nsIWidget::IMENotificationRequestsRef()
    2301             : {
    2302           0 :   TextEventDispatcher* dispatcher = GetTextEventDispatcher();
    2303           0 :   return dispatcher->IMENotificationRequestsRef();
    2304             : }
    2305             : 
    2306             : nsresult
    2307           0 : nsIWidget::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
    2308             :                                     nsIKeyEventInPluginCallback* aCallback)
    2309             : {
    2310           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    2311             : }
    2312             : 
    2313             : void
    2314           0 : nsIWidget::PostHandleKeyEvent(mozilla::WidgetKeyboardEvent* aEvent)
    2315             : {
    2316           0 : }
    2317             : 
    2318             : void
    2319           0 : nsIWidget::GetEditCommands(nsIWidget::NativeKeyBindingsType aType,
    2320             :                            const WidgetKeyboardEvent& aEvent,
    2321             :                            nsTArray<CommandInt>& aCommands)
    2322             : {
    2323           0 :   MOZ_ASSERT(aEvent.IsTrusted());
    2324           0 :   MOZ_ASSERT(aCommands.IsEmpty());
    2325           0 : }
    2326             : 
    2327             : namespace mozilla {
    2328             : namespace widget {
    2329             : 
    2330             : const char*
    2331           0 : ToChar(InputContext::Origin aOrigin)
    2332             : {
    2333           0 :   switch (aOrigin) {
    2334             :     case InputContext::ORIGIN_MAIN:
    2335           0 :       return "ORIGIN_MAIN";
    2336             :     case InputContext::ORIGIN_CONTENT:
    2337           0 :       return "ORIGIN_CONTENT";
    2338             :     default:
    2339           0 :       return "Unexpected value";
    2340             :   }
    2341             : }
    2342             : 
    2343             : const char*
    2344           0 : ToChar(IMEMessage aIMEMessage)
    2345             : {
    2346           0 :   switch (aIMEMessage) {
    2347             :     case NOTIFY_IME_OF_NOTHING:
    2348           0 :       return "NOTIFY_IME_OF_NOTHING";
    2349             :     case NOTIFY_IME_OF_FOCUS:
    2350           0 :       return "NOTIFY_IME_OF_FOCUS";
    2351             :     case NOTIFY_IME_OF_BLUR:
    2352           0 :       return "NOTIFY_IME_OF_BLUR";
    2353             :     case NOTIFY_IME_OF_SELECTION_CHANGE:
    2354           0 :       return "NOTIFY_IME_OF_SELECTION_CHANGE";
    2355             :     case NOTIFY_IME_OF_TEXT_CHANGE:
    2356           0 :       return "NOTIFY_IME_OF_TEXT_CHANGE";
    2357             :     case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED:
    2358           0 :       return "NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED";
    2359             :     case NOTIFY_IME_OF_POSITION_CHANGE:
    2360           0 :       return "NOTIFY_IME_OF_POSITION_CHANGE";
    2361             :     case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
    2362           0 :       return "NOTIFY_IME_OF_MOUSE_BUTTON_EVENT";
    2363             :     case REQUEST_TO_COMMIT_COMPOSITION:
    2364           0 :       return "REQUEST_TO_COMMIT_COMPOSITION";
    2365             :     case REQUEST_TO_CANCEL_COMPOSITION:
    2366           0 :       return "REQUEST_TO_CANCEL_COMPOSITION";
    2367             :     default:
    2368           0 :       return "Unexpected value";
    2369             :   }
    2370             : }
    2371             : 
    2372             : void
    2373           1 : NativeIMEContext::Init(nsIWidget* aWidget)
    2374             : {
    2375           1 :   if (!aWidget) {
    2376           1 :     mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
    2377           1 :     mOriginProcessID = static_cast<uint64_t>(-1);
    2378           1 :     return;
    2379             :   }
    2380           0 :   if (!XRE_IsContentProcess()) {
    2381           0 :     mRawNativeIMEContext = reinterpret_cast<uintptr_t>(
    2382           0 :       aWidget->GetNativeData(NS_RAW_NATIVE_IME_CONTEXT));
    2383           0 :     mOriginProcessID = 0;
    2384           0 :     return;
    2385             :   }
    2386             :   // If this is created in a child process, aWidget is an instance of
    2387             :   // PuppetWidget which doesn't support NS_RAW_NATIVE_IME_CONTEXT.
    2388             :   // Instead of that PuppetWidget::GetNativeIMEContext() returns cached
    2389             :   // native IME context of the parent process.
    2390           0 :   *this = aWidget->GetNativeIMEContext();
    2391             : }
    2392             : 
    2393             : void
    2394           0 : NativeIMEContext::InitWithRawNativeIMEContext(void* aRawNativeIMEContext)
    2395             : {
    2396           0 :   if (NS_WARN_IF(!aRawNativeIMEContext)) {
    2397           0 :     mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
    2398           0 :     mOriginProcessID = static_cast<uint64_t>(-1);
    2399           0 :     return;
    2400             :   }
    2401           0 :   mRawNativeIMEContext = reinterpret_cast<uintptr_t>(aRawNativeIMEContext);
    2402           0 :   mOriginProcessID =
    2403           0 :     XRE_IsContentProcess() ? ContentChild::GetSingleton()->GetID() : 0;
    2404             : }
    2405             : 
    2406             : void
    2407           0 : IMENotification::TextChangeDataBase::MergeWith(
    2408             :                    const IMENotification::TextChangeDataBase& aOther)
    2409             : {
    2410           0 :   MOZ_ASSERT(aOther.IsValid(),
    2411             :              "Merging data must store valid data");
    2412           0 :   MOZ_ASSERT(aOther.mStartOffset <= aOther.mRemovedEndOffset,
    2413             :              "end of removed text must be same or larger than start");
    2414           0 :   MOZ_ASSERT(aOther.mStartOffset <= aOther.mAddedEndOffset,
    2415             :              "end of added text must be same or larger than start");
    2416             : 
    2417           0 :   if (!IsValid()) {
    2418           0 :     *this = aOther;
    2419           0 :     return;
    2420             :   }
    2421             : 
    2422             :   // |mStartOffset| and |mRemovedEndOffset| represent all replaced or removed
    2423             :   // text ranges.  I.e., mStartOffset should be the smallest offset of all
    2424             :   // modified text ranges in old text.  |mRemovedEndOffset| should be the
    2425             :   // largest end offset in old text of all modified text ranges.
    2426             :   // |mAddedEndOffset| represents the end offset of all inserted text ranges.
    2427             :   // I.e., only this is an offset in new text.
    2428             :   // In other words, between mStartOffset and |mRemovedEndOffset| of the
    2429             :   // premodified text was already removed.  And some text whose length is
    2430             :   // |mAddedEndOffset - mStartOffset| is inserted to |mStartOffset|.  I.e.,
    2431             :   // this allows IME to mark dirty the modified text range with |mStartOffset|
    2432             :   // and |mRemovedEndOffset| if IME stores all text of the focused editor and
    2433             :   // to compute new text length with |mAddedEndOffset| and |mRemovedEndOffset|.
    2434             :   // Additionally, IME can retrieve only the text between |mStartOffset| and
    2435             :   // |mAddedEndOffset| for updating stored text.
    2436             : 
    2437             :   // For comparing new and old |mStartOffset|/|mRemovedEndOffset| values, they
    2438             :   // should be adjusted to be in same text. The |newData.mStartOffset| and
    2439             :   // |newData.mRemovedEndOffset| should be computed as in old text because
    2440             :   // |mStartOffset| and |mRemovedEndOffset| represent the modified text range
    2441             :   // in the old text but even if some text before the values of the newData
    2442             :   // has already been modified, the values don't include the changes.
    2443             : 
    2444             :   // For comparing new and old |mAddedEndOffset| values, they should be
    2445             :   // adjusted to be in same text.  The |oldData.mAddedEndOffset| should be
    2446             :   // computed as in the new text because |mAddedEndOffset| indicates the end
    2447             :   // offset of inserted text in the new text but |oldData.mAddedEndOffset|
    2448             :   // doesn't include any changes of the text before |newData.mAddedEndOffset|.
    2449             : 
    2450           0 :   const TextChangeDataBase& newData = aOther;
    2451           0 :   const TextChangeDataBase oldData = *this;
    2452             : 
    2453             :   // mCausedOnlyByComposition should be true only when all changes are caused
    2454             :   // by composition.
    2455           0 :   mCausedOnlyByComposition =
    2456           0 :     newData.mCausedOnlyByComposition && oldData.mCausedOnlyByComposition;
    2457             : 
    2458             :   // mIncludingChangesWithoutComposition should be true if at least one of
    2459             :   // merged changes occurred without composition.
    2460           0 :   mIncludingChangesWithoutComposition =
    2461           0 :     newData.mIncludingChangesWithoutComposition ||
    2462           0 :       oldData.mIncludingChangesWithoutComposition;
    2463             : 
    2464             :   // mIncludingChangesDuringComposition should be true when at least one of
    2465             :   // the merged non-composition changes occurred during the latest composition.
    2466           0 :   if (!newData.mCausedOnlyByComposition &&
    2467           0 :       !newData.mIncludingChangesDuringComposition) {
    2468           0 :     MOZ_ASSERT(newData.mIncludingChangesWithoutComposition);
    2469           0 :     MOZ_ASSERT(mIncludingChangesWithoutComposition);
    2470             :     // If new change is neither caused by composition nor occurred during
    2471             :     // composition, set mIncludingChangesDuringComposition to false because
    2472             :     // IME doesn't want outdated text changes as text change during current
    2473             :     // composition.
    2474           0 :     mIncludingChangesDuringComposition = false;
    2475             :   } else {
    2476             :     // Otherwise, set mIncludingChangesDuringComposition to true if either
    2477             :     // oldData or newData includes changes during composition.
    2478           0 :     mIncludingChangesDuringComposition =
    2479           0 :       newData.mIncludingChangesDuringComposition ||
    2480           0 :         oldData.mIncludingChangesDuringComposition;
    2481             :   }
    2482             : 
    2483           0 :   if (newData.mStartOffset >= oldData.mAddedEndOffset) {
    2484             :     // Case 1:
    2485             :     // If new start is after old end offset of added text, it means that text
    2486             :     // after the modified range is modified.  Like:
    2487             :     // added range of old change:             +----------+
    2488             :     // removed range of new change:                           +----------+
    2489             :     // So, the old start offset is always the smaller offset.
    2490           0 :     mStartOffset = oldData.mStartOffset;
    2491             :     // The new end offset of removed text is moved by the old change and we
    2492             :     // need to cancel the move of the old change for comparing the offsets in
    2493             :     // same text because it doesn't make sensce to compare offsets in different
    2494             :     // text.
    2495             :     uint32_t newRemovedEndOffsetInOldText =
    2496           0 :       newData.mRemovedEndOffset - oldData.Difference();
    2497           0 :     mRemovedEndOffset =
    2498           0 :       std::max(newRemovedEndOffsetInOldText, oldData.mRemovedEndOffset);
    2499             :     // The new end offset of added text is always the larger offset.
    2500           0 :     mAddedEndOffset = newData.mAddedEndOffset;
    2501           0 :     return;
    2502             :   }
    2503             : 
    2504           0 :   if (newData.mStartOffset >= oldData.mStartOffset) {
    2505             :     // If new start is in the modified range, it means that new data changes
    2506             :     // a part or all of the range.
    2507           0 :     mStartOffset = oldData.mStartOffset;
    2508           0 :     if (newData.mRemovedEndOffset >= oldData.mAddedEndOffset) {
    2509             :       // Case 2:
    2510             :       // If new end of removed text is greater than old end of added text, it
    2511             :       // means that all or a part of modified range modified again and text
    2512             :       // after the modified range is also modified.  Like:
    2513             :       // added range of old change:             +----------+
    2514             :       // removed range of new change:                   +----------+
    2515             :       // So, the new removed end offset is moved by the old change and we need
    2516             :       // to cancel the move of the old change for comparing the offsets in the
    2517             :       // same text because it doesn't make sense to compare the offsets in
    2518             :       // different text.
    2519             :       uint32_t newRemovedEndOffsetInOldText =
    2520           0 :         newData.mRemovedEndOffset - oldData.Difference();
    2521           0 :       mRemovedEndOffset =
    2522           0 :         std::max(newRemovedEndOffsetInOldText, oldData.mRemovedEndOffset);
    2523             :       // The old end of added text is replaced by new change. So, it should be
    2524             :       // same as the new start.  On the other hand, the new added end offset is
    2525             :       // always same or larger.  Therefore, the merged end offset of added
    2526             :       // text should be the new end offset of added text.
    2527           0 :       mAddedEndOffset = newData.mAddedEndOffset;
    2528           0 :       return;
    2529             :     }
    2530             : 
    2531             :     // Case 3:
    2532             :     // If new end of removed text is less than old end of added text, it means
    2533             :     // that only a part of the modified range is modified again.  Like:
    2534             :     // added range of old change:             +------------+
    2535             :     // removed range of new change:               +-----+
    2536             :     // So, the new end offset of removed text should be same as the old end
    2537             :     // offset of removed text.  Therefore, the merged end offset of removed
    2538             :     // text should be the old text change's |mRemovedEndOffset|.
    2539           0 :     mRemovedEndOffset = oldData.mRemovedEndOffset;
    2540             :     // The old end of added text is moved by new change.  So, we need to cancel
    2541             :     // the move of the new change for comparing the offsets in same text.
    2542             :     uint32_t oldAddedEndOffsetInNewText =
    2543           0 :       oldData.mAddedEndOffset + newData.Difference();
    2544           0 :     mAddedEndOffset =
    2545           0 :       std::max(newData.mAddedEndOffset, oldAddedEndOffsetInNewText);
    2546           0 :     return;
    2547             :   }
    2548             : 
    2549           0 :   if (newData.mRemovedEndOffset >= oldData.mStartOffset) {
    2550             :     // If new end of removed text is greater than old start (and new start is
    2551             :     // less than old start), it means that a part of modified range is modified
    2552             :     // again and some new text before the modified range is also modified.
    2553           0 :     MOZ_ASSERT(newData.mStartOffset < oldData.mStartOffset,
    2554             :       "new start offset should be less than old one here");
    2555           0 :     mStartOffset = newData.mStartOffset;
    2556           0 :     if (newData.mRemovedEndOffset >= oldData.mAddedEndOffset) {
    2557             :       // Case 4:
    2558             :       // If new end of removed text is greater than old end of added text, it
    2559             :       // means that all modified text and text after the modified range is
    2560             :       // modified.  Like:
    2561             :       // added range of old change:             +----------+
    2562             :       // removed range of new change:        +------------------+
    2563             :       // So, the new end of removed text is moved by the old change.  Therefore,
    2564             :       // we need to cancel the move of the old change for comparing the offsets
    2565             :       // in same text because it doesn't make sense to compare the offsets in
    2566             :       // different text.
    2567             :       uint32_t newRemovedEndOffsetInOldText =
    2568           0 :         newData.mRemovedEndOffset - oldData.Difference();
    2569           0 :       mRemovedEndOffset =
    2570           0 :         std::max(newRemovedEndOffsetInOldText, oldData.mRemovedEndOffset);
    2571             :       // The old end of added text is replaced by new change.  So, the old end
    2572             :       // offset of added text is same as new text change's start offset.  Then,
    2573             :       // new change's end offset of added text is always same or larger than
    2574             :       // it.  Therefore, merged end offset of added text is always the new end
    2575             :       // offset of added text.
    2576           0 :       mAddedEndOffset = newData.mAddedEndOffset;
    2577           0 :       return;
    2578             :     }
    2579             : 
    2580             :     // Case 5:
    2581             :     // If new end of removed text is less than old end of added text, it
    2582             :     // means that only a part of the modified range is modified again.  Like:
    2583             :     // added range of old change:             +----------+
    2584             :     // removed range of new change:      +----------+
    2585             :     // So, the new end of removed text should be same as old end of removed
    2586             :     // text for preventing end of removed text to be modified.  Therefore,
    2587             :     // merged end offset of removed text is always the old end offset of removed
    2588             :     // text.
    2589           0 :     mRemovedEndOffset = oldData.mRemovedEndOffset;
    2590             :     // The old end of added text is moved by this change.  So, we need to
    2591             :     // cancel the move of the new change for comparing the offsets in same text
    2592             :     // because it doesn't make sense to compare the offsets in different text.
    2593             :     uint32_t oldAddedEndOffsetInNewText =
    2594           0 :       oldData.mAddedEndOffset + newData.Difference();
    2595           0 :     mAddedEndOffset =
    2596           0 :       std::max(newData.mAddedEndOffset, oldAddedEndOffsetInNewText);
    2597           0 :     return;
    2598             :   }
    2599             : 
    2600             :   // Case 6:
    2601             :   // Otherwise, i.e., both new end of added text and new start are less than
    2602             :   // old start, text before the modified range is modified.  Like:
    2603             :   // added range of old change:                  +----------+
    2604             :   // removed range of new change: +----------+
    2605           0 :   MOZ_ASSERT(newData.mStartOffset < oldData.mStartOffset,
    2606             :     "new start offset should be less than old one here");
    2607           0 :   mStartOffset = newData.mStartOffset;
    2608           0 :   MOZ_ASSERT(newData.mRemovedEndOffset < oldData.mRemovedEndOffset,
    2609             :      "new removed end offset should be less than old one here");
    2610           0 :   mRemovedEndOffset = oldData.mRemovedEndOffset;
    2611             :   // The end of added text should be adjusted with the new difference.
    2612             :   uint32_t oldAddedEndOffsetInNewText =
    2613           0 :     oldData.mAddedEndOffset + newData.Difference();
    2614           0 :   mAddedEndOffset =
    2615           0 :     std::max(newData.mAddedEndOffset, oldAddedEndOffsetInNewText);
    2616             : }
    2617             : 
    2618             : #ifdef DEBUG
    2619             : 
    2620             : // Let's test the code of merging multiple text change data in debug build
    2621             : // and crash if one of them fails because this feature is very complex but
    2622             : // cannot be tested with mochitest.
    2623             : void
    2624           0 : IMENotification::TextChangeDataBase::Test()
    2625             : {
    2626             :   static bool gTestTextChangeEvent = true;
    2627           0 :   if (!gTestTextChangeEvent) {
    2628           0 :     return;
    2629             :   }
    2630           0 :   gTestTextChangeEvent = false;
    2631             : 
    2632             :   /****************************************************************************
    2633             :    * Case 1
    2634             :    ****************************************************************************/
    2635             : 
    2636             :   // Appending text
    2637           0 :   MergeWith(TextChangeData(10, 10, 20, false, false));
    2638           0 :   MergeWith(TextChangeData(20, 20, 35, false, false));
    2639           0 :   MOZ_ASSERT(mStartOffset == 10,
    2640             :     "Test 1-1-1: mStartOffset should be the first offset");
    2641           0 :   MOZ_ASSERT(mRemovedEndOffset == 10, // 20 - (20 - 10)
    2642             :     "Test 1-1-2: mRemovedEndOffset should be the first end of removed text");
    2643           0 :   MOZ_ASSERT(mAddedEndOffset == 35,
    2644             :     "Test 1-1-3: mAddedEndOffset should be the last end of added text");
    2645           0 :   Clear();
    2646             : 
    2647             :   // Removing text (longer line -> shorter line)
    2648           0 :   MergeWith(TextChangeData(10, 20, 10, false, false));
    2649           0 :   MergeWith(TextChangeData(10, 30, 10, false, false));
    2650           0 :   MOZ_ASSERT(mStartOffset == 10,
    2651             :     "Test 1-2-1: mStartOffset should be the first offset");
    2652           0 :   MOZ_ASSERT(mRemovedEndOffset == 40, // 30 + (10 - 20)
    2653             :     "Test 1-2-2: mRemovedEndOffset should be the the last end of removed text "
    2654             :     "with already removed length");
    2655           0 :   MOZ_ASSERT(mAddedEndOffset == 10,
    2656             :     "Test 1-2-3: mAddedEndOffset should be the last end of added text");
    2657           0 :   Clear();
    2658             : 
    2659             :   // Removing text (shorter line -> longer line)
    2660           0 :   MergeWith(TextChangeData(10, 20, 10, false, false));
    2661           0 :   MergeWith(TextChangeData(10, 15, 10, false, false));
    2662           0 :   MOZ_ASSERT(mStartOffset == 10,
    2663             :     "Test 1-3-1: mStartOffset should be the first offset");
    2664           0 :   MOZ_ASSERT(mRemovedEndOffset == 25, // 15 + (10 - 20)
    2665             :     "Test 1-3-2: mRemovedEndOffset should be the the last end of removed text "
    2666             :     "with already removed length");
    2667           0 :   MOZ_ASSERT(mAddedEndOffset == 10,
    2668             :     "Test 1-3-3: mAddedEndOffset should be the last end of added text");
    2669           0 :   Clear();
    2670             : 
    2671             :   // Appending text at different point (not sure if actually occurs)
    2672           0 :   MergeWith(TextChangeData(10, 10, 20, false, false));
    2673           0 :   MergeWith(TextChangeData(55, 55, 60, false, false));
    2674           0 :   MOZ_ASSERT(mStartOffset == 10,
    2675             :     "Test 1-4-1: mStartOffset should be the smallest offset");
    2676           0 :   MOZ_ASSERT(mRemovedEndOffset == 45, // 55 - (10 - 20)
    2677             :     "Test 1-4-2: mRemovedEndOffset should be the the largest end of removed "
    2678             :     "text without already added length");
    2679           0 :   MOZ_ASSERT(mAddedEndOffset == 60,
    2680             :     "Test 1-4-3: mAddedEndOffset should be the last end of added text");
    2681           0 :   Clear();
    2682             : 
    2683             :   // Removing text at different point (not sure if actually occurs)
    2684           0 :   MergeWith(TextChangeData(10, 20, 10, false, false));
    2685           0 :   MergeWith(TextChangeData(55, 68, 55, false, false));
    2686           0 :   MOZ_ASSERT(mStartOffset == 10,
    2687             :     "Test 1-5-1: mStartOffset should be the smallest offset");
    2688           0 :   MOZ_ASSERT(mRemovedEndOffset == 78, // 68 - (10 - 20)
    2689             :     "Test 1-5-2: mRemovedEndOffset should be the the largest end of removed "
    2690             :     "text with already removed length");
    2691           0 :   MOZ_ASSERT(mAddedEndOffset == 55,
    2692             :     "Test 1-5-3: mAddedEndOffset should be the largest end of added text");
    2693           0 :   Clear();
    2694             : 
    2695             :   // Replacing text and append text (becomes longer)
    2696           0 :   MergeWith(TextChangeData(30, 35, 32, false, false));
    2697           0 :   MergeWith(TextChangeData(32, 32, 40, false, false));
    2698           0 :   MOZ_ASSERT(mStartOffset == 30,
    2699             :     "Test 1-6-1: mStartOffset should be the smallest offset");
    2700           0 :   MOZ_ASSERT(mRemovedEndOffset == 35, // 32 - (32 - 35)
    2701             :     "Test 1-6-2: mRemovedEndOffset should be the the first end of removed "
    2702             :     "text");
    2703           0 :   MOZ_ASSERT(mAddedEndOffset == 40,
    2704             :     "Test 1-6-3: mAddedEndOffset should be the last end of added text");
    2705           0 :   Clear();
    2706             : 
    2707             :   // Replacing text and append text (becomes shorter)
    2708           0 :   MergeWith(TextChangeData(30, 35, 32, false, false));
    2709           0 :   MergeWith(TextChangeData(32, 32, 33, false, false));
    2710           0 :   MOZ_ASSERT(mStartOffset == 30,
    2711             :     "Test 1-7-1: mStartOffset should be the smallest offset");
    2712           0 :   MOZ_ASSERT(mRemovedEndOffset == 35, // 32 - (32 - 35)
    2713             :     "Test 1-7-2: mRemovedEndOffset should be the the first end of removed "
    2714             :     "text");
    2715           0 :   MOZ_ASSERT(mAddedEndOffset == 33,
    2716             :     "Test 1-7-3: mAddedEndOffset should be the last end of added text");
    2717           0 :   Clear();
    2718             : 
    2719             :   // Removing text and replacing text after first range (not sure if actually
    2720             :   // occurs)
    2721           0 :   MergeWith(TextChangeData(30, 35, 30, false, false));
    2722           0 :   MergeWith(TextChangeData(32, 34, 48, false, false));
    2723           0 :   MOZ_ASSERT(mStartOffset == 30,
    2724             :     "Test 1-8-1: mStartOffset should be the smallest offset");
    2725           0 :   MOZ_ASSERT(mRemovedEndOffset == 39, // 34 - (30 - 35)
    2726             :     "Test 1-8-2: mRemovedEndOffset should be the the first end of removed text "
    2727             :     "without already removed text");
    2728           0 :   MOZ_ASSERT(mAddedEndOffset == 48,
    2729             :     "Test 1-8-3: mAddedEndOffset should be the last end of added text");
    2730           0 :   Clear();
    2731             : 
    2732             :   // Removing text and replacing text after first range (not sure if actually
    2733             :   // occurs)
    2734           0 :   MergeWith(TextChangeData(30, 35, 30, false, false));
    2735           0 :   MergeWith(TextChangeData(32, 38, 36, false, false));
    2736           0 :   MOZ_ASSERT(mStartOffset == 30,
    2737             :     "Test 1-9-1: mStartOffset should be the smallest offset");
    2738           0 :   MOZ_ASSERT(mRemovedEndOffset == 43, // 38 - (30 - 35)
    2739             :     "Test 1-9-2: mRemovedEndOffset should be the the first end of removed text "
    2740             :     "without already removed text");
    2741           0 :   MOZ_ASSERT(mAddedEndOffset == 36,
    2742             :     "Test 1-9-3: mAddedEndOffset should be the last end of added text");
    2743           0 :   Clear();
    2744             : 
    2745             :   /****************************************************************************
    2746             :    * Case 2
    2747             :    ****************************************************************************/
    2748             : 
    2749             :   // Replacing text in around end of added text (becomes shorter) (not sure
    2750             :   // if actually occurs)
    2751           0 :   MergeWith(TextChangeData(50, 50, 55, false, false));
    2752           0 :   MergeWith(TextChangeData(53, 60, 54, false, false));
    2753           0 :   MOZ_ASSERT(mStartOffset == 50,
    2754             :     "Test 2-1-1: mStartOffset should be the smallest offset");
    2755           0 :   MOZ_ASSERT(mRemovedEndOffset == 55, // 60 - (55 - 50)
    2756             :     "Test 2-1-2: mRemovedEndOffset should be the the last end of removed text "
    2757             :     "without already added text length");
    2758           0 :   MOZ_ASSERT(mAddedEndOffset == 54,
    2759             :     "Test 2-1-3: mAddedEndOffset should be the last end of added text");
    2760           0 :   Clear();
    2761             : 
    2762             :   // Replacing text around end of added text (becomes longer) (not sure
    2763             :   // if actually occurs)
    2764           0 :   MergeWith(TextChangeData(50, 50, 55, false, false));
    2765           0 :   MergeWith(TextChangeData(54, 62, 68, false, false));
    2766           0 :   MOZ_ASSERT(mStartOffset == 50,
    2767             :     "Test 2-2-1: mStartOffset should be the smallest offset");
    2768           0 :   MOZ_ASSERT(mRemovedEndOffset == 57, // 62 - (55 - 50)
    2769             :     "Test 2-2-2: mRemovedEndOffset should be the the last end of removed text "
    2770             :     "without already added text length");
    2771           0 :   MOZ_ASSERT(mAddedEndOffset == 68,
    2772             :     "Test 2-2-3: mAddedEndOffset should be the last end of added text");
    2773           0 :   Clear();
    2774             : 
    2775             :   // Replacing text around end of replaced text (became shorter) (not sure if
    2776             :   // actually occurs)
    2777           0 :   MergeWith(TextChangeData(36, 48, 45, false, false));
    2778           0 :   MergeWith(TextChangeData(43, 50, 49, false, false));
    2779           0 :   MOZ_ASSERT(mStartOffset == 36,
    2780             :     "Test 2-3-1: mStartOffset should be the smallest offset");
    2781           0 :   MOZ_ASSERT(mRemovedEndOffset == 53, // 50 - (45 - 48)
    2782             :     "Test 2-3-2: mRemovedEndOffset should be the the last end of removed text "
    2783             :     "without already removed text length");
    2784           0 :   MOZ_ASSERT(mAddedEndOffset == 49,
    2785             :     "Test 2-3-3: mAddedEndOffset should be the last end of added text");
    2786           0 :   Clear();
    2787             : 
    2788             :   // Replacing text around end of replaced text (became longer) (not sure if
    2789             :   // actually occurs)
    2790           0 :   MergeWith(TextChangeData(36, 52, 53, false, false));
    2791           0 :   MergeWith(TextChangeData(43, 68, 61, false, false));
    2792           0 :   MOZ_ASSERT(mStartOffset == 36,
    2793             :     "Test 2-4-1: mStartOffset should be the smallest offset");
    2794           0 :   MOZ_ASSERT(mRemovedEndOffset == 67, // 68 - (53 - 52)
    2795             :     "Test 2-4-2: mRemovedEndOffset should be the the last end of removed text "
    2796             :     "without already added text length");
    2797           0 :   MOZ_ASSERT(mAddedEndOffset == 61,
    2798             :     "Test 2-4-3: mAddedEndOffset should be the last end of added text");
    2799           0 :   Clear();
    2800             : 
    2801             :   /****************************************************************************
    2802             :    * Case 3
    2803             :    ****************************************************************************/
    2804             : 
    2805             :   // Appending text in already added text (not sure if actually occurs)
    2806           0 :   MergeWith(TextChangeData(10, 10, 20, false, false));
    2807           0 :   MergeWith(TextChangeData(15, 15, 30, false, false));
    2808           0 :   MOZ_ASSERT(mStartOffset == 10,
    2809             :     "Test 3-1-1: mStartOffset should be the smallest offset");
    2810           0 :   MOZ_ASSERT(mRemovedEndOffset == 10,
    2811             :     "Test 3-1-2: mRemovedEndOffset should be the the first end of removed text");
    2812           0 :   MOZ_ASSERT(mAddedEndOffset == 35, // 20 + (30 - 15)
    2813             :     "Test 3-1-3: mAddedEndOffset should be the first end of added text with "
    2814             :     "added text length by the new change");
    2815           0 :   Clear();
    2816             : 
    2817             :   // Replacing text in added text (not sure if actually occurs)
    2818           0 :   MergeWith(TextChangeData(50, 50, 55, false, false));
    2819           0 :   MergeWith(TextChangeData(52, 53, 56, false, false));
    2820           0 :   MOZ_ASSERT(mStartOffset == 50,
    2821             :     "Test 3-2-1: mStartOffset should be the smallest offset");
    2822           0 :   MOZ_ASSERT(mRemovedEndOffset == 50,
    2823             :     "Test 3-2-2: mRemovedEndOffset should be the the first end of removed text");
    2824           0 :   MOZ_ASSERT(mAddedEndOffset == 58, // 55 + (56 - 53)
    2825             :     "Test 3-2-3: mAddedEndOffset should be the first end of added text with "
    2826             :     "added text length by the new change");
    2827           0 :   Clear();
    2828             : 
    2829             :   // Replacing text in replaced text (became shorter) (not sure if actually
    2830             :   // occurs)
    2831           0 :   MergeWith(TextChangeData(36, 48, 45, false, false));
    2832           0 :   MergeWith(TextChangeData(37, 38, 50, false, false));
    2833           0 :   MOZ_ASSERT(mStartOffset == 36,
    2834             :     "Test 3-3-1: mStartOffset should be the smallest offset");
    2835           0 :   MOZ_ASSERT(mRemovedEndOffset == 48,
    2836             :     "Test 3-3-2: mRemovedEndOffset should be the the first end of removed text");
    2837           0 :   MOZ_ASSERT(mAddedEndOffset == 57, // 45 + (50 - 38)
    2838             :     "Test 3-3-3: mAddedEndOffset should be the first end of added text with "
    2839             :     "added text length by the new change");
    2840           0 :   Clear();
    2841             : 
    2842             :   // Replacing text in replaced text (became longer) (not sure if actually
    2843             :   // occurs)
    2844           0 :   MergeWith(TextChangeData(32, 48, 53, false, false));
    2845           0 :   MergeWith(TextChangeData(43, 50, 52, false, false));
    2846           0 :   MOZ_ASSERT(mStartOffset == 32,
    2847             :     "Test 3-4-1: mStartOffset should be the smallest offset");
    2848           0 :   MOZ_ASSERT(mRemovedEndOffset == 48,
    2849             :     "Test 3-4-2: mRemovedEndOffset should be the the last end of removed text "
    2850             :     "without already added text length");
    2851           0 :   MOZ_ASSERT(mAddedEndOffset == 55, // 53 + (52 - 50)
    2852             :     "Test 3-4-3: mAddedEndOffset should be the first end of added text with "
    2853             :     "added text length by the new change");
    2854           0 :   Clear();
    2855             : 
    2856             :   // Replacing text in replaced text (became shorter) (not sure if actually
    2857             :   // occurs)
    2858           0 :   MergeWith(TextChangeData(36, 48, 50, false, false));
    2859           0 :   MergeWith(TextChangeData(37, 49, 47, false, false));
    2860           0 :   MOZ_ASSERT(mStartOffset == 36,
    2861             :     "Test 3-5-1: mStartOffset should be the smallest offset");
    2862           0 :   MOZ_ASSERT(mRemovedEndOffset == 48,
    2863             :     "Test 3-5-2: mRemovedEndOffset should be the the first end of removed "
    2864             :     "text");
    2865           0 :   MOZ_ASSERT(mAddedEndOffset == 48, // 50 + (47 - 49)
    2866             :     "Test 3-5-3: mAddedEndOffset should be the first end of added text without "
    2867             :     "removed text length by the new change");
    2868           0 :   Clear();
    2869             : 
    2870             :   // Replacing text in replaced text (became longer) (not sure if actually
    2871             :   // occurs)
    2872           0 :   MergeWith(TextChangeData(32, 48, 53, false, false));
    2873           0 :   MergeWith(TextChangeData(43, 50, 47, false, false));
    2874           0 :   MOZ_ASSERT(mStartOffset == 32,
    2875             :     "Test 3-6-1: mStartOffset should be the smallest offset");
    2876           0 :   MOZ_ASSERT(mRemovedEndOffset == 48,
    2877             :     "Test 3-6-2: mRemovedEndOffset should be the the last end of removed text "
    2878             :     "without already added text length");
    2879           0 :   MOZ_ASSERT(mAddedEndOffset == 50, // 53 + (47 - 50)
    2880             :     "Test 3-6-3: mAddedEndOffset should be the first end of added text without "
    2881             :     "removed text length by the new change");
    2882           0 :   Clear();
    2883             : 
    2884             :   /****************************************************************************
    2885             :    * Case 4
    2886             :    ****************************************************************************/
    2887             : 
    2888             :   // Replacing text all of already append text (not sure if actually occurs)
    2889           0 :   MergeWith(TextChangeData(50, 50, 55, false, false));
    2890           0 :   MergeWith(TextChangeData(44, 66, 68, false, false));
    2891           0 :   MOZ_ASSERT(mStartOffset == 44,
    2892             :     "Test 4-1-1: mStartOffset should be the smallest offset");
    2893           0 :   MOZ_ASSERT(mRemovedEndOffset == 61, // 66 - (55 - 50)
    2894             :     "Test 4-1-2: mRemovedEndOffset should be the the last end of removed text "
    2895             :     "without already added text length");
    2896           0 :   MOZ_ASSERT(mAddedEndOffset == 68,
    2897             :     "Test 4-1-3: mAddedEndOffset should be the last end of added text");
    2898           0 :   Clear();
    2899             : 
    2900             :   // Replacing text around a point in which text was removed (not sure if
    2901             :   // actually occurs)
    2902           0 :   MergeWith(TextChangeData(50, 62, 50, false, false));
    2903           0 :   MergeWith(TextChangeData(44, 66, 68, false, false));
    2904           0 :   MOZ_ASSERT(mStartOffset == 44,
    2905             :     "Test 4-2-1: mStartOffset should be the smallest offset");
    2906           0 :   MOZ_ASSERT(mRemovedEndOffset == 78, // 66 - (50 - 62)
    2907             :     "Test 4-2-2: mRemovedEndOffset should be the the last end of removed text "
    2908             :     "without already removed text length");
    2909           0 :   MOZ_ASSERT(mAddedEndOffset == 68,
    2910             :     "Test 4-2-3: mAddedEndOffset should be the last end of added text");
    2911           0 :   Clear();
    2912             : 
    2913             :   // Replacing text all replaced text (became shorter) (not sure if actually
    2914             :   // occurs)
    2915           0 :   MergeWith(TextChangeData(50, 62, 60, false, false));
    2916           0 :   MergeWith(TextChangeData(49, 128, 130, false, false));
    2917           0 :   MOZ_ASSERT(mStartOffset == 49,
    2918             :     "Test 4-3-1: mStartOffset should be the smallest offset");
    2919           0 :   MOZ_ASSERT(mRemovedEndOffset == 130, // 128 - (60 - 62)
    2920             :     "Test 4-3-2: mRemovedEndOffset should be the the last end of removed text "
    2921             :     "without already removed text length");
    2922           0 :   MOZ_ASSERT(mAddedEndOffset == 130,
    2923             :     "Test 4-3-3: mAddedEndOffset should be the last end of added text");
    2924           0 :   Clear();
    2925             : 
    2926             :   // Replacing text all replaced text (became longer) (not sure if actually
    2927             :   // occurs)
    2928           0 :   MergeWith(TextChangeData(50, 61, 73, false, false));
    2929           0 :   MergeWith(TextChangeData(44, 100, 50, false, false));
    2930           0 :   MOZ_ASSERT(mStartOffset == 44,
    2931             :     "Test 4-4-1: mStartOffset should be the smallest offset");
    2932           0 :   MOZ_ASSERT(mRemovedEndOffset == 88, // 100 - (73 - 61)
    2933             :     "Test 4-4-2: mRemovedEndOffset should be the the last end of removed text "
    2934             :     "with already added text length");
    2935           0 :   MOZ_ASSERT(mAddedEndOffset == 50,
    2936             :     "Test 4-4-3: mAddedEndOffset should be the last end of added text");
    2937           0 :   Clear();
    2938             : 
    2939             :   /****************************************************************************
    2940             :    * Case 5
    2941             :    ****************************************************************************/
    2942             : 
    2943             :   // Replacing text around start of added text (not sure if actually occurs)
    2944           0 :   MergeWith(TextChangeData(50, 50, 55, false, false));
    2945           0 :   MergeWith(TextChangeData(48, 52, 49, false, false));
    2946           0 :   MOZ_ASSERT(mStartOffset == 48,
    2947             :     "Test 5-1-1: mStartOffset should be the smallest offset");
    2948           0 :   MOZ_ASSERT(mRemovedEndOffset == 50,
    2949             :     "Test 5-1-2: mRemovedEndOffset should be the the first end of removed "
    2950             :     "text");
    2951           0 :   MOZ_ASSERT(mAddedEndOffset == 52, // 55 + (52 - 49)
    2952             :     "Test 5-1-3: mAddedEndOffset should be the first end of added text with "
    2953             :     "added text length by the new change");
    2954           0 :   Clear();
    2955             : 
    2956             :   // Replacing text around start of replaced text (became shorter) (not sure if
    2957             :   // actually occurs)
    2958           0 :   MergeWith(TextChangeData(50, 60, 58, false, false));
    2959           0 :   MergeWith(TextChangeData(43, 50, 48, false, false));
    2960           0 :   MOZ_ASSERT(mStartOffset == 43,
    2961             :     "Test 5-2-1: mStartOffset should be the smallest offset");
    2962           0 :   MOZ_ASSERT(mRemovedEndOffset == 60,
    2963             :     "Test 5-2-2: mRemovedEndOffset should be the the first end of removed "
    2964             :     "text");
    2965           0 :   MOZ_ASSERT(mAddedEndOffset == 56, // 58 + (48 - 50)
    2966             :     "Test 5-2-3: mAddedEndOffset should be the first end of added text without "
    2967             :     "removed text length by the new change");
    2968           0 :   Clear();
    2969             : 
    2970             :   // Replacing text around start of replaced text (became longer) (not sure if
    2971             :   // actually occurs)
    2972           0 :   MergeWith(TextChangeData(50, 60, 68, false, false));
    2973           0 :   MergeWith(TextChangeData(43, 55, 53, false, false));
    2974           0 :   MOZ_ASSERT(mStartOffset == 43,
    2975             :     "Test 5-3-1: mStartOffset should be the smallest offset");
    2976           0 :   MOZ_ASSERT(mRemovedEndOffset == 60,
    2977             :     "Test 5-3-2: mRemovedEndOffset should be the the first end of removed "
    2978             :     "text");
    2979           0 :   MOZ_ASSERT(mAddedEndOffset == 66, // 68 + (53 - 55)
    2980             :     "Test 5-3-3: mAddedEndOffset should be the first end of added text without "
    2981             :     "removed text length by the new change");
    2982           0 :   Clear();
    2983             : 
    2984             :   // Replacing text around start of replaced text (became shorter) (not sure if
    2985             :   // actually occurs)
    2986           0 :   MergeWith(TextChangeData(50, 60, 58, false, false));
    2987           0 :   MergeWith(TextChangeData(43, 50, 128, false, false));
    2988           0 :   MOZ_ASSERT(mStartOffset == 43,
    2989             :     "Test 5-4-1: mStartOffset should be the smallest offset");
    2990           0 :   MOZ_ASSERT(mRemovedEndOffset == 60,
    2991             :     "Test 5-4-2: mRemovedEndOffset should be the the first end of removed "
    2992             :     "text");
    2993           0 :   MOZ_ASSERT(mAddedEndOffset == 136, // 58 + (128 - 50)
    2994             :     "Test 5-4-3: mAddedEndOffset should be the first end of added text with "
    2995             :     "added text length by the new change");
    2996           0 :   Clear();
    2997             : 
    2998             :   // Replacing text around start of replaced text (became longer) (not sure if
    2999             :   // actually occurs)
    3000           0 :   MergeWith(TextChangeData(50, 60, 68, false, false));
    3001           0 :   MergeWith(TextChangeData(43, 55, 65, false, false));
    3002           0 :   MOZ_ASSERT(mStartOffset == 43,
    3003             :     "Test 5-5-1: mStartOffset should be the smallest offset");
    3004           0 :   MOZ_ASSERT(mRemovedEndOffset == 60,
    3005             :     "Test 5-5-2: mRemovedEndOffset should be the the first end of removed "
    3006             :     "text");
    3007           0 :   MOZ_ASSERT(mAddedEndOffset == 78, // 68 + (65 - 55)
    3008             :     "Test 5-5-3: mAddedEndOffset should be the first end of added text with "
    3009             :     "added text length by the new change");
    3010           0 :   Clear();
    3011             : 
    3012             :   /****************************************************************************
    3013             :    * Case 6
    3014             :    ****************************************************************************/
    3015             : 
    3016             :   // Appending text before already added text (not sure if actually occurs)
    3017           0 :   MergeWith(TextChangeData(30, 30, 45, false, false));
    3018           0 :   MergeWith(TextChangeData(10, 10, 20, false, false));
    3019           0 :   MOZ_ASSERT(mStartOffset == 10,
    3020             :     "Test 6-1-1: mStartOffset should be the smallest offset");
    3021           0 :   MOZ_ASSERT(mRemovedEndOffset == 30,
    3022             :     "Test 6-1-2: mRemovedEndOffset should be the the largest end of removed "
    3023             :     "text");
    3024           0 :   MOZ_ASSERT(mAddedEndOffset == 55, // 45 + (20 - 10)
    3025             :     "Test 6-1-3: mAddedEndOffset should be the first end of added text with "
    3026             :     "added text length by the new change");
    3027           0 :   Clear();
    3028             : 
    3029             :   // Removing text before already removed text (not sure if actually occurs)
    3030           0 :   MergeWith(TextChangeData(30, 35, 30, false, false));
    3031           0 :   MergeWith(TextChangeData(10, 25, 10, false, false));
    3032           0 :   MOZ_ASSERT(mStartOffset == 10,
    3033             :     "Test 6-2-1: mStartOffset should be the smallest offset");
    3034           0 :   MOZ_ASSERT(mRemovedEndOffset == 35,
    3035             :     "Test 6-2-2: mRemovedEndOffset should be the the largest end of removed "
    3036             :     "text");
    3037           0 :   MOZ_ASSERT(mAddedEndOffset == 15, // 30 - (25 - 10)
    3038             :     "Test 6-2-3: mAddedEndOffset should be the first end of added text with "
    3039             :     "removed text length by the new change");
    3040           0 :   Clear();
    3041             : 
    3042             :   // Replacing text before already replaced text (not sure if actually occurs)
    3043           0 :   MergeWith(TextChangeData(50, 65, 70, false, false));
    3044           0 :   MergeWith(TextChangeData(13, 24, 15, false, false));
    3045           0 :   MOZ_ASSERT(mStartOffset == 13,
    3046             :     "Test 6-3-1: mStartOffset should be the smallest offset");
    3047           0 :   MOZ_ASSERT(mRemovedEndOffset == 65,
    3048             :     "Test 6-3-2: mRemovedEndOffset should be the the largest end of removed "
    3049             :     "text");
    3050           0 :   MOZ_ASSERT(mAddedEndOffset == 61, // 70 + (15 - 24)
    3051             :     "Test 6-3-3: mAddedEndOffset should be the first end of added text without "
    3052             :     "removed text length by the new change");
    3053           0 :   Clear();
    3054             : 
    3055             :   // Replacing text before already replaced text (not sure if actually occurs)
    3056           0 :   MergeWith(TextChangeData(50, 65, 70, false, false));
    3057           0 :   MergeWith(TextChangeData(13, 24, 36, false, false));
    3058           0 :   MOZ_ASSERT(mStartOffset == 13,
    3059             :     "Test 6-4-1: mStartOffset should be the smallest offset");
    3060           0 :   MOZ_ASSERT(mRemovedEndOffset == 65,
    3061             :     "Test 6-4-2: mRemovedEndOffset should be the the largest end of removed "
    3062             :     "text");
    3063           0 :   MOZ_ASSERT(mAddedEndOffset == 82, // 70 + (36 - 24)
    3064             :     "Test 6-4-3: mAddedEndOffset should be the first end of added text without "
    3065             :     "removed text length by the new change");
    3066           0 :   Clear();
    3067             : }
    3068             : 
    3069             : #endif // #ifdef DEBUG
    3070             : 
    3071             : } // namespace widget
    3072             : } // namespace mozilla
    3073             : 
    3074             : #ifdef DEBUG
    3075             : //////////////////////////////////////////////////////////////
    3076             : //
    3077             : // Convert a GUI event message code to a string.
    3078             : // Makes it a lot easier to debug events.
    3079             : //
    3080             : // See gtk/nsWidget.cpp and windows/nsWindow.cpp
    3081             : // for a DebugPrintEvent() function that uses
    3082             : // this.
    3083             : //
    3084             : //////////////////////////////////////////////////////////////
    3085             : /* static */ nsAutoString
    3086           0 : nsBaseWidget::debug_GuiEventToString(WidgetGUIEvent* aGuiEvent)
    3087             : {
    3088           0 :   NS_ASSERTION(nullptr != aGuiEvent,"cmon, null gui event.");
    3089             : 
    3090           0 :   nsAutoString eventName(NS_LITERAL_STRING("UNKNOWN"));
    3091             : 
    3092             : #define _ASSIGN_eventName(_value,_name)\
    3093             : case _value: eventName.AssignLiteral(_name) ; break
    3094             : 
    3095           0 :   switch(aGuiEvent->mMessage)
    3096             :   {
    3097           0 :     _ASSIGN_eventName(eBlur,"eBlur");
    3098           0 :     _ASSIGN_eventName(eDrop,"eDrop");
    3099           0 :     _ASSIGN_eventName(eDragEnter,"eDragEnter");
    3100           0 :     _ASSIGN_eventName(eDragExit,"eDragExit");
    3101           0 :     _ASSIGN_eventName(eDragOver,"eDragOver");
    3102           0 :     _ASSIGN_eventName(eEditorInput,"eEditorInput");
    3103           0 :     _ASSIGN_eventName(eFocus,"eFocus");
    3104           0 :     _ASSIGN_eventName(eFocusIn,"eFocusIn");
    3105           0 :     _ASSIGN_eventName(eFocusOut,"eFocusOut");
    3106           0 :     _ASSIGN_eventName(eFormSelect,"eFormSelect");
    3107           0 :     _ASSIGN_eventName(eFormChange,"eFormChange");
    3108           0 :     _ASSIGN_eventName(eFormReset,"eFormReset");
    3109           0 :     _ASSIGN_eventName(eFormSubmit,"eFormSubmit");
    3110           0 :     _ASSIGN_eventName(eImageAbort,"eImageAbort");
    3111           0 :     _ASSIGN_eventName(eLoadError,"eLoadError");
    3112           0 :     _ASSIGN_eventName(eKeyDown,"eKeyDown");
    3113           0 :     _ASSIGN_eventName(eKeyPress,"eKeyPress");
    3114           0 :     _ASSIGN_eventName(eKeyUp,"eKeyUp");
    3115           0 :     _ASSIGN_eventName(eMouseEnterIntoWidget,"eMouseEnterIntoWidget");
    3116           0 :     _ASSIGN_eventName(eMouseExitFromWidget,"eMouseExitFromWidget");
    3117           0 :     _ASSIGN_eventName(eMouseDown,"eMouseDown");
    3118           0 :     _ASSIGN_eventName(eMouseUp,"eMouseUp");
    3119           0 :     _ASSIGN_eventName(eMouseClick,"eMouseClick");
    3120           0 :     _ASSIGN_eventName(eMouseAuxClick,"eMouseAuxClick");
    3121           0 :     _ASSIGN_eventName(eMouseDoubleClick,"eMouseDoubleClick");
    3122           0 :     _ASSIGN_eventName(eMouseMove,"eMouseMove");
    3123           0 :     _ASSIGN_eventName(eLoad,"eLoad");
    3124           0 :     _ASSIGN_eventName(ePopState,"ePopState");
    3125           0 :     _ASSIGN_eventName(eBeforeScriptExecute,"eBeforeScriptExecute");
    3126           0 :     _ASSIGN_eventName(eAfterScriptExecute,"eAfterScriptExecute");
    3127           0 :     _ASSIGN_eventName(eUnload,"eUnload");
    3128           0 :     _ASSIGN_eventName(eHashChange,"eHashChange");
    3129           0 :     _ASSIGN_eventName(eReadyStateChange,"eReadyStateChange");
    3130           0 :     _ASSIGN_eventName(eXULBroadcast, "eXULBroadcast");
    3131           0 :     _ASSIGN_eventName(eXULCommandUpdate, "eXULCommandUpdate");
    3132             : 
    3133             : #undef _ASSIGN_eventName
    3134             : 
    3135             :   default:
    3136             :     {
    3137             :       char buf[32];
    3138             : 
    3139           0 :       SprintfLiteral(buf,"UNKNOWN: %d",aGuiEvent->mMessage);
    3140             : 
    3141           0 :       CopyASCIItoUTF16(buf, eventName);
    3142             :     }
    3143           0 :     break;
    3144             :   }
    3145             : 
    3146           0 :   return nsAutoString(eventName);
    3147             : }
    3148             : //////////////////////////////////////////////////////////////
    3149             : //
    3150             : // Code to deal with paint and event debug prefs.
    3151             : //
    3152             : //////////////////////////////////////////////////////////////
    3153             : struct PrefPair
    3154             : {
    3155             :   const char * name;
    3156             :   bool value;
    3157             : };
    3158             : 
    3159             : static PrefPair debug_PrefValues[] =
    3160             : {
    3161             :   { "nglayout.debug.crossing_event_dumping", false },
    3162             :   { "nglayout.debug.event_dumping", false },
    3163             :   { "nglayout.debug.invalidate_dumping", false },
    3164             :   { "nglayout.debug.motion_event_dumping", false },
    3165             :   { "nglayout.debug.paint_dumping", false },
    3166             :   { "nglayout.debug.paint_flashing", false }
    3167             : };
    3168             : 
    3169             : //////////////////////////////////////////////////////////////
    3170             : bool
    3171          17 : nsBaseWidget::debug_GetCachedBoolPref(const char * aPrefName)
    3172             : {
    3173          17 :   NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
    3174             : 
    3175          55 :   for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
    3176             :   {
    3177          55 :     if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
    3178             :     {
    3179          17 :       return debug_PrefValues[i].value;
    3180             :     }
    3181             :   }
    3182             : 
    3183           0 :   return false;
    3184             : }
    3185             : //////////////////////////////////////////////////////////////
    3186           0 : static void debug_SetCachedBoolPref(const char * aPrefName,bool aValue)
    3187             : {
    3188           0 :   NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
    3189             : 
    3190           0 :   for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
    3191             :   {
    3192           0 :     if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
    3193             :     {
    3194           0 :       debug_PrefValues[i].value = aValue;
    3195             : 
    3196           0 :       return;
    3197             :     }
    3198             :   }
    3199             : 
    3200           0 :   NS_ASSERTION(false, "cmon, this code is not reached dude.");
    3201             : }
    3202             : 
    3203             : //////////////////////////////////////////////////////////////
    3204           2 : class Debug_PrefObserver final : public nsIObserver {
    3205           0 :     ~Debug_PrefObserver() {}
    3206             : 
    3207             :   public:
    3208             :     NS_DECL_ISUPPORTS
    3209             :     NS_DECL_NSIOBSERVER
    3210             : };
    3211             : 
    3212         106 : NS_IMPL_ISUPPORTS(Debug_PrefObserver, nsIObserver)
    3213             : 
    3214             : NS_IMETHODIMP
    3215           0 : Debug_PrefObserver::Observe(nsISupports* subject, const char* topic,
    3216             :                             const char16_t* data)
    3217             : {
    3218           0 :   NS_ConvertUTF16toUTF8 prefName(data);
    3219             : 
    3220           0 :   bool value = Preferences::GetBool(prefName.get(), false);
    3221           0 :   debug_SetCachedBoolPref(prefName.get(), value);
    3222           0 :   return NS_OK;
    3223             : }
    3224             : 
    3225             : //////////////////////////////////////////////////////////////
    3226             : /* static */ void
    3227           3 : debug_RegisterPrefCallbacks()
    3228             : {
    3229             :   static bool once = true;
    3230             : 
    3231           3 :   if (!once) {
    3232           1 :     return;
    3233             :   }
    3234             : 
    3235           2 :   once = false;
    3236             : 
    3237           4 :   nsCOMPtr<nsIObserver> obs(new Debug_PrefObserver());
    3238          14 :   for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++) {
    3239             :     // Initialize the pref values
    3240          12 :     debug_PrefValues[i].value =
    3241          12 :       Preferences::GetBool(debug_PrefValues[i].name, false);
    3242             : 
    3243          12 :     if (obs) {
    3244             :       // Register callbacks for when these change
    3245          12 :       Preferences::AddStrongObserver(obs, debug_PrefValues[i].name);
    3246             :     }
    3247             :   }
    3248             : }
    3249             : //////////////////////////////////////////////////////////////
    3250             : static int32_t
    3251           0 : _GetPrintCount()
    3252             : {
    3253             :   static int32_t sCount = 0;
    3254             : 
    3255           0 :   return ++sCount;
    3256             : }
    3257             : //////////////////////////////////////////////////////////////
    3258             : /* static */ bool
    3259           0 : nsBaseWidget::debug_WantPaintFlashing()
    3260             : {
    3261           0 :   return debug_GetCachedBoolPref("nglayout.debug.paint_flashing");
    3262             : }
    3263             : //////////////////////////////////////////////////////////////
    3264             : /* static */ void
    3265          12 : nsBaseWidget::debug_DumpEvent(FILE *                aFileOut,
    3266             :                               nsIWidget *           aWidget,
    3267             :                               WidgetGUIEvent*       aGuiEvent,
    3268             :                               const char*           aWidgetName,
    3269             :                               int32_t               aWindowID)
    3270             : {
    3271          12 :   if (aGuiEvent->mMessage == eMouseMove) {
    3272           8 :     if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping"))
    3273          20 :       return;
    3274             :   }
    3275             : 
    3276           6 :   if (aGuiEvent->mMessage == eMouseEnterIntoWidget ||
    3277           2 :       aGuiEvent->mMessage == eMouseExitFromWidget) {
    3278           4 :     if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping"))
    3279           4 :       return;
    3280             :   }
    3281             : 
    3282           0 :   if (!debug_GetCachedBoolPref("nglayout.debug.event_dumping"))
    3283           0 :     return;
    3284             : 
    3285           0 :   NS_LossyConvertUTF16toASCII tempString(debug_GuiEventToString(aGuiEvent).get());
    3286             : 
    3287           0 :   fprintf(aFileOut,
    3288             :           "%4d %-26s widget=%-8p name=%-12s id=0x%-6x refpt=%d,%d\n",
    3289             :           _GetPrintCount(),
    3290             :           tempString.get(),
    3291             :           (void *) aWidget,
    3292             :           aWidgetName,
    3293             :           aWindowID,
    3294             :           aGuiEvent->mRefPoint.x,
    3295           0 :           aGuiEvent->mRefPoint.y);
    3296             : }
    3297             : //////////////////////////////////////////////////////////////
    3298             : /* static */ void
    3299           2 : nsBaseWidget::debug_DumpPaintEvent(FILE *                aFileOut,
    3300             :                                    nsIWidget *           aWidget,
    3301             :                                    const nsIntRegion &   aRegion,
    3302             :                                    const char *          aWidgetName,
    3303             :                                    int32_t               aWindowID)
    3304             : {
    3305           2 :   NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
    3306           2 :   NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
    3307             : 
    3308           2 :   if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
    3309           2 :     return;
    3310             : 
    3311           0 :   nsIntRect rect = aRegion.GetBounds();
    3312           0 :   fprintf(aFileOut,
    3313             :           "%4d PAINT      widget=%p name=%-12s id=0x%-6x bounds-rect=%3d,%-3d %3d,%-3d",
    3314             :           _GetPrintCount(),
    3315             :           (void *) aWidget,
    3316             :           aWidgetName,
    3317             :           aWindowID,
    3318             :           rect.x, rect.y, rect.width, rect.height
    3319           0 :     );
    3320             : 
    3321           0 :   fprintf(aFileOut,"\n");
    3322             : }
    3323             : //////////////////////////////////////////////////////////////
    3324             : /* static */ void
    3325           3 : nsBaseWidget::debug_DumpInvalidate(FILE* aFileOut,
    3326             :                                    nsIWidget* aWidget,
    3327             :                                    const LayoutDeviceIntRect* aRect,
    3328             :                                    const char* aWidgetName,
    3329             :                                    int32_t aWindowID)
    3330             : {
    3331           3 :   if (!debug_GetCachedBoolPref("nglayout.debug.invalidate_dumping"))
    3332           3 :     return;
    3333             : 
    3334           0 :   NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
    3335           0 :   NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
    3336             : 
    3337           0 :   fprintf(aFileOut,
    3338             :           "%4d Invalidate widget=%p name=%-12s id=0x%-6x",
    3339             :           _GetPrintCount(),
    3340             :           (void *) aWidget,
    3341             :           aWidgetName,
    3342           0 :           aWindowID);
    3343             : 
    3344           0 :   if (aRect) {
    3345             :     fprintf(aFileOut,
    3346             :             " rect=%3d,%-3d %3d,%-3d",
    3347           0 :             aRect->x, aRect->y, aRect->width, aRect->height);
    3348             :   } else {
    3349             :     fprintf(aFileOut,
    3350             :             " rect=%-15s",
    3351           0 :             "none");
    3352             :   }
    3353             : 
    3354           0 :   fprintf(aFileOut, "\n");
    3355           9 : }
    3356             : //////////////////////////////////////////////////////////////
    3357             : 
    3358             : #endif // DEBUG

Generated by: LCOV version 1.13