123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "mozilla/ArrayUtils.h"
- #include "mozilla/UniquePtr.h"
- #include "mozilla/TextEventDispatcher.h"
- #include "mozilla/TextEventDispatcherListener.h"
- #include "mozilla/layers/CompositorBridgeChild.h"
- #include "mozilla/layers/CompositorBridgeParent.h"
- #include "mozilla/layers/ImageBridgeChild.h"
- #include "nsBaseWidget.h"
- #include "nsDeviceContext.h"
- #include "nsCOMPtr.h"
- #include "nsGfxCIID.h"
- #include "nsWidgetsCID.h"
- #include "nsServiceManagerUtils.h"
- #include "nsIKeyEventInPluginCallback.h"
- #include "nsIScreenManager.h"
- #include "nsAppDirectoryServiceDefs.h"
- #include "nsISimpleEnumerator.h"
- #include "nsIContent.h"
- #include "nsIDocument.h"
- #include "nsIPresShell.h"
- #include "nsIServiceManager.h"
- #include "mozilla/Preferences.h"
- #include "BasicLayers.h"
- #include "ClientLayerManager.h"
- #include "mozilla/layers/Compositor.h"
- #include "nsIXULRuntime.h"
- #include "nsIXULWindow.h"
- #include "nsIBaseWindow.h"
- #include "nsXULPopupManager.h"
- #include "nsIWidgetListener.h"
- #include "nsIGfxInfo.h"
- #include "npapi.h"
- #include "X11UndefineNone.h"
- #include "base/thread.h"
- #include "prdtoa.h"
- #include "prenv.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/Unused.h"
- #include "nsContentUtils.h"
- #include "gfxPrefs.h"
- #include "mozilla/gfx/2D.h"
- #include "mozilla/MouseEvents.h"
- #include "GLConsts.h"
- #include "mozilla/Unused.h"
- #include "mozilla/IMEStateManager.h"
- #include "mozilla/VsyncDispatcher.h"
- #include "mozilla/layers/IAPZCTreeManager.h"
- #include "mozilla/layers/APZEventState.h"
- #include "mozilla/layers/APZThreadUtils.h"
- #include "mozilla/layers/ChromeProcessController.h"
- #include "mozilla/layers/InputAPZContext.h"
- #include "mozilla/layers/APZCCallbackHelper.h"
- #include "mozilla/dom/ContentChild.h"
- #include "mozilla/dom/TabParent.h"
- #include "mozilla/gfx/GPUProcessManager.h"
- #include "mozilla/Move.h"
- #include "mozilla/Services.h"
- #include "mozilla/Sprintf.h"
- #include "nsRefPtrHashtable.h"
- #include "TouchEvents.h"
- #include "WritingModes.h"
- #include "InputData.h"
- #include "FrameLayerBuilder.h"
- #ifdef ACCESSIBILITY
- #include "nsAccessibilityService.h"
- #endif
- #include "gfxConfig.h"
- #include "mozilla/layers/CompositorSession.h"
- #ifdef DEBUG
- #include "nsIObserver.h"
- static void debug_RegisterPrefCallbacks();
- #endif
- #ifdef NOISY_WIDGET_LEAKS
- static int32_t gNumWidgets;
- #endif
- #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
- static nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>* sPluginWidgetList;
- #endif
- nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
- using namespace mozilla::dom;
- using namespace mozilla::layers;
- using namespace mozilla::ipc;
- using namespace mozilla::widget;
- using namespace mozilla;
- using base::Thread;
- nsIContent* nsBaseWidget::mLastRollup = nullptr;
- // Global user preference for disabling native theme. Used
- // in NativeWindowTheme.
- bool gDisableNativeTheme = false;
- // Async pump timer during injected long touch taps
- #define TOUCH_INJECT_PUMP_TIMER_MSEC 50
- #define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
- int32_t nsIWidget::sPointerIdCounter = 0;
- // Some statics from nsIWidget.h
- /*static*/ uint64_t AutoObserverNotifier::sObserverId = 0;
- /*static*/ nsDataHashtable<nsUint64HashKey, nsCOMPtr<nsIObserver>> AutoObserverNotifier::sSavedObservers;
- namespace mozilla {
- namespace widget {
- void
- IMENotification::SelectionChangeDataBase::SetWritingMode(
- const WritingMode& aWritingMode)
- {
- mWritingMode = aWritingMode.mWritingMode;
- }
- WritingMode
- IMENotification::SelectionChangeDataBase::GetWritingMode() const
- {
- return WritingMode(mWritingMode);
- }
- } // namespace widget
- } // namespace mozilla
- nsAutoRollup::nsAutoRollup()
- {
- // remember if mLastRollup was null, and only clear it upon destruction
- // if so. This prevents recursive usage of nsAutoRollup from clearing
- // mLastRollup when it shouldn't.
- wasClear = !nsBaseWidget::mLastRollup;
- }
- nsAutoRollup::~nsAutoRollup()
- {
- if (nsBaseWidget::mLastRollup && wasClear) {
- NS_RELEASE(nsBaseWidget::mLastRollup);
- }
- }
- NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidget, nsISupportsWeakReference)
- //-------------------------------------------------------------------------
- //
- // nsBaseWidget constructor
- //
- //-------------------------------------------------------------------------
- nsBaseWidget::nsBaseWidget()
- : mWidgetListener(nullptr)
- , mAttachedWidgetListener(nullptr)
- , mPreviouslyAttachedWidgetListener(nullptr)
- , mLayerManager(nullptr)
- , mCompositorVsyncDispatcher(nullptr)
- , mCursor(eCursor_standard)
- , mBorderStyle(eBorderStyle_none)
- , mBounds(0,0,0,0)
- , mOriginalBounds(nullptr)
- , mClipRectCount(0)
- , mSizeMode(nsSizeMode_Normal)
- , mPopupLevel(ePopupLevelTop)
- , mPopupType(ePopupTypeAny)
- , mCompositorWidgetDelegate(nullptr)
- , mUpdateCursor(true)
- , mUseAttachedEvents(false)
- , mIMEHasFocus(false)
- #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
- , mAccessibilityInUseFlag(false)
- #endif
- {
- #ifdef NOISY_WIDGET_LEAKS
- gNumWidgets++;
- printf("WIDGETS+ = %d\n", gNumWidgets);
- #endif
- #ifdef DEBUG
- debug_RegisterPrefCallbacks();
- #endif
- #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
- if (!sPluginWidgetList) {
- sPluginWidgetList = new nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>();
- }
- #endif
- mShutdownObserver = new WidgetShutdownObserver(this);
- }
- NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
- WidgetShutdownObserver::WidgetShutdownObserver(nsBaseWidget* aWidget) :
- mWidget(aWidget),
- mRegistered(false)
- {
- Register();
- }
- WidgetShutdownObserver::~WidgetShutdownObserver()
- {
- // No need to call Unregister(), we can't be destroyed until nsBaseWidget
- // gets torn down. The observer service and nsBaseWidget have a ref on us
- // so nsBaseWidget has to call Unregister and then clear its ref.
- }
- NS_IMETHODIMP
- WidgetShutdownObserver::Observe(nsISupports *aSubject,
- const char *aTopic,
- const char16_t *aData)
- {
- if (mWidget && !strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
- RefPtr<nsBaseWidget> widget(mWidget);
- widget->Shutdown();
- }
- return NS_OK;
- }
- void
- WidgetShutdownObserver::Register()
- {
- if (!mRegistered) {
- mRegistered = true;
- nsContentUtils::RegisterShutdownObserver(this);
- }
- }
- void
- WidgetShutdownObserver::Unregister()
- {
- if (mRegistered) {
- mWidget = nullptr;
- nsContentUtils::UnregisterShutdownObserver(this);
- mRegistered = false;
- }
- }
- void
- nsBaseWidget::Shutdown()
- {
- RevokeTransactionIdAllocator();
- DestroyCompositor();
- FreeShutdownObserver();
- #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
- if (sPluginWidgetList) {
- delete sPluginWidgetList;
- sPluginWidgetList = nullptr;
- }
- #endif
- }
- void nsBaseWidget::DestroyCompositor()
- {
- // We release this before releasing the compositor, since it may hold the
- // last reference to our ClientLayerManager. ClientLayerManager's dtor can
- // trigger a paint, creating a new compositor, and we don't want to re-use
- // the old vsync dispatcher.
- if (mCompositorVsyncDispatcher) {
- mCompositorVsyncDispatcher->Shutdown();
- mCompositorVsyncDispatcher = nullptr;
- }
- // The compositor shutdown sequence looks like this:
- // 1. CompositorSession calls CompositorBridgeChild::Destroy.
- // 2. CompositorBridgeChild synchronously sends WillClose.
- // 3. CompositorBridgeParent releases some resources (such as the layer
- // manager, compositor, and widget).
- // 4. CompositorBridgeChild::Destroy returns.
- // 5. Asynchronously, CompositorBridgeParent::ActorDestroy will fire on the
- // compositor thread when the I/O thread closes the IPC channel.
- // 6. Step 5 will schedule DeferredDestroy on the compositor thread, which
- // releases the reference CompositorBridgeParent holds to itself.
- //
- // When CompositorSession::Shutdown returns, we assume the compositor is gone
- // or will be gone very soon.
- if (mCompositorSession) {
- ReleaseContentController();
- mAPZC = nullptr;
- mCompositorWidgetDelegate = nullptr;
- mCompositorBridgeChild = nullptr;
- // XXX CompositorBridgeChild and CompositorBridgeParent might be re-created in
- // ClientLayerManager destructor. See bug 1133426.
- RefPtr<CompositorSession> session = mCompositorSession.forget();
- session->Shutdown();
- }
- }
- // This prevents the layer manager from starting a new transaction during
- // shutdown.
- void
- nsBaseWidget::RevokeTransactionIdAllocator()
- {
- if (!mLayerManager) {
- return;
- }
- ClientLayerManager* clm = mLayerManager->AsClientLayerManager();
- if (!clm) {
- return;
- }
- clm->SetTransactionIdAllocator(nullptr);
- }
- void nsBaseWidget::ReleaseContentController()
- {
- if (mRootContentController) {
- mRootContentController->Destroy();
- mRootContentController = nullptr;
- }
- }
- void nsBaseWidget::DestroyLayerManager()
- {
- if (mLayerManager) {
- mLayerManager->Destroy();
- mLayerManager = nullptr;
- }
- DestroyCompositor();
- }
- void
- nsBaseWidget::OnRenderingDeviceReset()
- {
- if (!mLayerManager || !mCompositorSession) {
- return;
- }
- nsTArray<LayersBackend> backendHints;
- gfxPlatform::GetPlatform()->GetCompositorBackends(ComputeShouldAccelerate(), backendHints);
- // If the existing compositor does not use acceleration, and this widget
- // should not be accelerated, then there's no point in resetting.
- //
- // Note that if this widget should be accelerated, but instead has a basic
- // compositor, we still reset just in case we're now in the position to get
- // accelerated layers again.
- RefPtr<ClientLayerManager> clm = mLayerManager->AsClientLayerManager();
- if (!ComputeShouldAccelerate() &&
- clm->GetTextureFactoryIdentifier().mParentBackend != LayersBackend::LAYERS_BASIC)
- {
- return;
- }
- // Recreate the compositor.
- TextureFactoryIdentifier identifier;
- if (!mCompositorSession->Reset(backendHints, &identifier)) {
- // No action was taken, so we don't have to do anything.
- return;
- }
- // Invalidate all layers.
- FrameLayerBuilder::InvalidateAllLayers(mLayerManager);
- // Update the texture factory identifier.
- clm->UpdateTextureFactoryIdentifier(identifier);
- ImageBridgeChild::IdentifyCompositorTextureHost(identifier);
- }
- void
- nsBaseWidget::FreeShutdownObserver()
- {
- if (mShutdownObserver) {
- mShutdownObserver->Unregister();
- }
- mShutdownObserver = nullptr;
- }
- //-------------------------------------------------------------------------
- //
- // nsBaseWidget destructor
- //
- //-------------------------------------------------------------------------
- nsBaseWidget::~nsBaseWidget()
- {
- IMEStateManager::WidgetDestroyed(this);
- if (mLayerManager) {
- if (BasicLayerManager* mgr = mLayerManager->AsBasicLayerManager()) {
- mgr->ClearRetainerWidget();
- }
- }
- FreeShutdownObserver();
- RevokeTransactionIdAllocator();
- DestroyLayerManager();
- #ifdef NOISY_WIDGET_LEAKS
- gNumWidgets--;
- printf("WIDGETS- = %d\n", gNumWidgets);
- #endif
- delete mOriginalBounds;
- }
- //-------------------------------------------------------------------------
- //
- // Basic create.
- //
- //-------------------------------------------------------------------------
- void nsBaseWidget::BaseCreate(nsIWidget* aParent,
- nsWidgetInitData* aInitData)
- {
- static bool gDisableNativeThemeCached = false;
- if (!gDisableNativeThemeCached) {
- Preferences::AddBoolVarCache(&gDisableNativeTheme,
- "mozilla.widget.disable-native-theme",
- gDisableNativeTheme);
- gDisableNativeThemeCached = true;
- }
- // keep a reference to the device context
- if (nullptr != aInitData) {
- mWindowType = aInitData->mWindowType;
- mBorderStyle = aInitData->mBorderStyle;
- mPopupLevel = aInitData->mPopupLevel;
- mPopupType = aInitData->mPopupHint;
- }
- if (aParent) {
- aParent->AddChild(this);
- }
- }
- //-------------------------------------------------------------------------
- //
- // Accessor functions to get/set the client data
- //
- //-------------------------------------------------------------------------
- nsIWidgetListener* nsBaseWidget::GetWidgetListener()
- {
- return mWidgetListener;
- }
- void nsBaseWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
- {
- mWidgetListener = aWidgetListener;
- }
- already_AddRefed<nsIWidget>
- nsBaseWidget::CreateChild(const LayoutDeviceIntRect& aRect,
- nsWidgetInitData* aInitData,
- bool aForceUseIWidgetParent)
- {
- nsIWidget* parent = this;
- nsNativeWidget nativeParent = nullptr;
- if (!aForceUseIWidgetParent) {
- // Use only either parent or nativeParent, not both, to match
- // existing code. Eventually Create() should be divested of its
- // nativeWidget parameter.
- nativeParent = parent ? parent->GetNativeData(NS_NATIVE_WIDGET) : nullptr;
- parent = nativeParent ? nullptr : parent;
- MOZ_ASSERT(!parent || !nativeParent, "messed up logic");
- }
- nsCOMPtr<nsIWidget> widget;
- if (aInitData && aInitData->mWindowType == eWindowType_popup) {
- widget = AllocateChildPopupWidget();
- } else {
- static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
- widget = do_CreateInstance(kCChildCID);
- }
- if (widget &&
- NS_SUCCEEDED(widget->Create(parent, nativeParent, aRect, aInitData))) {
- return widget.forget();
- }
- return nullptr;
- }
- // Attach a view to our widget which we'll send events to.
- void
- nsBaseWidget::AttachViewToTopLevel(bool aUseAttachedEvents)
- {
- NS_ASSERTION((mWindowType == eWindowType_toplevel ||
- mWindowType == eWindowType_dialog ||
- mWindowType == eWindowType_invisible ||
- mWindowType == eWindowType_child),
- "Can't attach to window of that type");
- mUseAttachedEvents = aUseAttachedEvents;
- }
- nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener()
- {
- return mAttachedWidgetListener;
- }
- nsIWidgetListener* nsBaseWidget::GetPreviouslyAttachedWidgetListener()
- {
- return mPreviouslyAttachedWidgetListener;
- }
- void nsBaseWidget::SetPreviouslyAttachedWidgetListener(nsIWidgetListener* aListener)
- {
- mPreviouslyAttachedWidgetListener = aListener;
- }
- void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener)
- {
- mAttachedWidgetListener = aListener;
- }
- //-------------------------------------------------------------------------
- //
- // Close this nsBaseWidget
- //
- //-------------------------------------------------------------------------
- void nsBaseWidget::Destroy()
- {
- // Just in case our parent is the only ref to us
- nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
- // disconnect from the parent
- nsIWidget *parent = GetParent();
- if (parent) {
- parent->RemoveChild(this);
- }
- #if defined(XP_WIN)
- // Allow our scroll capture container to be cleaned up, if we have one.
- mScrollCaptureContainer = nullptr;
- #endif
- }
- //-------------------------------------------------------------------------
- //
- // Set this nsBaseWidget's parent
- //
- //-------------------------------------------------------------------------
- NS_IMETHODIMP nsBaseWidget::SetParent(nsIWidget* aNewParent)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- //-------------------------------------------------------------------------
- //
- // Get this nsBaseWidget parent
- //
- //-------------------------------------------------------------------------
- nsIWidget* nsBaseWidget::GetParent(void)
- {
- return nullptr;
- }
- //-------------------------------------------------------------------------
- //
- // Get this nsBaseWidget top level widget
- //
- //-------------------------------------------------------------------------
- nsIWidget* nsBaseWidget::GetTopLevelWidget()
- {
- nsIWidget *topLevelWidget = nullptr, *widget = this;
- while (widget) {
- topLevelWidget = widget;
- widget = widget->GetParent();
- }
- return topLevelWidget;
- }
- //-------------------------------------------------------------------------
- //
- // Get this nsBaseWidget's top (non-sheet) parent (if it's a sheet)
- //
- //-------------------------------------------------------------------------
- nsIWidget* nsBaseWidget::GetSheetWindowParent(void)
- {
- return nullptr;
- }
- float nsBaseWidget::GetDPI()
- {
- return 96.0f;
- }
- CSSToLayoutDeviceScale nsIWidget::GetDefaultScale()
- {
- double devPixelsPerCSSPixel = DefaultScaleOverride();
- if (devPixelsPerCSSPixel <= 0.0) {
- devPixelsPerCSSPixel = GetDefaultScaleInternal();
- }
- return CSSToLayoutDeviceScale(devPixelsPerCSSPixel);
- }
- /* static */
- double nsIWidget::DefaultScaleOverride()
- {
- // The number of device pixels per CSS pixel. A value <= 0 means choose
- // automatically based on the DPI. A positive value is used as-is. This effectively
- // controls the size of a CSS "px".
- double devPixelsPerCSSPixel = -1.0;
- nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
- if (!prefString.IsEmpty()) {
- devPixelsPerCSSPixel = PR_strtod(prefString, nullptr);
- }
- return devPixelsPerCSSPixel;
- }
- //-------------------------------------------------------------------------
- //
- // Add a child to the list of children
- //
- //-------------------------------------------------------------------------
- void nsBaseWidget::AddChild(nsIWidget* aChild)
- {
- MOZ_ASSERT(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
- "aChild not properly removed from its old child list");
- if (!mFirstChild) {
- mFirstChild = mLastChild = aChild;
- } else {
- // append to the list
- MOZ_ASSERT(mLastChild);
- MOZ_ASSERT(!mLastChild->GetNextSibling());
- mLastChild->SetNextSibling(aChild);
- aChild->SetPrevSibling(mLastChild);
- mLastChild = aChild;
- }
- }
- //-------------------------------------------------------------------------
- //
- // Remove a child from the list of children
- //
- //-------------------------------------------------------------------------
- void nsBaseWidget::RemoveChild(nsIWidget* aChild)
- {
- #ifdef DEBUG
- MOZ_RELEASE_ASSERT(aChild->GetParent() == this, "Not one of our kids!");
- #endif
- if (mLastChild == aChild) {
- mLastChild = mLastChild->GetPrevSibling();
- }
- if (mFirstChild == aChild) {
- mFirstChild = mFirstChild->GetNextSibling();
- }
- // Now remove from the list. Make sure that we pass ownership of the tail
- // of the list correctly before we have aChild let go of it.
- nsIWidget* prev = aChild->GetPrevSibling();
- nsIWidget* next = aChild->GetNextSibling();
- if (prev) {
- prev->SetNextSibling(next);
- }
- if (next) {
- next->SetPrevSibling(prev);
- }
- aChild->SetNextSibling(nullptr);
- aChild->SetPrevSibling(nullptr);
- }
- //-------------------------------------------------------------------------
- //
- // Sets widget's position within its parent's child list.
- //
- //-------------------------------------------------------------------------
- void nsBaseWidget::SetZIndex(int32_t aZIndex)
- {
- // Hold a ref to ourselves just in case, since we're going to remove
- // from our parent.
- nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
- mZIndex = aZIndex;
- // reorder this child in its parent's list.
- nsBaseWidget* parent = static_cast<nsBaseWidget*>(GetParent());
- if (parent) {
- parent->RemoveChild(this);
- // Scope sib outside the for loop so we can check it afterward
- nsIWidget* sib = parent->GetFirstChild();
- for ( ; sib; sib = sib->GetNextSibling()) {
- int32_t childZIndex = GetZIndex();
- if (aZIndex < childZIndex) {
- // Insert ourselves before sib
- nsIWidget* prev = sib->GetPrevSibling();
- mNextSibling = sib;
- mPrevSibling = prev;
- sib->SetPrevSibling(this);
- if (prev) {
- prev->SetNextSibling(this);
- } else {
- NS_ASSERTION(sib == parent->mFirstChild, "Broken child list");
- // We've taken ownership of sib, so it's safe to have parent let
- // go of it
- parent->mFirstChild = this;
- }
- PlaceBehind(eZPlacementBelow, sib, false);
- break;
- }
- }
- // were we added to the list?
- if (!sib) {
- parent->AddChild(this);
- }
- }
- }
- //-------------------------------------------------------------------------
- //
- // Maximize, minimize or restore the window. The BaseWidget implementation
- // merely stores the state.
- //
- //-------------------------------------------------------------------------
- void
- nsBaseWidget::SetSizeMode(nsSizeMode aMode)
- {
- MOZ_ASSERT(aMode == nsSizeMode_Normal ||
- aMode == nsSizeMode_Minimized ||
- aMode == nsSizeMode_Maximized ||
- aMode == nsSizeMode_Fullscreen);
- mSizeMode = aMode;
- }
- //-------------------------------------------------------------------------
- //
- // Get this component cursor
- //
- //-------------------------------------------------------------------------
- nsCursor nsBaseWidget::GetCursor()
- {
- return mCursor;
- }
- NS_IMETHODIMP nsBaseWidget::SetCursor(nsCursor aCursor)
- {
- mCursor = aCursor;
- return NS_OK;
- }
- NS_IMETHODIMP nsBaseWidget::SetCursor(imgIContainer* aCursor,
- uint32_t aHotspotX, uint32_t aHotspotY)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- //-------------------------------------------------------------------------
- //
- // Window transparency methods
- //
- //-------------------------------------------------------------------------
- void nsBaseWidget::SetTransparencyMode(nsTransparencyMode aMode) {
- }
- nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
- return eTransparencyOpaque;
- }
- bool
- nsBaseWidget::IsWindowClipRegionEqual(const nsTArray<LayoutDeviceIntRect>& aRects)
- {
- return mClipRects &&
- mClipRectCount == aRects.Length() &&
- memcmp(mClipRects.get(), aRects.Elements(), sizeof(LayoutDeviceIntRect)*mClipRectCount) == 0;
- }
- void
- nsBaseWidget::StoreWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects)
- {
- mClipRectCount = aRects.Length();
- mClipRects = MakeUnique<LayoutDeviceIntRect[]>(mClipRectCount);
- if (mClipRects) {
- memcpy(mClipRects.get(), aRects.Elements(), sizeof(LayoutDeviceIntRect)*mClipRectCount);
- }
- }
- void
- nsBaseWidget::GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects)
- {
- if (mClipRects) {
- aRects->AppendElements(mClipRects.get(), mClipRectCount);
- } else {
- aRects->AppendElement(LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height));
- }
- }
- const LayoutDeviceIntRegion
- nsBaseWidget::RegionFromArray(const nsTArray<LayoutDeviceIntRect>& aRects)
- {
- LayoutDeviceIntRegion region;
- for (uint32_t i = 0; i < aRects.Length(); ++i) {
- region.Or(region, aRects[i]);
- }
- return region;
- }
- void
- nsBaseWidget::ArrayFromRegion(const LayoutDeviceIntRegion& aRegion,
- nsTArray<LayoutDeviceIntRect>& aRects)
- {
- for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
- aRects.AppendElement(iter.Get());
- }
- }
- nsresult
- nsBaseWidget::SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
- bool aIntersectWithExisting)
- {
- if (!aIntersectWithExisting) {
- StoreWindowClipRegion(aRects);
- } else {
- // get current rects
- nsTArray<LayoutDeviceIntRect> currentRects;
- GetWindowClipRegion(¤tRects);
- // create region from them
- LayoutDeviceIntRegion currentRegion = RegionFromArray(currentRects);
- // create region from new rects
- LayoutDeviceIntRegion newRegion = RegionFromArray(aRects);
- // intersect regions
- LayoutDeviceIntRegion intersection;
- intersection.And(currentRegion, newRegion);
- // create int rect array from intersection
- nsTArray<LayoutDeviceIntRect> rects;
- ArrayFromRegion(intersection, rects);
- // store
- StoreWindowClipRegion(rects);
- }
- return NS_OK;
- }
- //-------------------------------------------------------------------------
- //
- // Hide window borders/decorations for this widget
- //
- //-------------------------------------------------------------------------
- NS_IMETHODIMP nsBaseWidget::HideWindowChrome(bool aShouldHide)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- /* virtual */ void
- nsBaseWidget::PerformFullscreenTransition(FullscreenTransitionStage aStage,
- uint16_t aDuration,
- nsISupports* aData,
- nsIRunnable* aCallback)
- {
- MOZ_ASSERT_UNREACHABLE(
- "Should never call PerformFullscreenTransition on nsBaseWidget");
- }
- //-------------------------------------------------------------------------
- //
- // Put the window into full-screen mode
- //
- //-------------------------------------------------------------------------
- void
- nsBaseWidget::InfallibleMakeFullScreen(bool aFullScreen, nsIScreen* aScreen)
- {
- HideWindowChrome(aFullScreen);
- if (aFullScreen) {
- if (!mOriginalBounds) {
- mOriginalBounds = new LayoutDeviceIntRect();
- }
- *mOriginalBounds = GetScreenBounds();
- // Move to top-left corner of screen and size to the screen dimensions
- nsCOMPtr<nsIScreen> screen = aScreen;
- if (!screen) {
- screen = GetWidgetScreen();
- }
- if (screen) {
- int32_t left, top, width, height;
- if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
- Resize(left, top, width, height, true);
- }
- }
- } else if (mOriginalBounds) {
- if (BoundsUseDesktopPixels()) {
- DesktopRect deskRect = *mOriginalBounds / GetDesktopToDeviceScale();
- Resize(deskRect.x, deskRect.y, deskRect.width, deskRect.height, true);
- } else {
- Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
- mOriginalBounds->height, true);
- }
- }
- }
- nsresult
- nsBaseWidget::MakeFullScreen(bool aFullScreen, nsIScreen* aScreen)
- {
- InfallibleMakeFullScreen(aFullScreen, aScreen);
- return NS_OK;
- }
- nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
- nsBaseWidget* aWidget, gfxContext* aTarget,
- BufferMode aDoubleBuffering, ScreenRotation aRotation)
- : mWidget(aWidget)
- {
- LayerManager* lm = mWidget->GetLayerManager();
- NS_ASSERTION(!lm || lm->GetBackendType() == LayersBackend::LAYERS_BASIC,
- "AutoLayerManagerSetup instantiated for non-basic layer backend!");
- if (lm) {
- mLayerManager = lm->AsBasicLayerManager();
- if (mLayerManager) {
- mLayerManager->SetDefaultTarget(aTarget);
- mLayerManager->SetDefaultTargetConfiguration(aDoubleBuffering, aRotation);
- }
- }
- }
- nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
- {
- if (mLayerManager) {
- mLayerManager->SetDefaultTarget(nullptr);
- mLayerManager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, ROTATION_0);
- }
- }
- bool nsBaseWidget::IsSmallPopup() const
- {
- return mWindowType == eWindowType_popup && mPopupType != ePopupTypePanel;
- }
- bool
- nsBaseWidget::ComputeShouldAccelerate()
- {
- return gfx::gfxConfig::IsEnabled(gfx::Feature::HW_COMPOSITING) &&
- WidgetTypeSupportsAcceleration();
- }
- bool
- nsBaseWidget::UseAPZ()
- {
- return (gfxPlatform::AsyncPanZoomEnabled() &&
- (WindowType() == eWindowType_toplevel || WindowType() == eWindowType_child));
- }
- void nsBaseWidget::CreateCompositor()
- {
- LayoutDeviceIntRect rect = GetBounds();
- CreateCompositor(rect.width, rect.height);
- }
- already_AddRefed<GeckoContentController>
- nsBaseWidget::CreateRootContentController()
- {
- RefPtr<GeckoContentController> controller = new ChromeProcessController(this, mAPZEventState, mAPZC);
- return controller.forget();
- }
- void nsBaseWidget::ConfigureAPZCTreeManager()
- {
- MOZ_ASSERT(mAPZC);
- ConfigureAPZControllerThread();
- mAPZC->SetDPI(GetDPI());
- RefPtr<IAPZCTreeManager> treeManager = mAPZC; // for capture by the lambdas
- ContentReceivedInputBlockCallback callback(
- [treeManager](const ScrollableLayerGuid& aGuid,
- uint64_t aInputBlockId,
- bool aPreventDefault)
- {
- MOZ_ASSERT(NS_IsMainThread());
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod
- <uint64_t, bool>(treeManager,
- &IAPZCTreeManager::ContentReceivedInputBlock,
- aInputBlockId,
- aPreventDefault));
- });
- mAPZEventState = new APZEventState(this, mozilla::Move(callback));
- mSetAllowedTouchBehaviorCallback = [treeManager](uint64_t aInputBlockId,
- const nsTArray<TouchBehaviorFlags>& aFlags)
- {
- MOZ_ASSERT(NS_IsMainThread());
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod
- <uint64_t,
- StoreCopyPassByLRef<nsTArray<TouchBehaviorFlags>>>(treeManager,
- &IAPZCTreeManager::SetAllowedTouchBehavior,
- aInputBlockId, aFlags));
- };
- mRootContentController = CreateRootContentController();
- if (mRootContentController) {
- mCompositorSession->SetContentController(mRootContentController);
- }
- // When APZ is enabled, we can actually enable raw touch events because we
- // have code that can deal with them properly. If APZ is not enabled, this
- // function doesn't get called.
- if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) ||
- Preferences::GetBool("dom.w3c_pointer_events.enabled", false)) {
- RegisterTouchWindow();
- }
- }
- void nsBaseWidget::ConfigureAPZControllerThread()
- {
- // By default the controller thread is the main thread.
- APZThreadUtils::SetControllerThread(MessageLoop::current());
- }
- void
- nsBaseWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
- const nsTArray<ScrollableLayerGuid>& aTargets) const
- {
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod
- <uint64_t, StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>(mAPZC,
- &IAPZCTreeManager::SetTargetAPZC,
- aInputBlockId, aTargets));
- }
- void
- nsBaseWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
- const FrameMetrics::ViewID& aViewId,
- const Maybe<ZoomConstraints>& aConstraints)
- {
- if (!mCompositorSession || !mAPZC) {
- if (mInitialZoomConstraints) {
- MOZ_ASSERT(mInitialZoomConstraints->mPresShellID == aPresShellId);
- MOZ_ASSERT(mInitialZoomConstraints->mViewID == aViewId);
- if (!aConstraints) {
- mInitialZoomConstraints.reset();
- }
- }
- if (aConstraints) {
- // We have some constraints, but the compositor and APZC aren't created yet.
- // Save these so we can use them later.
- mInitialZoomConstraints = Some(InitialZoomConstraints(aPresShellId, aViewId, aConstraints.ref()));
- }
- return;
- }
- uint64_t layersId = mCompositorSession->RootLayerTreeId();
- mAPZC->UpdateZoomConstraints(ScrollableLayerGuid(layersId, aPresShellId, aViewId),
- aConstraints);
- }
- bool
- nsBaseWidget::AsyncPanZoomEnabled() const
- {
- return !!mAPZC;
- }
- nsEventStatus
- nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent,
- const ScrollableLayerGuid& aGuid,
- uint64_t aInputBlockId,
- nsEventStatus aApzResponse)
- {
- MOZ_ASSERT(NS_IsMainThread());
- InputAPZContext context(aGuid, aInputBlockId, aApzResponse);
- // If this is an event that the APZ has targeted to an APZC in the root
- // process, apply that APZC's callback-transform before dispatching the
- // event. If the event is instead targeted to an APZC in the child process,
- // the transform will be applied in the child process before dispatching
- // the event there (see e.g. TabChild::RecvRealTouchEvent()).
- if (aGuid.mLayersId == mCompositorSession->RootLayerTreeId()) {
- APZCCallbackHelper::ApplyCallbackTransform(*aEvent, aGuid,
- GetDefaultScale());
- }
- // Make a copy of the original event for the APZCCallbackHelper helpers that
- // we call later, because the event passed to DispatchEvent can get mutated in
- // ways that we don't want (i.e. touch points can get stripped out).
- nsEventStatus status;
- UniquePtr<WidgetEvent> original(aEvent->Duplicate());
- DispatchEvent(aEvent, status);
- if (mAPZC && !context.WasRoutedToChildProcess() && aInputBlockId) {
- // EventStateManager did not route the event into the child process.
- // It's safe to communicate to APZ that the event has been processed.
- // TODO: Eventually we'll be able to move the SendSetTargetAPZCNotification
- // call into APZEventState::Process*Event() as well.
- if (WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent()) {
- if (touchEvent->mMessage == eTouchStart) {
- if (gfxPrefs::TouchActionEnabled()) {
- APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(this,
- GetDocument(), *(original->AsTouchEvent()), aInputBlockId,
- mSetAllowedTouchBehaviorCallback);
- }
- APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(),
- *(original->AsTouchEvent()), aGuid, aInputBlockId);
- }
- mAPZEventState->ProcessTouchEvent(*touchEvent, aGuid, aInputBlockId,
- aApzResponse, status);
- } else if (WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent()) {
- MOZ_ASSERT(wheelEvent->mFlags.mHandledByAPZ);
- APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(),
- *(original->AsWheelEvent()), aGuid, aInputBlockId);
- if (wheelEvent->mCanTriggerSwipe) {
- ReportSwipeStarted(aInputBlockId, wheelEvent->TriggersSwipe());
- }
- mAPZEventState->ProcessWheelEvent(*wheelEvent, aGuid, aInputBlockId);
- } else if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
- MOZ_ASSERT(mouseEvent->mFlags.mHandledByAPZ);
- APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(),
- *(original->AsMouseEvent()), aGuid, aInputBlockId);
- mAPZEventState->ProcessMouseEvent(*mouseEvent, aGuid, aInputBlockId);
- }
- }
- return status;
- }
- class DispatchWheelEventOnMainThread : public Runnable
- {
- public:
- DispatchWheelEventOnMainThread(const ScrollWheelInput& aWheelInput,
- nsBaseWidget* aWidget,
- nsEventStatus aAPZResult,
- uint64_t aInputBlockId,
- ScrollableLayerGuid aGuid)
- : mWheelInput(aWheelInput)
- , mWidget(aWidget)
- , mAPZResult(aAPZResult)
- , mInputBlockId(aInputBlockId)
- , mGuid(aGuid)
- {
- }
- NS_IMETHOD Run() override
- {
- WidgetWheelEvent wheelEvent = mWheelInput.ToWidgetWheelEvent(mWidget);
- mWidget->ProcessUntransformedAPZEvent(&wheelEvent, mGuid, mInputBlockId, mAPZResult);
- return NS_OK;
- }
- private:
- ScrollWheelInput mWheelInput;
- nsBaseWidget* mWidget;
- nsEventStatus mAPZResult;
- uint64_t mInputBlockId;
- ScrollableLayerGuid mGuid;
- };
- class DispatchWheelInputOnControllerThread : public Runnable
- {
- public:
- DispatchWheelInputOnControllerThread(const WidgetWheelEvent& aWheelEvent,
- IAPZCTreeManager* aAPZC,
- nsBaseWidget* aWidget)
- : mMainMessageLoop(MessageLoop::current())
- , mWheelInput(aWheelEvent)
- , mAPZC(aAPZC)
- , mWidget(aWidget)
- , mInputBlockId(0)
- {
- }
- NS_IMETHOD Run() override
- {
- nsEventStatus result = mAPZC->ReceiveInputEvent(mWheelInput, &mGuid, &mInputBlockId);
- if (result == nsEventStatus_eConsumeNoDefault) {
- return NS_OK;
- }
- RefPtr<Runnable> r = new DispatchWheelEventOnMainThread(mWheelInput, mWidget, result, mInputBlockId, mGuid);
- mMainMessageLoop->PostTask(r.forget());
- return NS_OK;
- }
- private:
- MessageLoop* mMainMessageLoop;
- ScrollWheelInput mWheelInput;
- RefPtr<IAPZCTreeManager> mAPZC;
- nsBaseWidget* mWidget;
- uint64_t mInputBlockId;
- ScrollableLayerGuid mGuid;
- };
- void
- nsBaseWidget::DispatchTouchInput(MultiTouchInput& aInput)
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (mAPZC) {
- MOZ_ASSERT(APZThreadUtils::IsControllerThread());
- uint64_t inputBlockId = 0;
- ScrollableLayerGuid guid;
- nsEventStatus result = mAPZC->ReceiveInputEvent(aInput, &guid, &inputBlockId);
- if (result == nsEventStatus_eConsumeNoDefault) {
- return;
- }
- WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this);
- ProcessUntransformedAPZEvent(&event, guid, inputBlockId, result);
- } else {
- WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this);
- nsEventStatus status;
- DispatchEvent(&event, status);
- }
- }
- nsEventStatus
- nsBaseWidget::DispatchInputEvent(WidgetInputEvent* aEvent)
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (mAPZC) {
- if (APZThreadUtils::IsControllerThread()) {
- uint64_t inputBlockId = 0;
- ScrollableLayerGuid guid;
- nsEventStatus result = mAPZC->ReceiveInputEvent(*aEvent, &guid, &inputBlockId);
- if (result == nsEventStatus_eConsumeNoDefault) {
- return result;
- }
- return ProcessUntransformedAPZEvent(aEvent, guid, inputBlockId, result);
- } else {
- WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
- if (wheelEvent) {
- RefPtr<Runnable> r = new DispatchWheelInputOnControllerThread(*wheelEvent, mAPZC, this);
- APZThreadUtils::RunOnControllerThread(r.forget());
- return nsEventStatus_eConsumeDoDefault;
- }
- MOZ_CRASH();
- }
- }
- nsEventStatus status;
- DispatchEvent(aEvent, status);
- return status;
- }
- void
- nsBaseWidget::DispatchEventToAPZOnly(mozilla::WidgetInputEvent* aEvent)
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (mAPZC) {
- MOZ_ASSERT(APZThreadUtils::IsControllerThread());
- uint64_t inputBlockId = 0;
- ScrollableLayerGuid guid;
- mAPZC->ReceiveInputEvent(*aEvent, &guid, &inputBlockId);
- }
- }
- nsIDocument*
- nsBaseWidget::GetDocument() const
- {
- if (mWidgetListener) {
- if (nsIPresShell* presShell = mWidgetListener->GetPresShell()) {
- return presShell->GetDocument();
- }
- }
- return nullptr;
- }
- void nsBaseWidget::CreateCompositorVsyncDispatcher()
- {
- // Parent directly listens to the vsync source whereas
- // child process communicate via IPC
- // Should be called AFTER gfxPlatform is initialized
- if (XRE_IsParentProcess()) {
- mCompositorVsyncDispatcher = new CompositorVsyncDispatcher();
- }
- }
- CompositorVsyncDispatcher*
- nsBaseWidget::GetCompositorVsyncDispatcher()
- {
- return mCompositorVsyncDispatcher;
- }
- void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
- {
- // This makes sure that gfxPlatforms gets initialized if it hasn't by now.
- gfxPlatform::GetPlatform();
- MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(),
- "This function assumes OMTC");
- MOZ_ASSERT(!mCompositorSession && !mCompositorBridgeChild,
- "Should have properly cleaned up the previous PCompositor pair beforehand");
- if (mCompositorBridgeChild) {
- mCompositorBridgeChild->Destroy();
- }
- // Recreating this is tricky, as we may still have an old and we need
- // to make sure it's properly destroyed by calling DestroyCompositor!
- // If we've already received a shutdown notification, don't try
- // create a new compositor.
- if (!mShutdownObserver) {
- return;
- }
- CreateCompositorVsyncDispatcher();
- RefPtr<ClientLayerManager> lm = new ClientLayerManager(this);
- bool useAPZ = UseAPZ();
- gfx::GPUProcessManager* gpu = gfx::GPUProcessManager::Get();
- mCompositorSession = gpu->CreateTopLevelCompositor(
- this,
- lm,
- GetDefaultScale(),
- useAPZ,
- UseExternalCompositingSurface(),
- gfx::IntSize(aWidth, aHeight));
- mCompositorBridgeChild = mCompositorSession->GetCompositorBridgeChild();
- mCompositorWidgetDelegate = mCompositorSession->GetCompositorWidgetDelegate();
- if (useAPZ) {
- mAPZC = mCompositorSession->GetAPZCTreeManager();
- ConfigureAPZCTreeManager();
- } else {
- mAPZC = nullptr;
- }
- if (mInitialZoomConstraints) {
- UpdateZoomConstraints(mInitialZoomConstraints->mPresShellID,
- mInitialZoomConstraints->mViewID,
- Some(mInitialZoomConstraints->mConstraints));
- mInitialZoomConstraints.reset();
- }
- ShadowLayerForwarder* lf = lm->AsShadowForwarder();
- // As long as we are creating a ClientLayerManager above lf must be non-null.
- MOZ_ASSERT(lf);
- if (lf) {
- TextureFactoryIdentifier textureFactoryIdentifier;
- PLayerTransactionChild* shadowManager = nullptr;
- nsTArray<LayersBackend> backendHints;
- gfxPlatform::GetPlatform()->GetCompositorBackends(ComputeShouldAccelerate(), backendHints);
- bool success = false;
- if (!backendHints.IsEmpty()) {
- shadowManager = mCompositorBridgeChild->SendPLayerTransactionConstructor(
- backendHints, 0, &textureFactoryIdentifier, &success);
- }
- if (!success) {
- NS_WARNING("Failed to create an OMT compositor.");
- DestroyCompositor();
- mLayerManager = nullptr;
- return;
- }
- lf->SetShadowManager(shadowManager);
- if (ClientLayerManager* clm = lm->AsClientLayerManager()) {
- clm->UpdateTextureFactoryIdentifier(textureFactoryIdentifier);
- }
- // Some popup or transparent widgets may use a different backend than the
- // compositors used with ImageBridge and VR (and more generally web content).
- if (WidgetTypeSupportsAcceleration()) {
- ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
- }
- }
- WindowUsesOMTC();
- mLayerManager = lm.forget();
- // Only track compositors for top-level windows, since other window types
- // may use the basic compositor.
- bool getCompositorFromThisWindow = (mWindowType == eWindowType_toplevel);
- if (getCompositorFromThisWindow) {
- gfxPlatform::GetPlatform()->NotifyCompositorCreated(mLayerManager->GetCompositorBackendType());
- }
- }
- void nsBaseWidget::NotifyRemoteCompositorSessionLost(CompositorSession* aSession)
- {
- MOZ_ASSERT(aSession == mCompositorSession);
- DestroyLayerManager();
- }
- bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
- {
- return gfxPlatform::UsesOffMainThreadCompositing();
- }
- LayerManager* nsBaseWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
- LayersBackend aBackendHint,
- LayerManagerPersistence aPersistence)
- {
- if (!mLayerManager) {
- if (!mShutdownObserver) {
- // We are shutting down, do not try to re-create a LayerManager
- return nullptr;
- }
- // Try to use an async compositor first, if possible
- if (ShouldUseOffMainThreadCompositing()) {
- // e10s uses the parameter to pass in the shadow manager from the TabChild
- // so we don't expect to see it there since this doesn't support e10s.
- NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
- CreateCompositor();
- }
- if (!mLayerManager) {
- mLayerManager = CreateBasicLayerManager();
- }
- }
- return mLayerManager;
- }
- LayerManager* nsBaseWidget::CreateBasicLayerManager()
- {
- return new BasicLayerManager(this);
- }
- CompositorBridgeChild* nsBaseWidget::GetRemoteRenderer()
- {
- return mCompositorBridgeChild;
- }
- already_AddRefed<gfx::DrawTarget>
- nsBaseWidget::StartRemoteDrawing()
- {
- return nullptr;
- }
- uint32_t
- nsBaseWidget::GetGLFrameBufferFormat()
- {
- return LOCAL_GL_RGBA;
- }
- //-------------------------------------------------------------------------
- //
- // Destroy the window
- //
- //-------------------------------------------------------------------------
- void nsBaseWidget::OnDestroy()
- {
- if (mTextEventDispatcher) {
- mTextEventDispatcher->OnDestroyWidget();
- // Don't release it until this widget actually released because after this
- // is called, TextEventDispatcher() may create it again.
- }
- // If this widget is being destroyed, let the APZ code know to drop references
- // to this widget. Callers of this function all should be holding a deathgrip
- // on this widget already.
- ReleaseContentController();
- }
- NS_IMETHODIMP nsBaseWidget::MoveClient(double aX, double aY)
- {
- LayoutDeviceIntPoint clientOffset(GetClientOffset());
- // GetClientOffset returns device pixels; scale back to desktop pixels
- // if that's what this widget uses for the Move/Resize APIs
- if (BoundsUseDesktopPixels()) {
- DesktopPoint desktopOffset = clientOffset / GetDesktopToDeviceScale();
- return Move(aX - desktopOffset.x, aY - desktopOffset.y);
- } else {
- return Move(aX - clientOffset.x, aY - clientOffset.y);
- }
- }
- NS_IMETHODIMP nsBaseWidget::ResizeClient(double aWidth,
- double aHeight,
- bool aRepaint)
- {
- NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
- NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
- LayoutDeviceIntRect clientBounds = GetClientBounds();
- // GetClientBounds and mBounds are device pixels; scale back to desktop pixels
- // if that's what this widget uses for the Move/Resize APIs
- if (BoundsUseDesktopPixels()) {
- DesktopSize desktopDelta =
- (LayoutDeviceIntSize(mBounds.width, mBounds.height) -
- clientBounds.Size()) / GetDesktopToDeviceScale();
- return Resize(aWidth + desktopDelta.width, aHeight + desktopDelta.height,
- aRepaint);
- } else {
- return Resize(mBounds.width + (aWidth - clientBounds.width),
- mBounds.height + (aHeight - clientBounds.height), aRepaint);
- }
- }
- NS_IMETHODIMP nsBaseWidget::ResizeClient(double aX,
- double aY,
- double aWidth,
- double aHeight,
- bool aRepaint)
- {
- NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
- NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
- LayoutDeviceIntRect clientBounds = GetClientBounds();
- LayoutDeviceIntPoint clientOffset = GetClientOffset();
- if (BoundsUseDesktopPixels()) {
- DesktopToLayoutDeviceScale scale = GetDesktopToDeviceScale();
- DesktopPoint desktopOffset = clientOffset / scale;
- DesktopSize desktopDelta =
- (LayoutDeviceIntSize(mBounds.width, mBounds.height) -
- clientBounds.Size()) / scale;
- return Resize(aX - desktopOffset.x, aY - desktopOffset.y,
- aWidth + desktopDelta.width, aHeight + desktopDelta.height,
- aRepaint);
- } else {
- return Resize(aX - clientOffset.x, aY - clientOffset.y,
- aWidth + mBounds.width - clientBounds.width,
- aHeight + mBounds.height - clientBounds.height,
- aRepaint);
- }
- }
- //-------------------------------------------------------------------------
- //
- // Bounds
- //
- //-------------------------------------------------------------------------
- /**
- * If the implementation of nsWindow supports borders this method MUST be overridden
- *
- **/
- LayoutDeviceIntRect
- nsBaseWidget::GetClientBounds()
- {
- return GetBounds();
- }
- /**
- * If the implementation of nsWindow supports borders this method MUST be overridden
- *
- **/
- LayoutDeviceIntRect
- nsBaseWidget::GetBounds()
- {
- return mBounds;
- }
- /**
- * If the implementation of nsWindow uses a local coordinate system within the window,
- * this method must be overridden
- *
- **/
- LayoutDeviceIntRect
- nsBaseWidget::GetScreenBounds()
- {
- return GetBounds();
- }
- nsresult
- nsBaseWidget::GetRestoredBounds(LayoutDeviceIntRect& aRect)
- {
- if (SizeMode() != nsSizeMode_Normal) {
- return NS_ERROR_FAILURE;
- }
- aRect = GetScreenBounds();
- return NS_OK;
- }
- LayoutDeviceIntPoint
- nsBaseWidget::GetClientOffset()
- {
- return LayoutDeviceIntPoint(0, 0);
- }
- NS_IMETHODIMP
- nsBaseWidget::SetNonClientMargins(LayoutDeviceIntMargin &margins)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- uint32_t nsBaseWidget::GetMaxTouchPoints() const
- {
- return 0;
- }
- NS_IMETHODIMP
- nsBaseWidget::GetAttention(int32_t aCycleCount) {
- return NS_OK;
- }
- bool
- nsBaseWidget::HasPendingInputEvent()
- {
- return false;
- }
- NS_IMETHODIMP
- nsBaseWidget::SetIcon(const nsAString&)
- {
- return NS_OK;
- }
- bool
- nsBaseWidget::ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect)
- {
- return false;
- }
- /**
- * Modifies aFile to point at an icon file with the given name and suffix. The
- * suffix may correspond to a file extension with leading '.' if appropriate.
- * Returns true if the icon file exists and can be read.
- */
- static bool
- ResolveIconNameHelper(nsIFile *aFile,
- const nsAString &aIconName,
- const nsAString &aIconSuffix)
- {
- aFile->Append(NS_LITERAL_STRING("icons"));
- aFile->Append(NS_LITERAL_STRING("default"));
- aFile->Append(aIconName + aIconSuffix);
- bool readable;
- return NS_SUCCEEDED(aFile->IsReadable(&readable)) && readable;
- }
- /**
- * Resolve the given icon name into a local file object. This method is
- * intended to be called by subclasses of nsBaseWidget. aIconSuffix is a
- * platform specific icon file suffix (e.g., ".ico" under Win32).
- *
- * If no file is found matching the given parameters, then null is returned.
- */
- void
- nsBaseWidget::ResolveIconName(const nsAString &aIconName,
- const nsAString &aIconSuffix,
- nsIFile **aResult)
- {
- *aResult = nullptr;
- nsCOMPtr<nsIProperties> dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
- if (!dirSvc)
- return;
- // first check auxilary chrome directories
- nsCOMPtr<nsISimpleEnumerator> dirs;
- dirSvc->Get(NS_APP_CHROME_DIR_LIST, NS_GET_IID(nsISimpleEnumerator),
- getter_AddRefs(dirs));
- if (dirs) {
- bool hasMore;
- while (NS_SUCCEEDED(dirs->HasMoreElements(&hasMore)) && hasMore) {
- nsCOMPtr<nsISupports> element;
- dirs->GetNext(getter_AddRefs(element));
- if (!element)
- continue;
- nsCOMPtr<nsIFile> file = do_QueryInterface(element);
- if (!file)
- continue;
- if (ResolveIconNameHelper(file, aIconName, aIconSuffix)) {
- NS_ADDREF(*aResult = file);
- return;
- }
- }
- }
- // then check the main app chrome directory
- nsCOMPtr<nsIFile> file;
- dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
- getter_AddRefs(file));
- if (file && ResolveIconNameHelper(file, aIconName, aIconSuffix))
- NS_ADDREF(*aResult = file);
- }
- NS_IMETHODIMP
- nsBaseWidget::BeginResizeDrag(WidgetGUIEvent* aEvent,
- int32_t aHorizontal,
- int32_t aVertical)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- nsBaseWidget::BeginMoveDrag(WidgetMouseEvent* aEvent)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints)
- {
- mSizeConstraints = aConstraints;
- // We can't ensure that the size is honored at this point because we're
- // probably in the middle of a reflow.
- }
- const widget::SizeConstraints nsBaseWidget::GetSizeConstraints()
- {
- return mSizeConstraints;
- }
- // static
- nsIRollupListener*
- nsBaseWidget::GetActiveRollupListener()
- {
- // If set, then this is likely an <html:select> dropdown.
- if (gRollupListener)
- return gRollupListener;
- return nsXULPopupManager::GetInstance();
- }
- void
- nsBaseWidget::NotifyWindowDestroyed()
- {
- if (!mWidgetListener)
- return;
- nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
- nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
- if (xulWindow) {
- xulWindow->Destroy();
- }
- }
- void
- nsBaseWidget::NotifySizeMoveDone()
- {
- if (!mWidgetListener || mWidgetListener->GetXULWindow())
- return;
- nsIPresShell* presShell = mWidgetListener->GetPresShell();
- if (presShell) {
- presShell->WindowSizeMoveDone();
- }
- }
- void
- nsBaseWidget::NotifyWindowMoved(int32_t aX, int32_t aY)
- {
- if (mWidgetListener) {
- mWidgetListener->WindowMoved(this, aX, aY);
- }
- if (mIMEHasFocus && GetIMEUpdatePreference().WantPositionChanged()) {
- NotifyIME(IMENotification(IMEMessage::NOTIFY_IME_OF_POSITION_CHANGE));
- }
- }
- void
- nsBaseWidget::NotifySysColorChanged()
- {
- if (!mWidgetListener || mWidgetListener->GetXULWindow())
- return;
- nsIPresShell* presShell = mWidgetListener->GetPresShell();
- if (presShell) {
- presShell->SysColorChanged();
- }
- }
- void
- nsBaseWidget::NotifyThemeChanged()
- {
- if (!mWidgetListener || mWidgetListener->GetXULWindow())
- return;
- nsIPresShell* presShell = mWidgetListener->GetPresShell();
- if (presShell) {
- presShell->ThemeChanged();
- }
- }
- void
- nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
- UIStateChangeType aShowFocusRings)
- {
- if (nsIDocument* doc = GetDocument()) {
- nsPIDOMWindowOuter* win = doc->GetWindow();
- if (win) {
- win->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
- }
- }
- }
- NS_IMETHODIMP
- nsBaseWidget::NotifyIME(const IMENotification& aIMENotification)
- {
- switch (aIMENotification.mMessage) {
- case REQUEST_TO_COMMIT_COMPOSITION:
- case REQUEST_TO_CANCEL_COMPOSITION:
- // Currently, if native IME handler doesn't use TextEventDispatcher,
- // the request may be notified to mTextEventDispatcher or native IME
- // directly. Therefore, if mTextEventDispatcher has a composition,
- // the request should be handled by the mTextEventDispatcher.
- if (mTextEventDispatcher && mTextEventDispatcher->IsComposing()) {
- return mTextEventDispatcher->NotifyIME(aIMENotification);
- }
- // Otherwise, it should be handled by native IME.
- return NotifyIMEInternal(aIMENotification);
- default: {
- if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
- mIMEHasFocus = true;
- }
- EnsureTextEventDispatcher();
- // If the platform specific widget uses TextEventDispatcher for handling
- // native IME and keyboard events, IME event handler should be notified
- // of the notification via TextEventDispatcher. Otherwise, on the other
- // platforms which have not used TextEventDispatcher yet, IME event
- // handler should be notified by the old path (NotifyIMEInternal).
- nsresult rv = mTextEventDispatcher->NotifyIME(aIMENotification);
- nsresult rv2 = NotifyIMEInternal(aIMENotification);
- if (aIMENotification.mMessage == NOTIFY_IME_OF_BLUR) {
- mIMEHasFocus = false;
- }
- return rv2 == NS_ERROR_NOT_IMPLEMENTED ? rv : rv2;
- }
- }
- }
- void
- nsBaseWidget::EnsureTextEventDispatcher()
- {
- if (mTextEventDispatcher) {
- return;
- }
- mTextEventDispatcher = new TextEventDispatcher(this);
- }
- NS_IMETHODIMP_(nsIWidget::TextEventDispatcher*)
- nsBaseWidget::GetTextEventDispatcher()
- {
- EnsureTextEventDispatcher();
- return mTextEventDispatcher;
- }
- void*
- nsBaseWidget::GetPseudoIMEContext()
- {
- TextEventDispatcher* dispatcher = GetTextEventDispatcher();
- if (!dispatcher) {
- return nullptr;
- }
- return dispatcher->GetPseudoIMEContext();
- }
- NS_IMETHODIMP_(TextEventDispatcherListener*)
- nsBaseWidget::GetNativeTextEventDispatcherListener()
- {
- // TODO: If all platforms supported use of TextEventDispatcher for handling
- // native IME and keyboard events, this method should be removed since
- // in such case, this is overridden by all the subclasses.
- return nullptr;
- }
- void
- nsBaseWidget::ZoomToRect(const uint32_t& aPresShellId,
- const FrameMetrics::ViewID& aViewId,
- const CSSRect& aRect,
- const uint32_t& aFlags)
- {
- if (!mCompositorSession || !mAPZC) {
- return;
- }
- uint64_t layerId = mCompositorSession->RootLayerTreeId();
- mAPZC->ZoomToRect(ScrollableLayerGuid(layerId, aPresShellId, aViewId), aRect, aFlags);
- }
- #ifdef ACCESSIBILITY
- #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
- // defined in nsAppRunner.cpp
- extern const char* kAccessibilityLastRunDatePref;
- static inline uint32_t
- PRTimeToSeconds(PRTime t_usec)
- {
- PRTime usec_per_sec = PR_USEC_PER_SEC;
- return uint32_t(t_usec /= usec_per_sec);
- }
- #endif
- a11y::Accessible*
- nsBaseWidget::GetRootAccessible()
- {
- NS_ENSURE_TRUE(mWidgetListener, nullptr);
- nsIPresShell* presShell = mWidgetListener->GetPresShell();
- NS_ENSURE_TRUE(presShell, nullptr);
- // If container is null then the presshell is not active. This often happens
- // when a preshell is being held onto for fastback.
- nsPresContext* presContext = presShell->GetPresContext();
- NS_ENSURE_TRUE(presContext->GetContainerWeak(), nullptr);
- // Accessible creation might be not safe so use IsSafeToRunScript to
- // make sure it's not created at unsafe times.
- nsAccessibilityService* accService = GetOrCreateAccService();
- if (accService) {
- #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
- if (!mAccessibilityInUseFlag) {
- mAccessibilityInUseFlag = true;
- uint32_t now = PRTimeToSeconds(PR_Now());
- Preferences::SetInt(kAccessibilityLastRunDatePref, now);
- }
- #endif
- return accService->GetRootDocumentAccessible(presShell, nsContentUtils::IsSafeToRunScript());
- }
- return nullptr;
- }
- #endif // ACCESSIBILITY
- void
- nsBaseWidget::StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics)
- {
- if (!AsyncPanZoomEnabled()) {
- return;
- }
- MOZ_ASSERT(XRE_IsParentProcess() && mCompositorSession);
- int layersId = mCompositorSession->RootLayerTreeId();;
- ScrollableLayerGuid guid(layersId, aDragMetrics.mPresShellId, aDragMetrics.mViewId);
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod
- <ScrollableLayerGuid, AsyncDragMetrics>(mAPZC,
- &IAPZCTreeManager::StartScrollbarDrag,
- guid, aDragMetrics));
- }
- already_AddRefed<nsIScreen>
- nsBaseWidget::GetWidgetScreen()
- {
- nsCOMPtr<nsIScreenManager> screenManager;
- screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
- if (!screenManager) {
- return nullptr;
- }
- LayoutDeviceIntRect bounds = GetScreenBounds();
- DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale());
- nsCOMPtr<nsIScreen> screen;
- screenManager->ScreenForRect(deskBounds.x, deskBounds.y,
- deskBounds.width, deskBounds.height,
- getter_AddRefs(screen));
- return screen.forget();
- }
- nsresult
- nsIWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint, bool aLongTap,
- nsIObserver* aObserver)
- {
- AutoObserverNotifier notifier(aObserver, "touchtap");
- if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
- sPointerIdCounter = 0;
- }
- int pointerId = sPointerIdCounter;
- sPointerIdCounter++;
- nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_CONTACT,
- aPoint, 1.0, 90, nullptr);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!aLongTap) {
- return SynthesizeNativeTouchPoint(pointerId, TOUCH_REMOVE,
- aPoint, 0, 0, nullptr);
- }
- // initiate a long tap
- int elapse = Preferences::GetInt("ui.click_hold_context_menus.delay",
- TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC);
- if (!mLongTapTimer) {
- mLongTapTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
- if (NS_FAILED(rv)) {
- SynthesizeNativeTouchPoint(pointerId, TOUCH_CANCEL,
- aPoint, 0, 0, nullptr);
- return NS_ERROR_UNEXPECTED;
- }
- // Windows requires recuring events, so we set this to a smaller window
- // than the pref value.
- int timeout = elapse;
- if (timeout > TOUCH_INJECT_PUMP_TIMER_MSEC) {
- timeout = TOUCH_INJECT_PUMP_TIMER_MSEC;
- }
- mLongTapTimer->InitWithFuncCallback(OnLongTapTimerCallback, this,
- timeout,
- nsITimer::TYPE_REPEATING_SLACK);
- }
- // If we already have a long tap pending, cancel it. We only allow one long
- // tap to be active at a time.
- if (mLongTapTouchPoint) {
- SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
- mLongTapTouchPoint->mPosition, 0, 0, nullptr);
- }
- mLongTapTouchPoint =
- MakeUnique<LongTapInfo>(pointerId, aPoint,
- TimeDuration::FromMilliseconds(elapse),
- aObserver);
- notifier.SkipNotification(); // we'll do it in the long-tap callback
- return NS_OK;
- }
- // static
- void
- nsIWidget::OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure)
- {
- nsIWidget *self = static_cast<nsIWidget *>(aClosure);
- if ((self->mLongTapTouchPoint->mStamp + self->mLongTapTouchPoint->mDuration) >
- TimeStamp::Now()) {
- #ifdef XP_WIN
- // Windows needs us to keep pumping feedback to the digitizer, so update
- // the pointer id with the same position.
- self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
- TOUCH_CONTACT,
- self->mLongTapTouchPoint->mPosition,
- 1.0, 90, nullptr);
- #endif
- return;
- }
- AutoObserverNotifier notifier(self->mLongTapTouchPoint->mObserver, "touchtap");
- // finished, remove the touch point
- self->mLongTapTimer->Cancel();
- self->mLongTapTimer = nullptr;
- self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
- TOUCH_REMOVE,
- self->mLongTapTouchPoint->mPosition,
- 0, 0, nullptr);
- self->mLongTapTouchPoint = nullptr;
- }
- nsresult
- nsIWidget::ClearNativeTouchSequence(nsIObserver* aObserver)
- {
- AutoObserverNotifier notifier(aObserver, "cleartouch");
- if (!mLongTapTimer) {
- return NS_OK;
- }
- mLongTapTimer->Cancel();
- mLongTapTimer = nullptr;
- SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
- mLongTapTouchPoint->mPosition, 0, 0, nullptr);
- mLongTapTouchPoint = nullptr;
- return NS_OK;
- }
- MultiTouchInput
- nsBaseWidget::UpdateSynthesizedTouchState(MultiTouchInput* aState,
- uint32_t aTime,
- mozilla::TimeStamp aTimeStamp,
- uint32_t aPointerId,
- TouchPointerState aPointerState,
- LayoutDeviceIntPoint aPoint,
- double aPointerPressure,
- uint32_t aPointerOrientation)
- {
- ScreenIntPoint pointerScreenPoint = ViewAs<ScreenPixel>(aPoint,
- PixelCastJustification::LayoutDeviceIsScreenForBounds);
- // We can't dispatch *aState directly because (a) dispatching
- // it might inadvertently modify it and (b) in the case of touchend or
- // touchcancel events aState will hold the touches that are
- // still down whereas the input dispatched needs to hold the removed
- // touch(es). We use |inputToDispatch| for this purpose.
- MultiTouchInput inputToDispatch;
- inputToDispatch.mInputType = MULTITOUCH_INPUT;
- inputToDispatch.mTime = aTime;
- inputToDispatch.mTimeStamp = aTimeStamp;
- int32_t index = aState->IndexOfTouch((int32_t)aPointerId);
- if (aPointerState == TOUCH_CONTACT) {
- if (index >= 0) {
- // found an existing touch point, update it
- SingleTouchData& point = aState->mTouches[index];
- point.mScreenPoint = pointerScreenPoint;
- point.mRotationAngle = (float)aPointerOrientation;
- point.mForce = (float)aPointerPressure;
- inputToDispatch.mType = MultiTouchInput::MULTITOUCH_MOVE;
- } else {
- // new touch point, add it
- aState->mTouches.AppendElement(SingleTouchData(
- (int32_t)aPointerId,
- pointerScreenPoint,
- ScreenSize(0, 0),
- (float)aPointerOrientation,
- (float)aPointerPressure));
- inputToDispatch.mType = MultiTouchInput::MULTITOUCH_START;
- }
- inputToDispatch.mTouches = aState->mTouches;
- } else {
- MOZ_ASSERT(aPointerState == TOUCH_REMOVE || aPointerState == TOUCH_CANCEL);
- // a touch point is being lifted, so remove it from the stored list
- if (index >= 0) {
- aState->mTouches.RemoveElementAt(index);
- }
- inputToDispatch.mType = (aPointerState == TOUCH_REMOVE
- ? MultiTouchInput::MULTITOUCH_END
- : MultiTouchInput::MULTITOUCH_CANCEL);
- inputToDispatch.mTouches.AppendElement(SingleTouchData(
- (int32_t)aPointerId,
- pointerScreenPoint,
- ScreenSize(0, 0),
- (float)aPointerOrientation,
- (float)aPointerPressure));
- }
- return inputToDispatch;
- }
- void
- nsBaseWidget::RegisterPluginWindowForRemoteUpdates()
- {
- #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
- NS_NOTREACHED("nsBaseWidget::RegisterPluginWindowForRemoteUpdates not implemented!");
- return;
- #else
- MOZ_ASSERT(NS_IsMainThread());
- void* id = GetNativeData(NS_NATIVE_PLUGIN_ID);
- if (!id) {
- NS_WARNING("This is not a valid native widget!");
- return;
- }
- MOZ_ASSERT(sPluginWidgetList);
- sPluginWidgetList->Put(id, this);
- #endif
- }
- void
- nsBaseWidget::UnregisterPluginWindowForRemoteUpdates()
- {
- #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
- NS_NOTREACHED("nsBaseWidget::UnregisterPluginWindowForRemoteUpdates not implemented!");
- return;
- #else
- MOZ_ASSERT(NS_IsMainThread());
- void* id = GetNativeData(NS_NATIVE_PLUGIN_ID);
- if (!id) {
- NS_WARNING("This is not a valid native widget!");
- return;
- }
- MOZ_ASSERT(sPluginWidgetList);
- sPluginWidgetList->Remove(id);
- #endif
- }
- // static
- nsIWidget*
- nsIWidget::LookupRegisteredPluginWindow(uintptr_t aWindowID)
- {
- #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
- NS_NOTREACHED("nsBaseWidget::LookupRegisteredPluginWindow not implemented!");
- return nullptr;
- #else
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(sPluginWidgetList);
- return sPluginWidgetList->GetWeak((void*)aWindowID);
- #endif
- }
- // static
- void
- nsIWidget::UpdateRegisteredPluginWindowVisibility(uintptr_t aOwnerWidget,
- nsTArray<uintptr_t>& aPluginIds)
- {
- #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
- NS_NOTREACHED("nsBaseWidget::UpdateRegisteredPluginWindowVisibility not implemented!");
- return;
- #else
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(sPluginWidgetList);
- // Our visible list is associated with a compositor which is associated with
- // a specific top level window. We use the parent widget during iteration
- // to skip the plugin widgets owned by other top level windows.
- for (auto iter = sPluginWidgetList->Iter(); !iter.Done(); iter.Next()) {
- const void* windowId = iter.Key();
- nsIWidget* widget = iter.UserData();
- MOZ_ASSERT(windowId);
- MOZ_ASSERT(widget);
- if (!widget->Destroyed()) {
- if ((uintptr_t)widget->GetParent() == aOwnerWidget) {
- widget->Show(aPluginIds.Contains((uintptr_t)windowId));
- }
- }
- }
- #endif
- }
- #if defined(XP_WIN)
- // static
- void
- nsIWidget::CaptureRegisteredPlugins(uintptr_t aOwnerWidget)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(sPluginWidgetList);
- // Our visible list is associated with a compositor which is associated with
- // a specific top level window. We use the parent widget during iteration
- // to skip the plugin widgets owned by other top level windows.
- for (auto iter = sPluginWidgetList->Iter(); !iter.Done(); iter.Next()) {
- const void* windowId = iter.Key();
- nsIWidget* widget = iter.UserData();
- MOZ_ASSERT(windowId);
- MOZ_ASSERT(widget);
- if (!widget->Destroyed() && widget->IsVisible()) {
- if ((uintptr_t)widget->GetParent() == aOwnerWidget) {
- widget->UpdateScrollCapture();
- }
- }
- }
- }
- uint64_t
- nsBaseWidget::CreateScrollCaptureContainer()
- {
- mScrollCaptureContainer =
- LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
- if (!mScrollCaptureContainer) {
- NS_WARNING("Failed to create ImageContainer for widget image capture.");
- return ImageContainer::sInvalidAsyncContainerId;
- }
- return mScrollCaptureContainer->GetAsyncContainerID();
- }
- void
- nsBaseWidget::UpdateScrollCapture()
- {
- // Don't capture if no container or no size.
- if (!mScrollCaptureContainer || mBounds.width <= 0 || mBounds.height <= 0) {
- return;
- }
- // If the derived class cannot take a snapshot, for example due to clipping,
- // then it is responsible for creating a fallback. If null is returned, this
- // means that we want to keep the existing snapshot.
- RefPtr<gfx::SourceSurface> snapshot = CreateScrollSnapshot();
- if (!snapshot) {
- return;
- }
- ImageContainer::NonOwningImage holder(new SourceSurfaceImage(snapshot));
- AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
- imageList.AppendElement(holder);
- mScrollCaptureContainer->SetCurrentImages(imageList);
- }
- void
- nsBaseWidget::DefaultFillScrollCapture(DrawTarget* aSnapshotDrawTarget)
- {
- gfx::IntSize dtSize = aSnapshotDrawTarget->GetSize();
- aSnapshotDrawTarget->FillRect(
- gfx::Rect(0, 0, dtSize.width, dtSize.height),
- gfx::ColorPattern(gfx::Color::FromABGR(kScrollCaptureFillColor)),
- gfx::DrawOptions(1.f, gfx::CompositionOp::OP_SOURCE));
- aSnapshotDrawTarget->Flush();
- }
- #endif
- NS_IMETHODIMP_(nsIWidget::NativeIMEContext)
- nsIWidget::GetNativeIMEContext()
- {
- return NativeIMEContext(this);
- }
- nsresult
- nsIWidget::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
- nsIKeyEventInPluginCallback* aCallback)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- namespace mozilla {
- namespace widget {
- const char*
- ToChar(IMEMessage aIMEMessage)
- {
- switch (aIMEMessage) {
- case NOTIFY_IME_OF_NOTHING:
- return "NOTIFY_IME_OF_NOTHING";
- case NOTIFY_IME_OF_FOCUS:
- return "NOTIFY_IME_OF_FOCUS";
- case NOTIFY_IME_OF_BLUR:
- return "NOTIFY_IME_OF_BLUR";
- case NOTIFY_IME_OF_SELECTION_CHANGE:
- return "NOTIFY_IME_OF_SELECTION_CHANGE";
- case NOTIFY_IME_OF_TEXT_CHANGE:
- return "NOTIFY_IME_OF_TEXT_CHANGE";
- case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED:
- return "NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED";
- case NOTIFY_IME_OF_POSITION_CHANGE:
- return "NOTIFY_IME_OF_POSITION_CHANGE";
- case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
- return "NOTIFY_IME_OF_MOUSE_BUTTON_EVENT";
- case REQUEST_TO_COMMIT_COMPOSITION:
- return "REQUEST_TO_COMMIT_COMPOSITION";
- case REQUEST_TO_CANCEL_COMPOSITION:
- return "REQUEST_TO_CANCEL_COMPOSITION";
- default:
- return "Unexpected value";
- }
- }
- void
- NativeIMEContext::Init(nsIWidget* aWidget)
- {
- if (!aWidget) {
- mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
- mOriginProcessID = static_cast<uint64_t>(-1);
- return;
- }
- if (!XRE_IsContentProcess()) {
- mRawNativeIMEContext = reinterpret_cast<uintptr_t>(
- aWidget->GetNativeData(NS_RAW_NATIVE_IME_CONTEXT));
- mOriginProcessID = 0;
- return;
- }
- // If this is created in a child process, aWidget is an instance of
- // PuppetWidget which doesn't support NS_RAW_NATIVE_IME_CONTEXT.
- // Instead of that PuppetWidget::GetNativeIMEContext() returns cached
- // native IME context of the parent process.
- *this = aWidget->GetNativeIMEContext();
- }
- void
- NativeIMEContext::InitWithRawNativeIMEContext(void* aRawNativeIMEContext)
- {
- if (NS_WARN_IF(!aRawNativeIMEContext)) {
- mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
- mOriginProcessID = static_cast<uint64_t>(-1);
- return;
- }
- mRawNativeIMEContext = reinterpret_cast<uintptr_t>(aRawNativeIMEContext);
- mOriginProcessID =
- XRE_IsContentProcess() ? ContentChild::GetSingleton()->GetID() : 0;
- }
- void
- IMENotification::TextChangeDataBase::MergeWith(
- const IMENotification::TextChangeDataBase& aOther)
- {
- MOZ_ASSERT(aOther.IsValid(),
- "Merging data must store valid data");
- MOZ_ASSERT(aOther.mStartOffset <= aOther.mRemovedEndOffset,
- "end of removed text must be same or larger than start");
- MOZ_ASSERT(aOther.mStartOffset <= aOther.mAddedEndOffset,
- "end of added text must be same or larger than start");
- if (!IsValid()) {
- *this = aOther;
- return;
- }
- // |mStartOffset| and |mRemovedEndOffset| represent all replaced or removed
- // text ranges. I.e., mStartOffset should be the smallest offset of all
- // modified text ranges in old text. |mRemovedEndOffset| should be the
- // largest end offset in old text of all modified text ranges.
- // |mAddedEndOffset| represents the end offset of all inserted text ranges.
- // I.e., only this is an offset in new text.
- // In other words, between mStartOffset and |mRemovedEndOffset| of the
- // premodified text was already removed. And some text whose length is
- // |mAddedEndOffset - mStartOffset| is inserted to |mStartOffset|. I.e.,
- // this allows IME to mark dirty the modified text range with |mStartOffset|
- // and |mRemovedEndOffset| if IME stores all text of the focused editor and
- // to compute new text length with |mAddedEndOffset| and |mRemovedEndOffset|.
- // Additionally, IME can retrieve only the text between |mStartOffset| and
- // |mAddedEndOffset| for updating stored text.
- // For comparing new and old |mStartOffset|/|mRemovedEndOffset| values, they
- // should be adjusted to be in same text. The |newData.mStartOffset| and
- // |newData.mRemovedEndOffset| should be computed as in old text because
- // |mStartOffset| and |mRemovedEndOffset| represent the modified text range
- // in the old text but even if some text before the values of the newData
- // has already been modified, the values don't include the changes.
- // For comparing new and old |mAddedEndOffset| values, they should be
- // adjusted to be in same text. The |oldData.mAddedEndOffset| should be
- // computed as in the new text because |mAddedEndOffset| indicates the end
- // offset of inserted text in the new text but |oldData.mAddedEndOffset|
- // doesn't include any changes of the text before |newData.mAddedEndOffset|.
- const TextChangeDataBase& newData = aOther;
- const TextChangeDataBase oldData = *this;
- // mCausedOnlyByComposition should be true only when all changes are caused
- // by composition.
- mCausedOnlyByComposition =
- newData.mCausedOnlyByComposition && oldData.mCausedOnlyByComposition;
- // mIncludingChangesWithoutComposition should be true if at least one of
- // merged changes occurred without composition.
- mIncludingChangesWithoutComposition =
- newData.mIncludingChangesWithoutComposition ||
- oldData.mIncludingChangesWithoutComposition;
- // mIncludingChangesDuringComposition should be true when at least one of
- // the merged non-composition changes occurred during the latest composition.
- if (!newData.mCausedOnlyByComposition &&
- !newData.mIncludingChangesDuringComposition) {
- MOZ_ASSERT(newData.mIncludingChangesWithoutComposition);
- MOZ_ASSERT(mIncludingChangesWithoutComposition);
- // If new change is neither caused by composition nor occurred during
- // composition, set mIncludingChangesDuringComposition to false because
- // IME doesn't want outdated text changes as text change during current
- // composition.
- mIncludingChangesDuringComposition = false;
- } else {
- // Otherwise, set mIncludingChangesDuringComposition to true if either
- // oldData or newData includes changes during composition.
- mIncludingChangesDuringComposition =
- newData.mIncludingChangesDuringComposition ||
- oldData.mIncludingChangesDuringComposition;
- }
- if (newData.mStartOffset >= oldData.mAddedEndOffset) {
- // Case 1:
- // If new start is after old end offset of added text, it means that text
- // after the modified range is modified. Like:
- // added range of old change: +----------+
- // removed range of new change: +----------+
- // So, the old start offset is always the smaller offset.
- mStartOffset = oldData.mStartOffset;
- // The new end offset of removed text is moved by the old change and we
- // need to cancel the move of the old change for comparing the offsets in
- // same text because it doesn't make sensce to compare offsets in different
- // text.
- uint32_t newRemovedEndOffsetInOldText =
- newData.mRemovedEndOffset - oldData.Difference();
- mRemovedEndOffset =
- std::max(newRemovedEndOffsetInOldText, oldData.mRemovedEndOffset);
- // The new end offset of added text is always the larger offset.
- mAddedEndOffset = newData.mAddedEndOffset;
- return;
- }
- if (newData.mStartOffset >= oldData.mStartOffset) {
- // If new start is in the modified range, it means that new data changes
- // a part or all of the range.
- mStartOffset = oldData.mStartOffset;
- if (newData.mRemovedEndOffset >= oldData.mAddedEndOffset) {
- // Case 2:
- // If new end of removed text is greater than old end of added text, it
- // means that all or a part of modified range modified again and text
- // after the modified range is also modified. Like:
- // added range of old change: +----------+
- // removed range of new change: +----------+
- // So, the new removed end offset is moved by the old change and we need
- // to cancel the move of the old change for comparing the offsets in the
- // same text because it doesn't make sense to compare the offsets in
- // different text.
- uint32_t newRemovedEndOffsetInOldText =
- newData.mRemovedEndOffset - oldData.Difference();
- mRemovedEndOffset =
- std::max(newRemovedEndOffsetInOldText, oldData.mRemovedEndOffset);
- // The old end of added text is replaced by new change. So, it should be
- // same as the new start. On the other hand, the new added end offset is
- // always same or larger. Therefore, the merged end offset of added
- // text should be the new end offset of added text.
- mAddedEndOffset = newData.mAddedEndOffset;
- return;
- }
- // Case 3:
- // If new end of removed text is less than old end of added text, it means
- // that only a part of the modified range is modified again. Like:
- // added range of old change: +------------+
- // removed range of new change: +-----+
- // So, the new end offset of removed text should be same as the old end
- // offset of removed text. Therefore, the merged end offset of removed
- // text should be the old text change's |mRemovedEndOffset|.
- mRemovedEndOffset = oldData.mRemovedEndOffset;
- // The old end of added text is moved by new change. So, we need to cancel
- // the move of the new change for comparing the offsets in same text.
- uint32_t oldAddedEndOffsetInNewText =
- oldData.mAddedEndOffset + newData.Difference();
- mAddedEndOffset =
- std::max(newData.mAddedEndOffset, oldAddedEndOffsetInNewText);
- return;
- }
- if (newData.mRemovedEndOffset >= oldData.mStartOffset) {
- // If new end of removed text is greater than old start (and new start is
- // less than old start), it means that a part of modified range is modified
- // again and some new text before the modified range is also modified.
- MOZ_ASSERT(newData.mStartOffset < oldData.mStartOffset,
- "new start offset should be less than old one here");
- mStartOffset = newData.mStartOffset;
- if (newData.mRemovedEndOffset >= oldData.mAddedEndOffset) {
- // Case 4:
- // If new end of removed text is greater than old end of added text, it
- // means that all modified text and text after the modified range is
- // modified. Like:
- // added range of old change: +----------+
- // removed range of new change: +------------------+
- // So, the new end of removed text is moved by the old change. Therefore,
- // we need to cancel the move of the old change for comparing the offsets
- // in same text because it doesn't make sense to compare the offsets in
- // different text.
- uint32_t newRemovedEndOffsetInOldText =
- newData.mRemovedEndOffset - oldData.Difference();
- mRemovedEndOffset =
- std::max(newRemovedEndOffsetInOldText, oldData.mRemovedEndOffset);
- // The old end of added text is replaced by new change. So, the old end
- // offset of added text is same as new text change's start offset. Then,
- // new change's end offset of added text is always same or larger than
- // it. Therefore, merged end offset of added text is always the new end
- // offset of added text.
- mAddedEndOffset = newData.mAddedEndOffset;
- return;
- }
- // Case 5:
- // If new end of removed text is less than old end of added text, it
- // means that only a part of the modified range is modified again. Like:
- // added range of old change: +----------+
- // removed range of new change: +----------+
- // So, the new end of removed text should be same as old end of removed
- // text for preventing end of removed text to be modified. Therefore,
- // merged end offset of removed text is always the old end offset of removed
- // text.
- mRemovedEndOffset = oldData.mRemovedEndOffset;
- // The old end of added text is moved by this change. So, we need to
- // cancel the move of the new change for comparing the offsets in same text
- // because it doesn't make sense to compare the offsets in different text.
- uint32_t oldAddedEndOffsetInNewText =
- oldData.mAddedEndOffset + newData.Difference();
- mAddedEndOffset =
- std::max(newData.mAddedEndOffset, oldAddedEndOffsetInNewText);
- return;
- }
- // Case 6:
- // Otherwise, i.e., both new end of added text and new start are less than
- // old start, text before the modified range is modified. Like:
- // added range of old change: +----------+
- // removed range of new change: +----------+
- MOZ_ASSERT(newData.mStartOffset < oldData.mStartOffset,
- "new start offset should be less than old one here");
- mStartOffset = newData.mStartOffset;
- MOZ_ASSERT(newData.mRemovedEndOffset < oldData.mRemovedEndOffset,
- "new removed end offset should be less than old one here");
- mRemovedEndOffset = oldData.mRemovedEndOffset;
- // The end of added text should be adjusted with the new difference.
- uint32_t oldAddedEndOffsetInNewText =
- oldData.mAddedEndOffset + newData.Difference();
- mAddedEndOffset =
- std::max(newData.mAddedEndOffset, oldAddedEndOffsetInNewText);
- }
- #ifdef DEBUG
- // Let's test the code of merging multiple text change data in debug build
- // and crash if one of them fails because this feature is very complex but
- // cannot be tested with mochitest.
- void
- IMENotification::TextChangeDataBase::Test()
- {
- static bool gTestTextChangeEvent = true;
- if (!gTestTextChangeEvent) {
- return;
- }
- gTestTextChangeEvent = false;
- /****************************************************************************
- * Case 1
- ****************************************************************************/
- // Appending text
- MergeWith(TextChangeData(10, 10, 20, false, false));
- MergeWith(TextChangeData(20, 20, 35, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 1-1-1: mStartOffset should be the first offset");
- MOZ_ASSERT(mRemovedEndOffset == 10, // 20 - (20 - 10)
- "Test 1-1-2: mRemovedEndOffset should be the first end of removed text");
- MOZ_ASSERT(mAddedEndOffset == 35,
- "Test 1-1-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Removing text (longer line -> shorter line)
- MergeWith(TextChangeData(10, 20, 10, false, false));
- MergeWith(TextChangeData(10, 30, 10, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 1-2-1: mStartOffset should be the first offset");
- MOZ_ASSERT(mRemovedEndOffset == 40, // 30 + (10 - 20)
- "Test 1-2-2: mRemovedEndOffset should be the the last end of removed text "
- "with already removed length");
- MOZ_ASSERT(mAddedEndOffset == 10,
- "Test 1-2-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Removing text (shorter line -> longer line)
- MergeWith(TextChangeData(10, 20, 10, false, false));
- MergeWith(TextChangeData(10, 15, 10, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 1-3-1: mStartOffset should be the first offset");
- MOZ_ASSERT(mRemovedEndOffset == 25, // 15 + (10 - 20)
- "Test 1-3-2: mRemovedEndOffset should be the the last end of removed text "
- "with already removed length");
- MOZ_ASSERT(mAddedEndOffset == 10,
- "Test 1-3-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Appending text at different point (not sure if actually occurs)
- MergeWith(TextChangeData(10, 10, 20, false, false));
- MergeWith(TextChangeData(55, 55, 60, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 1-4-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 45, // 55 - (10 - 20)
- "Test 1-4-2: mRemovedEndOffset should be the the largest end of removed "
- "text without already added length");
- MOZ_ASSERT(mAddedEndOffset == 60,
- "Test 1-4-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Removing text at different point (not sure if actually occurs)
- MergeWith(TextChangeData(10, 20, 10, false, false));
- MergeWith(TextChangeData(55, 68, 55, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 1-5-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 78, // 68 - (10 - 20)
- "Test 1-5-2: mRemovedEndOffset should be the the largest end of removed "
- "text with already removed length");
- MOZ_ASSERT(mAddedEndOffset == 55,
- "Test 1-5-3: mAddedEndOffset should be the largest end of added text");
- Clear();
- // Replacing text and append text (becomes longer)
- MergeWith(TextChangeData(30, 35, 32, false, false));
- MergeWith(TextChangeData(32, 32, 40, false, false));
- MOZ_ASSERT(mStartOffset == 30,
- "Test 1-6-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 35, // 32 - (32 - 35)
- "Test 1-6-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 40,
- "Test 1-6-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Replacing text and append text (becomes shorter)
- MergeWith(TextChangeData(30, 35, 32, false, false));
- MergeWith(TextChangeData(32, 32, 33, false, false));
- MOZ_ASSERT(mStartOffset == 30,
- "Test 1-7-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 35, // 32 - (32 - 35)
- "Test 1-7-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 33,
- "Test 1-7-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Removing text and replacing text after first range (not sure if actually
- // occurs)
- MergeWith(TextChangeData(30, 35, 30, false, false));
- MergeWith(TextChangeData(32, 34, 48, false, false));
- MOZ_ASSERT(mStartOffset == 30,
- "Test 1-8-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 39, // 34 - (30 - 35)
- "Test 1-8-2: mRemovedEndOffset should be the the first end of removed text "
- "without already removed text");
- MOZ_ASSERT(mAddedEndOffset == 48,
- "Test 1-8-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Removing text and replacing text after first range (not sure if actually
- // occurs)
- MergeWith(TextChangeData(30, 35, 30, false, false));
- MergeWith(TextChangeData(32, 38, 36, false, false));
- MOZ_ASSERT(mStartOffset == 30,
- "Test 1-9-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 43, // 38 - (30 - 35)
- "Test 1-9-2: mRemovedEndOffset should be the the first end of removed text "
- "without already removed text");
- MOZ_ASSERT(mAddedEndOffset == 36,
- "Test 1-9-3: mAddedEndOffset should be the last end of added text");
- Clear();
- /****************************************************************************
- * Case 2
- ****************************************************************************/
- // Replacing text in around end of added text (becomes shorter) (not sure
- // if actually occurs)
- MergeWith(TextChangeData(50, 50, 55, false, false));
- MergeWith(TextChangeData(53, 60, 54, false, false));
- MOZ_ASSERT(mStartOffset == 50,
- "Test 2-1-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 55, // 60 - (55 - 50)
- "Test 2-1-2: mRemovedEndOffset should be the the last end of removed text "
- "without already added text length");
- MOZ_ASSERT(mAddedEndOffset == 54,
- "Test 2-1-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Replacing text around end of added text (becomes longer) (not sure
- // if actually occurs)
- MergeWith(TextChangeData(50, 50, 55, false, false));
- MergeWith(TextChangeData(54, 62, 68, false, false));
- MOZ_ASSERT(mStartOffset == 50,
- "Test 2-2-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 57, // 62 - (55 - 50)
- "Test 2-2-2: mRemovedEndOffset should be the the last end of removed text "
- "without already added text length");
- MOZ_ASSERT(mAddedEndOffset == 68,
- "Test 2-2-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Replacing text around end of replaced text (became shorter) (not sure if
- // actually occurs)
- MergeWith(TextChangeData(36, 48, 45, false, false));
- MergeWith(TextChangeData(43, 50, 49, false, false));
- MOZ_ASSERT(mStartOffset == 36,
- "Test 2-3-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 53, // 50 - (45 - 48)
- "Test 2-3-2: mRemovedEndOffset should be the the last end of removed text "
- "without already removed text length");
- MOZ_ASSERT(mAddedEndOffset == 49,
- "Test 2-3-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Replacing text around end of replaced text (became longer) (not sure if
- // actually occurs)
- MergeWith(TextChangeData(36, 52, 53, false, false));
- MergeWith(TextChangeData(43, 68, 61, false, false));
- MOZ_ASSERT(mStartOffset == 36,
- "Test 2-4-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 67, // 68 - (53 - 52)
- "Test 2-4-2: mRemovedEndOffset should be the the last end of removed text "
- "without already added text length");
- MOZ_ASSERT(mAddedEndOffset == 61,
- "Test 2-4-3: mAddedEndOffset should be the last end of added text");
- Clear();
- /****************************************************************************
- * Case 3
- ****************************************************************************/
- // Appending text in already added text (not sure if actually occurs)
- MergeWith(TextChangeData(10, 10, 20, false, false));
- MergeWith(TextChangeData(15, 15, 30, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 3-1-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 10,
- "Test 3-1-2: mRemovedEndOffset should be the the first end of removed text");
- MOZ_ASSERT(mAddedEndOffset == 35, // 20 + (30 - 15)
- "Test 3-1-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- // Replacing text in added text (not sure if actually occurs)
- MergeWith(TextChangeData(50, 50, 55, false, false));
- MergeWith(TextChangeData(52, 53, 56, false, false));
- MOZ_ASSERT(mStartOffset == 50,
- "Test 3-2-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 50,
- "Test 3-2-2: mRemovedEndOffset should be the the first end of removed text");
- MOZ_ASSERT(mAddedEndOffset == 58, // 55 + (56 - 53)
- "Test 3-2-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- // Replacing text in replaced text (became shorter) (not sure if actually
- // occurs)
- MergeWith(TextChangeData(36, 48, 45, false, false));
- MergeWith(TextChangeData(37, 38, 50, false, false));
- MOZ_ASSERT(mStartOffset == 36,
- "Test 3-3-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 48,
- "Test 3-3-2: mRemovedEndOffset should be the the first end of removed text");
- MOZ_ASSERT(mAddedEndOffset == 57, // 45 + (50 - 38)
- "Test 3-3-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- // Replacing text in replaced text (became longer) (not sure if actually
- // occurs)
- MergeWith(TextChangeData(32, 48, 53, false, false));
- MergeWith(TextChangeData(43, 50, 52, false, false));
- MOZ_ASSERT(mStartOffset == 32,
- "Test 3-4-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 48,
- "Test 3-4-2: mRemovedEndOffset should be the the last end of removed text "
- "without already added text length");
- MOZ_ASSERT(mAddedEndOffset == 55, // 53 + (52 - 50)
- "Test 3-4-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- // Replacing text in replaced text (became shorter) (not sure if actually
- // occurs)
- MergeWith(TextChangeData(36, 48, 50, false, false));
- MergeWith(TextChangeData(37, 49, 47, false, false));
- MOZ_ASSERT(mStartOffset == 36,
- "Test 3-5-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 48,
- "Test 3-5-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 48, // 50 + (47 - 49)
- "Test 3-5-3: mAddedEndOffset should be the first end of added text without "
- "removed text length by the new change");
- Clear();
- // Replacing text in replaced text (became longer) (not sure if actually
- // occurs)
- MergeWith(TextChangeData(32, 48, 53, false, false));
- MergeWith(TextChangeData(43, 50, 47, false, false));
- MOZ_ASSERT(mStartOffset == 32,
- "Test 3-6-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 48,
- "Test 3-6-2: mRemovedEndOffset should be the the last end of removed text "
- "without already added text length");
- MOZ_ASSERT(mAddedEndOffset == 50, // 53 + (47 - 50)
- "Test 3-6-3: mAddedEndOffset should be the first end of added text without "
- "removed text length by the new change");
- Clear();
- /****************************************************************************
- * Case 4
- ****************************************************************************/
- // Replacing text all of already append text (not sure if actually occurs)
- MergeWith(TextChangeData(50, 50, 55, false, false));
- MergeWith(TextChangeData(44, 66, 68, false, false));
- MOZ_ASSERT(mStartOffset == 44,
- "Test 4-1-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 61, // 66 - (55 - 50)
- "Test 4-1-2: mRemovedEndOffset should be the the last end of removed text "
- "without already added text length");
- MOZ_ASSERT(mAddedEndOffset == 68,
- "Test 4-1-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Replacing text around a point in which text was removed (not sure if
- // actually occurs)
- MergeWith(TextChangeData(50, 62, 50, false, false));
- MergeWith(TextChangeData(44, 66, 68, false, false));
- MOZ_ASSERT(mStartOffset == 44,
- "Test 4-2-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 78, // 66 - (50 - 62)
- "Test 4-2-2: mRemovedEndOffset should be the the last end of removed text "
- "without already removed text length");
- MOZ_ASSERT(mAddedEndOffset == 68,
- "Test 4-2-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Replacing text all replaced text (became shorter) (not sure if actually
- // occurs)
- MergeWith(TextChangeData(50, 62, 60, false, false));
- MergeWith(TextChangeData(49, 128, 130, false, false));
- MOZ_ASSERT(mStartOffset == 49,
- "Test 4-3-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 130, // 128 - (60 - 62)
- "Test 4-3-2: mRemovedEndOffset should be the the last end of removed text "
- "without already removed text length");
- MOZ_ASSERT(mAddedEndOffset == 130,
- "Test 4-3-3: mAddedEndOffset should be the last end of added text");
- Clear();
- // Replacing text all replaced text (became longer) (not sure if actually
- // occurs)
- MergeWith(TextChangeData(50, 61, 73, false, false));
- MergeWith(TextChangeData(44, 100, 50, false, false));
- MOZ_ASSERT(mStartOffset == 44,
- "Test 4-4-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 88, // 100 - (73 - 61)
- "Test 4-4-2: mRemovedEndOffset should be the the last end of removed text "
- "with already added text length");
- MOZ_ASSERT(mAddedEndOffset == 50,
- "Test 4-4-3: mAddedEndOffset should be the last end of added text");
- Clear();
- /****************************************************************************
- * Case 5
- ****************************************************************************/
- // Replacing text around start of added text (not sure if actually occurs)
- MergeWith(TextChangeData(50, 50, 55, false, false));
- MergeWith(TextChangeData(48, 52, 49, false, false));
- MOZ_ASSERT(mStartOffset == 48,
- "Test 5-1-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 50,
- "Test 5-1-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 52, // 55 + (52 - 49)
- "Test 5-1-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- // Replacing text around start of replaced text (became shorter) (not sure if
- // actually occurs)
- MergeWith(TextChangeData(50, 60, 58, false, false));
- MergeWith(TextChangeData(43, 50, 48, false, false));
- MOZ_ASSERT(mStartOffset == 43,
- "Test 5-2-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 60,
- "Test 5-2-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 56, // 58 + (48 - 50)
- "Test 5-2-3: mAddedEndOffset should be the first end of added text without "
- "removed text length by the new change");
- Clear();
- // Replacing text around start of replaced text (became longer) (not sure if
- // actually occurs)
- MergeWith(TextChangeData(50, 60, 68, false, false));
- MergeWith(TextChangeData(43, 55, 53, false, false));
- MOZ_ASSERT(mStartOffset == 43,
- "Test 5-3-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 60,
- "Test 5-3-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 66, // 68 + (53 - 55)
- "Test 5-3-3: mAddedEndOffset should be the first end of added text without "
- "removed text length by the new change");
- Clear();
- // Replacing text around start of replaced text (became shorter) (not sure if
- // actually occurs)
- MergeWith(TextChangeData(50, 60, 58, false, false));
- MergeWith(TextChangeData(43, 50, 128, false, false));
- MOZ_ASSERT(mStartOffset == 43,
- "Test 5-4-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 60,
- "Test 5-4-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 136, // 58 + (128 - 50)
- "Test 5-4-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- // Replacing text around start of replaced text (became longer) (not sure if
- // actually occurs)
- MergeWith(TextChangeData(50, 60, 68, false, false));
- MergeWith(TextChangeData(43, 55, 65, false, false));
- MOZ_ASSERT(mStartOffset == 43,
- "Test 5-5-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 60,
- "Test 5-5-2: mRemovedEndOffset should be the the first end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 78, // 68 + (65 - 55)
- "Test 5-5-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- /****************************************************************************
- * Case 6
- ****************************************************************************/
- // Appending text before already added text (not sure if actually occurs)
- MergeWith(TextChangeData(30, 30, 45, false, false));
- MergeWith(TextChangeData(10, 10, 20, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 6-1-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 30,
- "Test 6-1-2: mRemovedEndOffset should be the the largest end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 55, // 45 + (20 - 10)
- "Test 6-1-3: mAddedEndOffset should be the first end of added text with "
- "added text length by the new change");
- Clear();
- // Removing text before already removed text (not sure if actually occurs)
- MergeWith(TextChangeData(30, 35, 30, false, false));
- MergeWith(TextChangeData(10, 25, 10, false, false));
- MOZ_ASSERT(mStartOffset == 10,
- "Test 6-2-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 35,
- "Test 6-2-2: mRemovedEndOffset should be the the largest end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 15, // 30 - (25 - 10)
- "Test 6-2-3: mAddedEndOffset should be the first end of added text with "
- "removed text length by the new change");
- Clear();
- // Replacing text before already replaced text (not sure if actually occurs)
- MergeWith(TextChangeData(50, 65, 70, false, false));
- MergeWith(TextChangeData(13, 24, 15, false, false));
- MOZ_ASSERT(mStartOffset == 13,
- "Test 6-3-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 65,
- "Test 6-3-2: mRemovedEndOffset should be the the largest end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 61, // 70 + (15 - 24)
- "Test 6-3-3: mAddedEndOffset should be the first end of added text without "
- "removed text length by the new change");
- Clear();
- // Replacing text before already replaced text (not sure if actually occurs)
- MergeWith(TextChangeData(50, 65, 70, false, false));
- MergeWith(TextChangeData(13, 24, 36, false, false));
- MOZ_ASSERT(mStartOffset == 13,
- "Test 6-4-1: mStartOffset should be the smallest offset");
- MOZ_ASSERT(mRemovedEndOffset == 65,
- "Test 6-4-2: mRemovedEndOffset should be the the largest end of removed "
- "text");
- MOZ_ASSERT(mAddedEndOffset == 82, // 70 + (36 - 24)
- "Test 6-4-3: mAddedEndOffset should be the first end of added text without "
- "removed text length by the new change");
- Clear();
- }
- #endif // #ifdef DEBUG
- } // namespace widget
- } // namespace mozilla
- #ifdef DEBUG
- //////////////////////////////////////////////////////////////
- //
- // Convert a GUI event message code to a string.
- // Makes it a lot easier to debug events.
- //
- // See gtk/nsWidget.cpp and windows/nsWindow.cpp
- // for a DebugPrintEvent() function that uses
- // this.
- //
- //////////////////////////////////////////////////////////////
- /* static */ nsAutoString
- nsBaseWidget::debug_GuiEventToString(WidgetGUIEvent* aGuiEvent)
- {
- NS_ASSERTION(nullptr != aGuiEvent,"cmon, null gui event.");
- nsAutoString eventName(NS_LITERAL_STRING("UNKNOWN"));
- #define _ASSIGN_eventName(_value,_name)\
- case _value: eventName.AssignLiteral(_name) ; break
- switch(aGuiEvent->mMessage)
- {
- _ASSIGN_eventName(eBlur,"eBlur");
- _ASSIGN_eventName(eDrop,"eDrop");
- _ASSIGN_eventName(eDragEnter,"eDragEnter");
- _ASSIGN_eventName(eDragExit,"eDragExit");
- _ASSIGN_eventName(eDragOver,"eDragOver");
- _ASSIGN_eventName(eEditorInput,"eEditorInput");
- _ASSIGN_eventName(eFocus,"eFocus");
- _ASSIGN_eventName(eFocusIn,"eFocusIn");
- _ASSIGN_eventName(eFocusOut,"eFocusOut");
- _ASSIGN_eventName(eFormSelect,"eFormSelect");
- _ASSIGN_eventName(eFormChange,"eFormChange");
- _ASSIGN_eventName(eFormReset,"eFormReset");
- _ASSIGN_eventName(eFormSubmit,"eFormSubmit");
- _ASSIGN_eventName(eImageAbort,"eImageAbort");
- _ASSIGN_eventName(eLoadError,"eLoadError");
- _ASSIGN_eventName(eKeyDown,"eKeyDown");
- _ASSIGN_eventName(eKeyPress,"eKeyPress");
- _ASSIGN_eventName(eKeyUp,"eKeyUp");
- _ASSIGN_eventName(eMouseEnterIntoWidget,"eMouseEnterIntoWidget");
- _ASSIGN_eventName(eMouseExitFromWidget,"eMouseExitFromWidget");
- _ASSIGN_eventName(eMouseDown,"eMouseDown");
- _ASSIGN_eventName(eMouseUp,"eMouseUp");
- _ASSIGN_eventName(eMouseClick,"eMouseClick");
- _ASSIGN_eventName(eMouseAuxClick,"eMouseAuxClick");
- _ASSIGN_eventName(eMouseDoubleClick,"eMouseDoubleClick");
- _ASSIGN_eventName(eMouseMove,"eMouseMove");
- _ASSIGN_eventName(eLoad,"eLoad");
- _ASSIGN_eventName(ePopState,"ePopState");
- _ASSIGN_eventName(eBeforeScriptExecute,"eBeforeScriptExecute");
- _ASSIGN_eventName(eAfterScriptExecute,"eAfterScriptExecute");
- _ASSIGN_eventName(eUnload,"eUnload");
- _ASSIGN_eventName(eHashChange,"eHashChange");
- _ASSIGN_eventName(eReadyStateChange,"eReadyStateChange");
- _ASSIGN_eventName(eXULBroadcast, "eXULBroadcast");
- _ASSIGN_eventName(eXULCommandUpdate, "eXULCommandUpdate");
- #undef _ASSIGN_eventName
- default:
- {
- char buf[32];
- SprintfLiteral(buf,"UNKNOWN: %d",aGuiEvent->mMessage);
- CopyASCIItoUTF16(buf, eventName);
- }
- break;
- }
- return nsAutoString(eventName);
- }
- //////////////////////////////////////////////////////////////
- //
- // Code to deal with paint and event debug prefs.
- //
- //////////////////////////////////////////////////////////////
- struct PrefPair
- {
- const char * name;
- bool value;
- };
- static PrefPair debug_PrefValues[] =
- {
- { "nglayout.debug.crossing_event_dumping", false },
- { "nglayout.debug.event_dumping", false },
- { "nglayout.debug.invalidate_dumping", false },
- { "nglayout.debug.motion_event_dumping", false },
- { "nglayout.debug.paint_dumping", false },
- { "nglayout.debug.paint_flashing", false }
- };
- //////////////////////////////////////////////////////////////
- bool
- nsBaseWidget::debug_GetCachedBoolPref(const char * aPrefName)
- {
- NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
- for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
- {
- if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
- {
- return debug_PrefValues[i].value;
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////
- static void debug_SetCachedBoolPref(const char * aPrefName,bool aValue)
- {
- NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
- for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
- {
- if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
- {
- debug_PrefValues[i].value = aValue;
- return;
- }
- }
- NS_ASSERTION(false, "cmon, this code is not reached dude.");
- }
- //////////////////////////////////////////////////////////////
- class Debug_PrefObserver final : public nsIObserver {
- ~Debug_PrefObserver() {}
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIOBSERVER
- };
- NS_IMPL_ISUPPORTS(Debug_PrefObserver, nsIObserver)
- NS_IMETHODIMP
- Debug_PrefObserver::Observe(nsISupports* subject, const char* topic,
- const char16_t* data)
- {
- NS_ConvertUTF16toUTF8 prefName(data);
- bool value = Preferences::GetBool(prefName.get(), false);
- debug_SetCachedBoolPref(prefName.get(), value);
- return NS_OK;
- }
- //////////////////////////////////////////////////////////////
- /* static */ void
- debug_RegisterPrefCallbacks()
- {
- static bool once = true;
- if (!once) {
- return;
- }
- once = false;
- nsCOMPtr<nsIObserver> obs(new Debug_PrefObserver());
- for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++) {
- // Initialize the pref values
- debug_PrefValues[i].value =
- Preferences::GetBool(debug_PrefValues[i].name, false);
- if (obs) {
- // Register callbacks for when these change
- Preferences::AddStrongObserver(obs, debug_PrefValues[i].name);
- }
- }
- }
- //////////////////////////////////////////////////////////////
- static int32_t
- _GetPrintCount()
- {
- static int32_t sCount = 0;
- return ++sCount;
- }
- //////////////////////////////////////////////////////////////
- /* static */ bool
- nsBaseWidget::debug_WantPaintFlashing()
- {
- return debug_GetCachedBoolPref("nglayout.debug.paint_flashing");
- }
- //////////////////////////////////////////////////////////////
- /* static */ void
- nsBaseWidget::debug_DumpEvent(FILE * aFileOut,
- nsIWidget * aWidget,
- WidgetGUIEvent* aGuiEvent,
- const char* aWidgetName,
- int32_t aWindowID)
- {
- if (aGuiEvent->mMessage == eMouseMove) {
- if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping"))
- return;
- }
- if (aGuiEvent->mMessage == eMouseEnterIntoWidget ||
- aGuiEvent->mMessage == eMouseExitFromWidget) {
- if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping"))
- return;
- }
- if (!debug_GetCachedBoolPref("nglayout.debug.event_dumping"))
- return;
- NS_LossyConvertUTF16toASCII tempString(debug_GuiEventToString(aGuiEvent).get());
- fprintf(aFileOut,
- "%4d %-26s widget=%-8p name=%-12s id=0x%-6x refpt=%d,%d\n",
- _GetPrintCount(),
- tempString.get(),
- (void *) aWidget,
- aWidgetName,
- aWindowID,
- aGuiEvent->mRefPoint.x,
- aGuiEvent->mRefPoint.y);
- }
- //////////////////////////////////////////////////////////////
- /* static */ void
- nsBaseWidget::debug_DumpPaintEvent(FILE * aFileOut,
- nsIWidget * aWidget,
- const nsIntRegion & aRegion,
- const char * aWidgetName,
- int32_t aWindowID)
- {
- NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
- NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
- if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
- return;
- nsIntRect rect = aRegion.GetBounds();
- fprintf(aFileOut,
- "%4d PAINT widget=%p name=%-12s id=0x%-6x bounds-rect=%3d,%-3d %3d,%-3d",
- _GetPrintCount(),
- (void *) aWidget,
- aWidgetName,
- aWindowID,
- rect.x, rect.y, rect.width, rect.height
- );
- fprintf(aFileOut,"\n");
- }
- //////////////////////////////////////////////////////////////
- /* static */ void
- nsBaseWidget::debug_DumpInvalidate(FILE* aFileOut,
- nsIWidget* aWidget,
- const LayoutDeviceIntRect* aRect,
- const char* aWidgetName,
- int32_t aWindowID)
- {
- if (!debug_GetCachedBoolPref("nglayout.debug.invalidate_dumping"))
- return;
- NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
- NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
- fprintf(aFileOut,
- "%4d Invalidate widget=%p name=%-12s id=0x%-6x",
- _GetPrintCount(),
- (void *) aWidget,
- aWidgetName,
- aWindowID);
- if (aRect) {
- fprintf(aFileOut,
- " rect=%3d,%-3d %3d,%-3d",
- aRect->x, aRect->y, aRect->width, aRect->height);
- } else {
- fprintf(aFileOut,
- " rect=%-15s",
- "none");
- }
- fprintf(aFileOut, "\n");
- }
- //////////////////////////////////////////////////////////////
- #endif // DEBUG
|