1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "base/basictypes.h"
10 #include "ClientLayerManager.h"
11 #include "gfxPlatform.h"
12 #include "mozilla/dom/BrowserChild.h"
13 #include "mozilla/dom/TabGroup.h"
14 #include "mozilla/gfx/gfxVars.h"
15 #include "mozilla/Hal.h"
16 #include "mozilla/IMEStateManager.h"
17 #include "mozilla/layers/APZChild.h"
18 #include "mozilla/layers/PLayerTransactionChild.h"
19 #include "mozilla/layers/WebRenderLayerManager.h"
20 #include "mozilla/Preferences.h"
21 #include "mozilla/PresShell.h"
22 #include "mozilla/StaticPrefs_browser.h"
23 #include "mozilla/TextComposition.h"
24 #include "mozilla/TextEventDispatcher.h"
25 #include "mozilla/TextEvents.h"
26 #include "mozilla/Unused.h"
27 #include "BasicLayers.h"
28 #include "PuppetWidget.h"
29 #include "nsContentUtils.h"
30 #include "nsIWidgetListener.h"
31 #include "imgIContainer.h"
33 #include "nsXPLookAndFeel.h"
34 #include "nsPrintfCString.h"
36 using namespace mozilla
;
37 using namespace mozilla::dom
;
38 using namespace mozilla::hal
;
39 using namespace mozilla::gfx
;
40 using namespace mozilla::layers
;
41 using namespace mozilla::widget
;
43 static void InvalidateRegion(nsIWidget
* aWidget
,
44 const LayoutDeviceIntRegion
& aRegion
) {
45 for (auto iter
= aRegion
.RectIter(); !iter
.Done(); iter
.Next()) {
46 aWidget
->Invalidate(iter
.Get());
51 already_AddRefed
<nsIWidget
> nsIWidget::CreatePuppetWidget(
52 BrowserChild
* aBrowserChild
) {
53 MOZ_ASSERT(!aBrowserChild
|| nsIWidget::UsePuppetWidgets(),
54 "PuppetWidgets not allowed in this configuration");
56 nsCOMPtr
<nsIWidget
> widget
= new PuppetWidget(aBrowserChild
);
57 return widget
.forget();
63 static bool IsPopup(const nsWidgetInitData
* aInitData
) {
64 return aInitData
&& aInitData
->mWindowType
== eWindowType_popup
;
67 static bool MightNeedIMEFocus(const nsWidgetInitData
* aInitData
) {
68 // In the puppet-widget world, popup widgets are just dummies and
69 // shouldn't try to mess with IME state.
70 #ifdef MOZ_CROSS_PROCESS_IME
71 return !IsPopup(aInitData
);
77 // Arbitrary, fungible.
78 const size_t PuppetWidget::kMaxDimension
= 4000;
80 NS_IMPL_ISUPPORTS_INHERITED(PuppetWidget
, nsBaseWidget
,
81 TextEventDispatcherListener
)
83 PuppetWidget::PuppetWidget(BrowserChild
* aBrowserChild
)
84 : mBrowserChild(aBrowserChild
),
85 mMemoryPressureObserver(nullptr),
93 mNeedIMEStateInit(false),
94 mIgnoreCompositionEvents(false) {
95 // Setting 'Unknown' means "not yet cached".
96 mInputContext
.mIMEState
.mEnabled
= IMEState::UNKNOWN
;
99 PuppetWidget::~PuppetWidget() { Destroy(); }
101 void PuppetWidget::InfallibleCreate(nsIWidget
* aParent
,
102 nsNativeWidget aNativeParent
,
103 const LayoutDeviceIntRect
& aRect
,
104 nsWidgetInitData
* aInitData
) {
105 MOZ_ASSERT(!aNativeParent
, "got a non-Puppet native parent");
107 BaseCreate(nullptr, aInitData
);
113 mDrawTarget
= gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
114 IntSize(1, 1), SurfaceFormat::B8G8R8A8
);
116 mNeedIMEStateInit
= MightNeedIMEFocus(aInitData
);
118 PuppetWidget
* parent
= static_cast<PuppetWidget
*>(aParent
);
120 parent
->SetChild(this);
121 mLayerManager
= parent
->GetLayerManager();
123 Resize(mBounds
.X(), mBounds
.Y(), mBounds
.Width(), mBounds
.Height(), false);
125 mMemoryPressureObserver
= MemoryPressureObserver::Create(this);
128 nsresult
PuppetWidget::Create(nsIWidget
* aParent
, nsNativeWidget aNativeParent
,
129 const LayoutDeviceIntRect
& aRect
,
130 nsWidgetInitData
* aInitData
) {
131 InfallibleCreate(aParent
, aNativeParent
, aRect
, aInitData
);
135 void PuppetWidget::InitIMEState() {
136 MOZ_ASSERT(mBrowserChild
);
137 if (mNeedIMEStateInit
) {
138 mContentCache
.Clear();
139 mBrowserChild
->SendUpdateContentCache(mContentCache
);
140 mIMENotificationRequestsOfParent
= IMENotificationRequests();
141 mNeedIMEStateInit
= false;
145 already_AddRefed
<nsIWidget
> PuppetWidget::CreateChild(
146 const LayoutDeviceIntRect
& aRect
, nsWidgetInitData
* aInitData
,
147 bool aForceUseIWidgetParent
) {
148 bool isPopup
= IsPopup(aInitData
);
149 nsCOMPtr
<nsIWidget
> widget
= nsIWidget::CreatePuppetWidget(mBrowserChild
);
150 return ((widget
&& NS_SUCCEEDED(widget
->Create(isPopup
? nullptr : this,
151 nullptr, aRect
, aInitData
)))
156 void PuppetWidget::Destroy() {
157 if (mOnDestroyCalled
) {
160 mOnDestroyCalled
= true;
165 if (mMemoryPressureObserver
) {
166 mMemoryPressureObserver
->Unregister();
167 mMemoryPressureObserver
= nullptr;
171 mLayerManager
->Destroy();
173 mLayerManager
= nullptr;
174 mBrowserChild
= nullptr;
177 void PuppetWidget::Show(bool aState
) {
178 NS_ASSERTION(mEnabled
,
179 "does it make sense to Show()/Hide() a disabled widget?");
181 bool wasVisible
= mVisible
;
185 mChild
->mVisible
= aState
;
188 if (!wasVisible
&& mVisible
) {
189 // The previously attached widget listener is handy if
190 // we're transitioning from page to page without dropping
191 // layers (since we'll continue to show the old layers
192 // associated with that old widget listener). If the
193 // PuppetWidget was hidden, those layers are dropped,
194 // so the previously attached widget listener is really
195 // of no use anymore (and is actually actively harmful - see
197 mPreviouslyAttachedWidgetListener
= nullptr;
198 Resize(mBounds
.Width(), mBounds
.Height(), false);
203 void PuppetWidget::Resize(double aWidth
, double aHeight
, bool aRepaint
) {
204 LayoutDeviceIntRect oldBounds
= mBounds
;
206 LayoutDeviceIntSize(NSToIntRound(aWidth
), NSToIntRound(aHeight
)));
209 mChild
->Resize(aWidth
, aHeight
, aRepaint
);
213 // XXX: roc says that |aRepaint| dictates whether or not to
214 // invalidate the expanded area
215 if (oldBounds
.Size() < mBounds
.Size() && aRepaint
) {
216 LayoutDeviceIntRegion
dirty(mBounds
);
217 dirty
.Sub(dirty
, oldBounds
);
218 InvalidateRegion(this, dirty
);
221 // call WindowResized() on both the current listener, and possibly
222 // also the previous one if we're in a state where we're drawing that one
223 // because the current one is paint suppressed
224 if (!oldBounds
.IsEqualEdges(mBounds
) && mAttachedWidgetListener
) {
225 if (GetCurrentWidgetListener() &&
226 GetCurrentWidgetListener() != mAttachedWidgetListener
) {
227 GetCurrentWidgetListener()->WindowResized(this, mBounds
.Width(),
230 mAttachedWidgetListener
->WindowResized(this, mBounds
.Width(),
235 nsresult
PuppetWidget::ConfigureChildren(
236 const nsTArray
<Configuration
>& aConfigurations
) {
237 for (uint32_t i
= 0; i
< aConfigurations
.Length(); ++i
) {
238 const Configuration
& configuration
= aConfigurations
[i
];
239 PuppetWidget
* w
= static_cast<PuppetWidget
*>(configuration
.mChild
.get());
240 NS_ASSERTION(w
->GetParent() == this, "Configured widget is not a child");
241 w
->SetWindowClipRegion(configuration
.mClipRegion
, true);
242 LayoutDeviceIntRect bounds
= w
->GetBounds();
243 if (bounds
.Size() != configuration
.mBounds
.Size()) {
244 w
->Resize(configuration
.mBounds
.X(), configuration
.mBounds
.Y(),
245 configuration
.mBounds
.Width(), configuration
.mBounds
.Height(),
247 } else if (bounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
248 w
->Move(configuration
.mBounds
.X(), configuration
.mBounds
.Y());
250 w
->SetWindowClipRegion(configuration
.mClipRegion
, false);
255 void PuppetWidget::SetFocus(Raise aRaise
, CallerType aCallerType
) {
256 if (aRaise
== Raise::Yes
&& mBrowserChild
) {
257 mBrowserChild
->SendRequestFocus(true, aCallerType
);
261 void PuppetWidget::Invalidate(const LayoutDeviceIntRect
& aRect
) {
263 debug_DumpInvalidate(stderr
, this, &aRect
, "PuppetWidget", 0);
267 mChild
->Invalidate(aRect
);
271 mDirtyRegion
.Or(mDirtyRegion
, aRect
);
273 if (mBrowserChild
&& !mDirtyRegion
.IsEmpty() && !mPaintTask
.IsPending()) {
274 mPaintTask
= new PaintTask(this);
275 nsCOMPtr
<nsIRunnable
> event(mPaintTask
.get());
276 mBrowserChild
->TabGroup()->Dispatch(TaskCategory::Other
, event
.forget());
281 mozilla::LayoutDeviceToLayoutDeviceMatrix4x4
282 PuppetWidget::WidgetToTopLevelWidgetTransform() {
283 if (!GetOwningBrowserChild()) {
284 NS_WARNING("PuppetWidget without Tab does not have transform information.");
285 return mozilla::LayoutDeviceToLayoutDeviceMatrix4x4();
287 return GetOwningBrowserChild()->GetChildToParentConversionMatrix();
290 void PuppetWidget::InitEvent(WidgetGUIEvent
& aEvent
,
291 LayoutDeviceIntPoint
* aPoint
) {
292 if (nullptr == aPoint
) {
293 aEvent
.mRefPoint
= LayoutDeviceIntPoint(0, 0);
295 // use the point override if provided
296 aEvent
.mRefPoint
= *aPoint
;
298 aEvent
.mTime
= PR_Now() / 1000;
301 nsresult
PuppetWidget::DispatchEvent(WidgetGUIEvent
* aEvent
,
302 nsEventStatus
& aStatus
) {
304 debug_DumpEvent(stdout
, aEvent
->mWidget
, aEvent
, "PuppetWidget", 0);
307 MOZ_ASSERT(!mChild
|| mChild
->mWindowType
== eWindowType_popup
,
308 "Unexpected event dispatch!");
310 MOZ_ASSERT(!aEvent
->AsKeyboardEvent() ||
311 aEvent
->mFlags
.mIsSynthesizedForTests
||
312 aEvent
->AsKeyboardEvent()->AreAllEditCommandsInitialized(),
313 "Non-sysnthesized keyboard events should have edit commands for "
315 "before dispatched");
317 if (aEvent
->mClass
== eCompositionEventClass
) {
318 // If we've already requested to commit/cancel the latest composition,
319 // TextComposition for the old composition has been destroyed. Then,
320 // the DOM tree needs to listen to next eCompositionStart and its
321 // following events. So, until we meet new eCompositionStart, let's
322 // discard all unnecessary composition events here.
323 if (mIgnoreCompositionEvents
) {
324 if (aEvent
->mMessage
!= eCompositionStart
) {
325 aStatus
= nsEventStatus_eIgnore
;
328 // Now, we receive new eCompositionStart. Let's restart to handle
329 // composition in this process.
330 mIgnoreCompositionEvents
= false;
332 // Store the latest native IME context of parent process's widget or
333 // TextEventDispatcher if it's in this process.
334 WidgetCompositionEvent
* compositionEvent
= aEvent
->AsCompositionEvent();
336 if (mNativeIMEContext
.IsValid() &&
337 mNativeIMEContext
!= compositionEvent
->mNativeIMEContext
) {
338 RefPtr
<TextComposition
> composition
=
339 IMEStateManager::GetTextCompositionFor(this);
342 "When there is composition caused by old native IME context, "
343 "composition events caused by different native IME context are not "
346 #endif // #ifdef DEBUG
347 mNativeIMEContext
= compositionEvent
->mNativeIMEContext
;
350 // If the event is a composition event or a keyboard event, it should be
351 // dispatched with TextEventDispatcher if we could do that with current
352 // design. However, we cannot do that without big changes and the behavior
353 // is not so complicated for now. Therefore, we should just notify it
354 // of dispatching events and TextEventDispatcher should emulate the state
356 if (aEvent
->mClass
== eCompositionEventClass
||
357 aEvent
->mClass
== eKeyboardEventClass
) {
358 TextEventDispatcher
* dispatcher
= GetTextEventDispatcher();
359 // However, if the event is being dispatched by the text event dispatcher
360 // or, there is native text event dispatcher listener, that means that
361 // native text input event handler is in this process like on Android,
362 // and the event is not synthesized for tests, the event is coming from
363 // the TextEventDispatcher. In these cases, we shouldn't notify
364 // TextEventDispatcher of dispatching the event.
365 if (!dispatcher
->IsDispatchingEvent() &&
366 !(mNativeTextEventDispatcherListener
&&
367 !aEvent
->mFlags
.mIsSynthesizedForTests
)) {
368 DebugOnly
<nsresult
> rv
=
369 dispatcher
->BeginInputTransactionFor(aEvent
, this);
370 NS_WARNING_ASSERTION(
372 "The text event dispatcher should always succeed to start input "
373 "transaction for the event");
377 aStatus
= nsEventStatus_eIgnore
;
379 if (GetCurrentWidgetListener()) {
381 GetCurrentWidgetListener()->HandleEvent(aEvent
, mUseAttachedEvents
);
387 nsEventStatus
PuppetWidget::DispatchInputEvent(WidgetInputEvent
* aEvent
) {
388 if (!AsyncPanZoomEnabled()) {
389 nsEventStatus status
= nsEventStatus_eIgnore
;
390 DispatchEvent(aEvent
, status
);
394 if (!mBrowserChild
) {
395 return nsEventStatus_eIgnore
;
398 if (PresShell
* presShell
= mBrowserChild
->GetTopLevelPresShell()) {
399 // Because the root resolution is conceptually at the parent/child process
400 // boundary, we need to apply that resolution here because we're sending
401 // the event from the child to the parent process.
402 LayoutDevicePoint
pt(aEvent
->mRefPoint
);
403 pt
= pt
* presShell
->GetResolution();
404 aEvent
->mRefPoint
= LayoutDeviceIntPoint::Round(pt
);
407 switch (aEvent
->mClass
) {
408 case eWheelEventClass
:
409 Unused
<< mBrowserChild
->SendDispatchWheelEvent(*aEvent
->AsWheelEvent());
411 case eMouseEventClass
:
412 Unused
<< mBrowserChild
->SendDispatchMouseEvent(*aEvent
->AsMouseEvent());
414 case eKeyboardEventClass
:
415 Unused
<< mBrowserChild
->SendDispatchKeyboardEvent(
416 *aEvent
->AsKeyboardEvent());
419 MOZ_ASSERT_UNREACHABLE("unsupported event type");
422 return nsEventStatus_eIgnore
;
425 nsresult
PuppetWidget::SynthesizeNativeKeyEvent(
426 int32_t aNativeKeyboardLayout
, int32_t aNativeKeyCode
,
427 uint32_t aModifierFlags
, const nsAString
& aCharacters
,
428 const nsAString
& aUnmodifiedCharacters
, nsIObserver
* aObserver
) {
429 AutoObserverNotifier
notifier(aObserver
, "keyevent");
430 if (!mBrowserChild
) {
431 return NS_ERROR_FAILURE
;
433 mBrowserChild
->SendSynthesizeNativeKeyEvent(
434 aNativeKeyboardLayout
, aNativeKeyCode
, aModifierFlags
,
435 nsString(aCharacters
), nsString(aUnmodifiedCharacters
),
436 notifier
.SaveObserver());
440 nsresult
PuppetWidget::SynthesizeNativeMouseEvent(
441 mozilla::LayoutDeviceIntPoint aPoint
, uint32_t aNativeMessage
,
442 uint32_t aModifierFlags
, nsIObserver
* aObserver
) {
443 AutoObserverNotifier
notifier(aObserver
, "mouseevent");
444 if (!mBrowserChild
) {
445 return NS_ERROR_FAILURE
;
447 mBrowserChild
->SendSynthesizeNativeMouseEvent(
448 aPoint
, aNativeMessage
, aModifierFlags
, notifier
.SaveObserver());
452 nsresult
PuppetWidget::SynthesizeNativeMouseMove(
453 mozilla::LayoutDeviceIntPoint aPoint
, nsIObserver
* aObserver
) {
454 AutoObserverNotifier
notifier(aObserver
, "mousemove");
455 if (!mBrowserChild
) {
456 return NS_ERROR_FAILURE
;
458 mBrowserChild
->SendSynthesizeNativeMouseMove(aPoint
, notifier
.SaveObserver());
462 nsresult
PuppetWidget::SynthesizeNativeMouseScrollEvent(
463 mozilla::LayoutDeviceIntPoint aPoint
, uint32_t aNativeMessage
,
464 double aDeltaX
, double aDeltaY
, double aDeltaZ
, uint32_t aModifierFlags
,
465 uint32_t aAdditionalFlags
, nsIObserver
* aObserver
) {
466 AutoObserverNotifier
notifier(aObserver
, "mousescrollevent");
467 if (!mBrowserChild
) {
468 return NS_ERROR_FAILURE
;
470 mBrowserChild
->SendSynthesizeNativeMouseScrollEvent(
471 aPoint
, aNativeMessage
, aDeltaX
, aDeltaY
, aDeltaZ
, aModifierFlags
,
472 aAdditionalFlags
, notifier
.SaveObserver());
476 nsresult
PuppetWidget::SynthesizeNativeTouchPoint(
477 uint32_t aPointerId
, TouchPointerState aPointerState
,
478 LayoutDeviceIntPoint aPoint
, double aPointerPressure
,
479 uint32_t aPointerOrientation
, nsIObserver
* aObserver
) {
480 AutoObserverNotifier
notifier(aObserver
, "touchpoint");
481 if (!mBrowserChild
) {
482 return NS_ERROR_FAILURE
;
484 mBrowserChild
->SendSynthesizeNativeTouchPoint(
485 aPointerId
, aPointerState
, aPoint
, aPointerPressure
, aPointerOrientation
,
486 notifier
.SaveObserver());
490 nsresult
PuppetWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint
,
492 nsIObserver
* aObserver
) {
493 AutoObserverNotifier
notifier(aObserver
, "touchtap");
494 if (!mBrowserChild
) {
495 return NS_ERROR_FAILURE
;
497 mBrowserChild
->SendSynthesizeNativeTouchTap(aPoint
, aLongTap
,
498 notifier
.SaveObserver());
502 nsresult
PuppetWidget::ClearNativeTouchSequence(nsIObserver
* aObserver
) {
503 AutoObserverNotifier
notifier(aObserver
, "cleartouch");
504 if (!mBrowserChild
) {
505 return NS_ERROR_FAILURE
;
507 mBrowserChild
->SendClearNativeTouchSequence(notifier
.SaveObserver());
511 void PuppetWidget::SetConfirmedTargetAPZC(
512 uint64_t aInputBlockId
,
513 const nsTArray
<SLGuidAndRenderRoot
>& aTargets
) const {
515 mBrowserChild
->SetTargetAPZC(aInputBlockId
, aTargets
);
519 void PuppetWidget::UpdateZoomConstraints(
520 const uint32_t& aPresShellId
, const ScrollableLayerGuid::ViewID
& aViewId
,
521 const Maybe
<ZoomConstraints
>& aConstraints
) {
523 mBrowserChild
->DoUpdateZoomConstraints(aPresShellId
, aViewId
, aConstraints
);
527 bool PuppetWidget::AsyncPanZoomEnabled() const {
528 return mBrowserChild
&& mBrowserChild
->AsyncPanZoomEnabled();
531 bool PuppetWidget::GetEditCommands(NativeKeyBindingsType aType
,
532 const WidgetKeyboardEvent
& aEvent
,
533 nsTArray
<CommandInt
>& aCommands
) {
534 // Validate the arguments.
535 if (NS_WARN_IF(!nsIWidget::GetEditCommands(aType
, aEvent
, aCommands
))) {
538 if (NS_WARN_IF(!mBrowserChild
)) {
541 mBrowserChild
->RequestEditCommands(aType
, aEvent
, aCommands
);
545 LayerManager
* PuppetWidget::GetLayerManager(
546 PLayerTransactionChild
* aShadowManager
, LayersBackend aBackendHint
,
547 LayerManagerPersistence aPersistence
) {
548 if (!mLayerManager
) {
549 if (XRE_IsParentProcess()) {
550 // On the parent process there is no CompositorBridgeChild which confuses
551 // some layers code, so we use basic layers instead. Note that we create
552 // a non-retaining layer manager since we don't care about performance.
553 mLayerManager
= new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN
);
554 return mLayerManager
;
557 // If we know for sure that the parent side of this BrowserChild is not
558 // connected to the compositor, we don't want to use a "remote" layer
559 // manager like WebRender or Client. Instead we use a Basic one which
560 // can do drawing in this process.
561 MOZ_ASSERT(!mBrowserChild
||
562 mBrowserChild
->IsLayersConnected() != Some(true));
563 mLayerManager
= new BasicLayerManager(this);
566 return mLayerManager
;
569 bool PuppetWidget::CreateRemoteLayerManager(
570 const std::function
<bool(LayerManager
*)>& aInitializeFunc
) {
571 RefPtr
<LayerManager
> lm
;
572 MOZ_ASSERT(mBrowserChild
);
573 if (mBrowserChild
->GetCompositorOptions().UseWebRender()) {
574 lm
= new WebRenderLayerManager(this);
576 lm
= new ClientLayerManager(this);
579 if (!aInitializeFunc(lm
)) {
583 // Force the old LM to self destruct, otherwise if the reference dangles we
584 // could fail to revoke the most recent transaction. We only want to replace
585 // it if we successfully create its successor because a partially initialized
586 // layer manager is worse than a fully initialized but shutdown layer manager.
587 DestroyLayerManager();
588 mLayerManager
= lm
.forget();
592 nsresult
PuppetWidget::RequestIMEToCommitComposition(bool aCancel
) {
593 if (!mBrowserChild
) {
594 return NS_ERROR_FAILURE
;
597 MOZ_ASSERT(!Destroyed());
599 // There must not be composition which is caused by the PuppetWidget instance.
600 if (NS_WARN_IF(!mNativeIMEContext
.IsValid())) {
604 // We've already requested to commit/cancel composition.
605 if (NS_WARN_IF(mIgnoreCompositionEvents
)) {
607 RefPtr
<TextComposition
> composition
=
608 IMEStateManager::GetTextCompositionFor(this);
609 MOZ_ASSERT(!composition
);
610 #endif // #ifdef DEBUG
614 RefPtr
<TextComposition
> composition
=
615 IMEStateManager::GetTextCompositionFor(this);
616 // This method shouldn't be called when there is no text composition instance.
617 if (NS_WARN_IF(!composition
)) {
621 MOZ_DIAGNOSTIC_ASSERT(
622 composition
->IsRequestingCommitOrCancelComposition(),
623 "Requesting commit or cancel composition should be requested via "
624 "TextComposition instance");
626 bool isCommitted
= false;
627 nsAutoString committedString
;
628 if (NS_WARN_IF(!mBrowserChild
->SendRequestIMEToCommitComposition(
629 aCancel
, &isCommitted
, &committedString
))) {
630 return NS_ERROR_FAILURE
;
633 // If the composition wasn't committed synchronously, we need to wait async
634 // composition events for destroying the TextComposition instance.
639 // Dispatch eCompositionCommit event.
640 WidgetCompositionEvent
compositionCommitEvent(true, eCompositionCommit
, this);
641 InitEvent(compositionCommitEvent
, nullptr);
642 compositionCommitEvent
.mData
= committedString
;
643 nsEventStatus status
= nsEventStatus_eIgnore
;
644 DispatchEvent(&compositionCommitEvent
, status
);
647 RefPtr
<TextComposition
> currentComposition
=
648 IMEStateManager::GetTextCompositionFor(this);
649 MOZ_ASSERT(!currentComposition
);
650 #endif // #ifdef DEBUG
652 // Ignore the following composition events until we receive new
653 // eCompositionStart event.
654 mIgnoreCompositionEvents
= true;
656 Unused
<< mBrowserChild
->SendOnEventNeedingAckHandled(
657 eCompositionCommitRequestHandled
);
659 // NOTE: PuppetWidget might be destroyed already.
663 nsresult
PuppetWidget::StartPluginIME(const WidgetKeyboardEvent
& aKeyboardEvent
,
664 int32_t aPanelX
, int32_t aPanelY
,
665 nsString
& aCommitted
) {
666 DebugOnly
<bool> propagationAlreadyStopped
=
667 aKeyboardEvent
.mFlags
.mPropagationStopped
;
668 DebugOnly
<bool> immediatePropagationAlreadyStopped
=
669 aKeyboardEvent
.mFlags
.mImmediatePropagationStopped
;
670 if (!mBrowserChild
|| !mBrowserChild
->SendStartPluginIME(
671 aKeyboardEvent
, aPanelX
, aPanelY
, &aCommitted
)) {
672 return NS_ERROR_FAILURE
;
674 // BrowserChild::SendStartPluginIME() sends back the keyboard event to the
675 // main process synchronously. At this time,
676 // ParamTraits<WidgetEvent>::Write() marks the event as "posted to remote
677 // process". However, this is not correct here since the event has been
678 // handled synchronously in the main process. So, we adjust the cross process
679 // dispatching state here.
680 const_cast<WidgetKeyboardEvent
&>(aKeyboardEvent
)
681 .ResetCrossProcessDispatchingState();
682 // Although it shouldn't occur in content process,
683 // ResetCrossProcessDispatchingState() may reset propagation state too
684 // if the event was posted to a remote process and we're waiting its
685 // result. So, if you saw hitting the following assertions, you'd
686 // need to restore the propagation state too.
687 MOZ_ASSERT(propagationAlreadyStopped
==
688 aKeyboardEvent
.mFlags
.mPropagationStopped
);
689 MOZ_ASSERT(immediatePropagationAlreadyStopped
==
690 aKeyboardEvent
.mFlags
.mImmediatePropagationStopped
);
694 void PuppetWidget::SetPluginFocused(bool& aFocused
) {
696 mBrowserChild
->SendSetPluginFocused(aFocused
);
700 void PuppetWidget::DefaultProcOfPluginEvent(const WidgetPluginEvent
& aEvent
) {
701 if (!mBrowserChild
) {
704 mBrowserChild
->SendDefaultProcOfPluginEvent(aEvent
);
707 // When this widget caches input context and currently managed by
708 // IMEStateManager, the cache is valid.
709 bool PuppetWidget::HaveValidInputContextCache() const {
710 return (mInputContext
.mIMEState
.mEnabled
!= IMEState::UNKNOWN
&&
711 IMEStateManager::GetWidgetForActiveInputContext() == this);
714 void PuppetWidget::SetInputContext(const InputContext
& aContext
,
715 const InputContextAction
& aAction
) {
716 mInputContext
= aContext
;
717 // Any widget instances cannot cache IME open state because IME open state
718 // can be changed by user but native IME may not notify us of changing the
719 // open state on some platforms.
720 mInputContext
.mIMEState
.mOpen
= IMEState::OPEN_STATE_NOT_SUPPORTED
;
721 if (!mBrowserChild
) {
724 mBrowserChild
->SendSetInputContext(aContext
, aAction
);
727 InputContext
PuppetWidget::GetInputContext() {
728 // XXX Currently, we don't support retrieving IME open state from child
731 // If the cache of input context is valid, we can avoid to use synchronous
733 if (HaveValidInputContextCache()) {
734 return mInputContext
;
737 NS_WARNING("PuppetWidget::GetInputContext() needs to retrieve it with IPC");
739 // Don't cache InputContext here because this process isn't managing IME
740 // state of the chrome widget. So, we cannot modify mInputContext when
741 // chrome widget is set to new context.
742 InputContext context
;
744 mBrowserChild
->SendGetInputContext(&context
.mIMEState
);
749 NativeIMEContext
PuppetWidget::GetNativeIMEContext() {
750 return mNativeIMEContext
;
753 nsresult
PuppetWidget::NotifyIMEOfFocusChange(
754 const IMENotification
& aIMENotification
) {
755 if (!mBrowserChild
) {
756 return NS_ERROR_FAILURE
;
759 bool gotFocus
= aIMENotification
.mMessage
== NOTIFY_IME_OF_FOCUS
;
761 if (mInputContext
.mIMEState
.mEnabled
!= IMEState::PLUGIN
) {
762 // When IME gets focus, we should initalize all information of the
764 if (NS_WARN_IF(!mContentCache
.CacheAll(this, &aIMENotification
))) {
765 return NS_ERROR_FAILURE
;
768 // However, if a plugin has focus, only the editor rect information is
770 if (NS_WARN_IF(!mContentCache
.CacheEditorRect(this, &aIMENotification
))) {
771 return NS_ERROR_FAILURE
;
775 // When IME loses focus, we don't need to store anything.
776 mContentCache
.Clear();
779 mIMENotificationRequestsOfParent
=
780 IMENotificationRequests(IMENotificationRequests::NOTIFY_ALL
);
781 RefPtr
<PuppetWidget
> self
= this;
782 mBrowserChild
->SendNotifyIMEFocus(mContentCache
, aIMENotification
)
784 mBrowserChild
->TabGroup()->EventTargetFor(TaskCategory::UI
), __func__
,
785 [self
](IMENotificationRequests
&& aRequests
) {
786 self
->mIMENotificationRequestsOfParent
= aRequests
;
787 if (TextEventDispatcher
* dispatcher
=
788 self
->GetTextEventDispatcher()) {
789 dispatcher
->OnWidgetChangeIMENotificationRequests(self
);
792 [self
](mozilla::ipc::ResponseRejectReason
&& aReason
) {
793 NS_WARNING("SendNotifyIMEFocus got rejected.");
799 nsresult
PuppetWidget::NotifyIMEOfCompositionUpdate(
800 const IMENotification
& aIMENotification
) {
801 if (NS_WARN_IF(!mBrowserChild
)) {
802 return NS_ERROR_FAILURE
;
805 if (mInputContext
.mIMEState
.mEnabled
!= IMEState::PLUGIN
&&
806 NS_WARN_IF(!mContentCache
.CacheSelection(this, &aIMENotification
))) {
807 return NS_ERROR_FAILURE
;
809 mBrowserChild
->SendNotifyIMECompositionUpdate(mContentCache
,
814 nsresult
PuppetWidget::NotifyIMEOfTextChange(
815 const IMENotification
& aIMENotification
) {
816 MOZ_ASSERT(aIMENotification
.mMessage
== NOTIFY_IME_OF_TEXT_CHANGE
,
817 "Passed wrong notification");
818 if (!mBrowserChild
) {
819 return NS_ERROR_FAILURE
;
822 // While a plugin has focus, text change notification shouldn't be available.
823 if (NS_WARN_IF(mInputContext
.mIMEState
.mEnabled
== IMEState::PLUGIN
)) {
824 return NS_ERROR_FAILURE
;
827 // FYI: text change notification is the first notification after
828 // a user operation changes the content. So, we need to modify
829 // the cache as far as possible here.
831 if (NS_WARN_IF(!mContentCache
.CacheText(this, &aIMENotification
))) {
832 return NS_ERROR_FAILURE
;
835 // BrowserParent doesn't this this to cache. we don't send the notification
836 // if parent process doesn't request NOTIFY_TEXT_CHANGE.
837 if (mIMENotificationRequestsOfParent
.WantTextChange()) {
838 mBrowserChild
->SendNotifyIMETextChange(mContentCache
, aIMENotification
);
840 mBrowserChild
->SendUpdateContentCache(mContentCache
);
845 nsresult
PuppetWidget::NotifyIMEOfSelectionChange(
846 const IMENotification
& aIMENotification
) {
847 MOZ_ASSERT(aIMENotification
.mMessage
== NOTIFY_IME_OF_SELECTION_CHANGE
,
848 "Passed wrong notification");
849 if (!mBrowserChild
) {
850 return NS_ERROR_FAILURE
;
853 // While a plugin has focus, selection change notification shouldn't be
855 if (NS_WARN_IF(mInputContext
.mIMEState
.mEnabled
== IMEState::PLUGIN
)) {
856 return NS_ERROR_FAILURE
;
859 // Note that selection change must be notified after text change if it occurs.
860 // Therefore, we don't need to query text content again here.
861 mContentCache
.SetSelection(
862 this, aIMENotification
.mSelectionChangeData
.mOffset
,
863 aIMENotification
.mSelectionChangeData
.Length(),
864 aIMENotification
.mSelectionChangeData
.mReversed
,
865 aIMENotification
.mSelectionChangeData
.GetWritingMode());
867 mBrowserChild
->SendNotifyIMESelection(mContentCache
, aIMENotification
);
872 nsresult
PuppetWidget::NotifyIMEOfMouseButtonEvent(
873 const IMENotification
& aIMENotification
) {
874 if (!mBrowserChild
) {
875 return NS_ERROR_FAILURE
;
878 // While a plugin has focus, mouse button event notification shouldn't be
880 if (NS_WARN_IF(mInputContext
.mIMEState
.mEnabled
== IMEState::PLUGIN
)) {
881 return NS_ERROR_FAILURE
;
884 bool consumedByIME
= false;
885 if (!mBrowserChild
->SendNotifyIMEMouseButtonEvent(aIMENotification
,
887 return NS_ERROR_FAILURE
;
890 return consumedByIME
? NS_SUCCESS_EVENT_CONSUMED
: NS_OK
;
893 nsresult
PuppetWidget::NotifyIMEOfPositionChange(
894 const IMENotification
& aIMENotification
) {
895 if (NS_WARN_IF(!mBrowserChild
)) {
896 return NS_ERROR_FAILURE
;
899 if (NS_WARN_IF(!mContentCache
.CacheEditorRect(this, &aIMENotification
))) {
900 return NS_ERROR_FAILURE
;
902 // While a plugin has focus, selection range isn't available. So, we don't
903 // need to cache it at that time.
904 if (mInputContext
.mIMEState
.mEnabled
!= IMEState::PLUGIN
&&
905 NS_WARN_IF(!mContentCache
.CacheSelection(this, &aIMENotification
))) {
906 return NS_ERROR_FAILURE
;
908 if (mIMENotificationRequestsOfParent
.WantPositionChanged()) {
909 mBrowserChild
->SendNotifyIMEPositionChange(mContentCache
, aIMENotification
);
911 mBrowserChild
->SendUpdateContentCache(mContentCache
);
916 struct CursorSurface
{
917 UniquePtr
<char[]> mData
;
921 void PuppetWidget::SetCursor(nsCursor aCursor
, imgIContainer
* aCursorImage
,
922 uint32_t aHotspotX
, uint32_t aHotspotY
) {
923 if (!mBrowserChild
) {
927 // Don't cache on windows, Windowless flash breaks this via async cursor
930 if (!mUpdateCursor
&& mCursor
== aCursor
&& mCustomCursor
== aCursorImage
&&
932 (mCursorHotspotX
== aHotspotX
&& mCursorHotspotY
== aHotspotY
))) {
937 bool hasCustomCursor
= false;
938 UniquePtr
<char[]> customCursorData
;
940 IntSize customCursorSize
;
942 auto format
= SurfaceFormat::B8G8R8A8
;
943 bool force
= mUpdateCursor
;
946 RefPtr
<SourceSurface
> surface
= aCursorImage
->GetFrame(
947 imgIContainer::FRAME_CURRENT
,
948 imgIContainer::FLAG_SYNC_DECODE
| imgIContainer::FLAG_ASYNC_NOTIFY
);
950 if (RefPtr
<DataSourceSurface
> dataSurface
= surface
->GetDataSurface()) {
951 hasCustomCursor
= true;
952 customCursorData
= nsContentUtils::GetSurfaceData(
953 WrapNotNull(dataSurface
), &length
, &stride
);
954 customCursorSize
= dataSurface
->GetSize();
955 format
= dataSurface
->GetFormat();
960 mCustomCursor
= nullptr;
962 nsDependentCString
cursorData(customCursorData
? customCursorData
.get() : "",
964 if (!mBrowserChild
->SendSetCursor(aCursor
, hasCustomCursor
, cursorData
,
965 customCursorSize
.width
,
966 customCursorSize
.height
, stride
, format
,
967 aHotspotX
, aHotspotY
, force
)) {
972 mCustomCursor
= aCursorImage
;
973 mCursorHotspotX
= aHotspotX
;
974 mCursorHotspotY
= aHotspotY
;
975 mUpdateCursor
= false;
978 void PuppetWidget::ClearCachedCursor() {
979 nsBaseWidget::ClearCachedCursor();
980 mCustomCursor
= nullptr;
983 nsresult
PuppetWidget::Paint() {
984 MOZ_ASSERT(!mDirtyRegion
.IsEmpty(), "paint event logic messed up");
986 if (!GetCurrentWidgetListener()) return NS_OK
;
988 LayoutDeviceIntRegion region
= mDirtyRegion
;
990 // reset repaint tracking
991 mDirtyRegion
.SetEmpty();
994 RefPtr
<PuppetWidget
> strongThis(this);
996 GetCurrentWidgetListener()->WillPaintWindow(this);
998 if (GetCurrentWidgetListener()) {
1000 debug_DumpPaintEvent(stderr
, this, region
.ToUnknownRegion(), "PuppetWidget",
1004 if (mLayerManager
->GetBackendType() ==
1005 mozilla::layers::LayersBackend::LAYERS_CLIENT
||
1006 mLayerManager
->GetBackendType() ==
1007 mozilla::layers::LayersBackend::LAYERS_WR
||
1008 (mozilla::layers::LayersBackend::LAYERS_BASIC
==
1009 mLayerManager
->GetBackendType() &&
1010 mBrowserChild
&& mBrowserChild
->IsLayersConnected().isSome())) {
1011 // Do nothing, the compositor will handle drawing
1012 if (mBrowserChild
) {
1013 mBrowserChild
->NotifyPainted();
1015 } else if (mozilla::layers::LayersBackend::LAYERS_BASIC
==
1016 mLayerManager
->GetBackendType()) {
1017 RefPtr
<gfxContext
> ctx
= gfxContext::CreateOrNull(mDrawTarget
);
1019 gfxDevCrash(LogReason::InvalidContext
)
1020 << "PuppetWidget context problem " << gfx::hexa(mDrawTarget
);
1021 return NS_ERROR_FAILURE
;
1023 ctx
->Rectangle(gfxRect(0, 0, 0, 0));
1025 AutoLayerManagerSetup
setupLayerManager(this, ctx
,
1026 BufferMode::BUFFER_NONE
);
1027 GetCurrentWidgetListener()->PaintWindow(this, region
);
1028 if (mBrowserChild
) {
1029 mBrowserChild
->NotifyPainted();
1034 if (GetCurrentWidgetListener()) {
1035 GetCurrentWidgetListener()->DidPaintWindow();
1041 void PuppetWidget::SetChild(PuppetWidget
* aChild
) {
1042 MOZ_ASSERT(this != aChild
, "can't parent a widget to itself");
1043 MOZ_ASSERT(!aChild
->mChild
,
1044 "fake widget 'hierarchy' only expected to have one level");
1050 PuppetWidget::PaintTask::Run() {
1057 void PuppetWidget::PaintNowIfNeeded() {
1058 if (IsVisible() && mPaintTask
.IsPending()) {
1063 void PuppetWidget::OnMemoryPressure(layers::MemoryPressureReason aWhy
) {
1064 if (aWhy
!= MemoryPressureReason::LOW_MEMORY_ONGOING
&& !mVisible
&&
1065 mLayerManager
&& XRE_IsContentProcess()) {
1066 mLayerManager
->ClearCachedResources();
1070 bool PuppetWidget::NeedsPaint() {
1071 // e10s popups are handled by the parent process, so never should be painted
1073 if (XRE_IsContentProcess() &&
1074 StaticPrefs::browser_tabs_remote_desktopbehavior() &&
1075 mWindowType
== eWindowType_popup
) {
1076 NS_WARNING("Trying to paint an e10s popup in the child process!");
1083 float PuppetWidget::GetDPI() { return mDPI
; }
1085 double PuppetWidget::GetDefaultScaleInternal() { return mDefaultScale
; }
1087 int32_t PuppetWidget::RoundsWidgetCoordinatesTo() { return mRounding
; }
1089 void* PuppetWidget::GetNativeData(uint32_t aDataType
) {
1090 switch (aDataType
) {
1091 case NS_NATIVE_SHAREABLE_WINDOW
: {
1092 // NOTE: We can not have a tab child in some situations, such as when
1093 // we're rendering to a fake widget for thumbnails.
1094 if (!mBrowserChild
) {
1095 NS_WARNING("Need BrowserChild to get the nativeWindow from!");
1097 mozilla::WindowsHandle nativeData
= 0;
1098 if (mBrowserChild
) {
1099 nativeData
= mBrowserChild
->WidgetNativeData();
1101 return (void*)nativeData
;
1103 case NS_NATIVE_WINDOW
:
1104 case NS_NATIVE_WIDGET
:
1105 case NS_NATIVE_DISPLAY
:
1106 // These types are ignored (see bug 1183828, bug 1240891).
1108 case NS_RAW_NATIVE_IME_CONTEXT
:
1109 MOZ_CRASH("You need to call GetNativeIMEContext() instead");
1110 case NS_NATIVE_PLUGIN_PORT
:
1111 case NS_NATIVE_GRAPHIC
:
1112 case NS_NATIVE_SHELLWIDGET
:
1114 NS_WARNING("nsWindow::GetNativeData called with bad value");
1121 void PuppetWidget::SetNativeData(uint32_t aDataType
, uintptr_t aVal
) {
1122 switch (aDataType
) {
1123 case NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW
:
1124 MOZ_ASSERT(mBrowserChild
, "Need BrowserChild to send the message.");
1125 if (mBrowserChild
) {
1126 mBrowserChild
->SendSetNativeChildOfShareableWindow(aVal
);
1130 NS_WARNING("SetNativeData called with unsupported data type.");
1135 LayoutDeviceIntPoint
PuppetWidget::GetChromeOffset() {
1136 if (!GetOwningBrowserChild()) {
1137 NS_WARNING("PuppetWidget without Tab does not have chrome information.");
1138 return LayoutDeviceIntPoint();
1140 return GetOwningBrowserChild()->GetChromeOffset();
1143 LayoutDeviceIntPoint
PuppetWidget::GetWindowPosition() {
1144 if (!GetOwningBrowserChild()) {
1145 return LayoutDeviceIntPoint();
1148 int32_t winX
, winY
, winW
, winH
;
1150 GetOwningBrowserChild()->GetDimensions(0, &winX
, &winY
, &winW
, &winH
),
1151 LayoutDeviceIntPoint());
1152 return LayoutDeviceIntPoint(winX
, winY
) +
1153 GetOwningBrowserChild()->GetClientOffset();
1156 LayoutDeviceIntRect
PuppetWidget::GetScreenBounds() {
1157 return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds
.Size());
1160 LayoutDeviceIntSize
PuppetWidget::GetCompositionSize() {
1161 Maybe
<LayoutDeviceIntRect
> visibleRect
=
1162 mBrowserChild
? mBrowserChild
->GetVisibleRect() : Nothing();
1164 return nsBaseWidget::GetCompositionSize();
1166 return visibleRect
->Size();
1169 uint32_t PuppetWidget::GetMaxTouchPoints() const {
1170 return mBrowserChild
? mBrowserChild
->MaxTouchPoints() : 0;
1173 void PuppetWidget::StartAsyncScrollbarDrag(
1174 const AsyncDragMetrics
& aDragMetrics
) {
1175 mBrowserChild
->StartScrollbarDrag(aDragMetrics
);
1178 PuppetScreen::PuppetScreen(void* nativeScreen
) {}
1180 PuppetScreen::~PuppetScreen() {}
1182 static ScreenConfiguration
ScreenConfig() {
1183 ScreenConfiguration config
;
1184 hal::GetCurrentScreenConfiguration(&config
);
1188 nsIntSize
PuppetWidget::GetScreenDimensions() {
1189 nsIntRect r
= ScreenConfig().rect();
1190 return nsIntSize(r
.Width(), r
.Height());
1194 PuppetScreen::GetRect(int32_t* outLeft
, int32_t* outTop
, int32_t* outWidth
,
1195 int32_t* outHeight
) {
1196 nsIntRect r
= ScreenConfig().rect();
1197 r
.GetRect(outLeft
, outTop
, outWidth
, outHeight
);
1202 PuppetScreen::GetAvailRect(int32_t* outLeft
, int32_t* outTop
, int32_t* outWidth
,
1203 int32_t* outHeight
) {
1204 return GetRect(outLeft
, outTop
, outWidth
, outHeight
);
1208 PuppetScreen::GetPixelDepth(int32_t* aPixelDepth
) {
1209 *aPixelDepth
= ScreenConfig().pixelDepth();
1214 PuppetScreen::GetColorDepth(int32_t* aColorDepth
) {
1215 *aColorDepth
= ScreenConfig().colorDepth();
1219 NS_IMPL_ISUPPORTS(PuppetScreenManager
, nsIScreenManager
)
1221 PuppetScreenManager::PuppetScreenManager() {
1222 mOneScreen
= new PuppetScreen(nullptr);
1225 PuppetScreenManager::~PuppetScreenManager() {}
1228 PuppetScreenManager::GetPrimaryScreen(nsIScreen
** outScreen
) {
1229 NS_IF_ADDREF(*outScreen
= mOneScreen
.get());
1234 PuppetScreenManager::GetTotalScreenPixels(int64_t* aTotalScreenPixels
) {
1235 MOZ_ASSERT(aTotalScreenPixels
);
1237 int32_t x
, y
, width
, height
;
1238 x
= y
= width
= height
= 0;
1239 mOneScreen
->GetRect(&x
, &y
, &width
, &height
);
1240 *aTotalScreenPixels
= width
* height
;
1242 *aTotalScreenPixels
= 0;
1248 PuppetScreenManager::ScreenForRect(int32_t inLeft
, int32_t inTop
,
1249 int32_t inWidth
, int32_t inHeight
,
1250 nsIScreen
** outScreen
) {
1251 return GetPrimaryScreen(outScreen
);
1254 nsIWidgetListener
* PuppetWidget::GetCurrentWidgetListener() {
1255 if (!mPreviouslyAttachedWidgetListener
|| !mAttachedWidgetListener
) {
1256 return mAttachedWidgetListener
;
1259 if (mAttachedWidgetListener
->GetView()->IsPrimaryFramePaintSuppressed()) {
1260 return mPreviouslyAttachedWidgetListener
;
1263 return mAttachedWidgetListener
;
1266 void PuppetWidget::SetCandidateWindowForPlugin(
1267 const CandidateWindowPosition
& aPosition
) {
1268 if (!mBrowserChild
) {
1272 mBrowserChild
->SendSetCandidateWindowForPlugin(aPosition
);
1275 void PuppetWidget::EnableIMEForPlugin(bool aEnable
) {
1276 if (!mBrowserChild
) {
1280 // If current IME state isn't plugin, we ignore this call.
1281 if (NS_WARN_IF(HaveValidInputContextCache() &&
1282 mInputContext
.mIMEState
.mEnabled
!= IMEState::UNKNOWN
&&
1283 mInputContext
.mIMEState
.mEnabled
!= IMEState::PLUGIN
)) {
1287 // We don't have valid state in cache or state is plugin, so delegate to
1289 mBrowserChild
->SendEnableIMEForPlugin(aEnable
);
1292 void PuppetWidget::ZoomToRect(const uint32_t& aPresShellId
,
1293 const ScrollableLayerGuid::ViewID
& aViewId
,
1294 const CSSRect
& aRect
, const uint32_t& aFlags
) {
1295 if (!mBrowserChild
) {
1299 mBrowserChild
->ZoomToRect(aPresShellId
, aViewId
, aRect
, aFlags
);
1302 void PuppetWidget::LookUpDictionary(
1303 const nsAString
& aText
, const nsTArray
<mozilla::FontRange
>& aFontRangeArray
,
1304 const bool aIsVertical
, const LayoutDeviceIntPoint
& aPoint
) {
1305 if (!mBrowserChild
) {
1309 mBrowserChild
->SendLookUpDictionary(nsString(aText
), aFontRangeArray
,
1310 aIsVertical
, aPoint
);
1313 bool PuppetWidget::HasPendingInputEvent() {
1314 if (!mBrowserChild
) {
1320 mBrowserChild
->GetIPCChannel()->PeekMessages(
1321 [&ret
](const IPC::Message
& aMsg
) -> bool {
1322 if (nsContentUtils::IsMessageInputEvent(aMsg
)) {
1324 return false; // Stop peeking.
1332 void PuppetWidget::HandledWindowedPluginKeyEvent(
1333 const NativeEventData
& aKeyEventData
, bool aIsConsumed
) {
1334 if (NS_WARN_IF(mKeyEventInPluginCallbacks
.IsEmpty())) {
1337 nsCOMPtr
<nsIKeyEventInPluginCallback
> callback
=
1338 mKeyEventInPluginCallbacks
[0];
1339 MOZ_ASSERT(callback
);
1340 mKeyEventInPluginCallbacks
.RemoveElementAt(0);
1341 callback
->HandledWindowedPluginKeyEvent(aKeyEventData
, aIsConsumed
);
1344 nsresult
PuppetWidget::OnWindowedPluginKeyEvent(
1345 const NativeEventData
& aKeyEventData
,
1346 nsIKeyEventInPluginCallback
* aCallback
) {
1347 if (NS_WARN_IF(!mBrowserChild
)) {
1348 return NS_ERROR_NOT_AVAILABLE
;
1350 if (NS_WARN_IF(!mBrowserChild
->SendOnWindowedPluginKeyEvent(aKeyEventData
))) {
1351 return NS_ERROR_FAILURE
;
1353 mKeyEventInPluginCallbacks
.AppendElement(aCallback
);
1354 return NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY
;
1357 // TextEventDispatcherListener
1360 PuppetWidget::NotifyIME(TextEventDispatcher
* aTextEventDispatcher
,
1361 const IMENotification
& aIMENotification
) {
1362 MOZ_ASSERT(aTextEventDispatcher
== mTextEventDispatcher
);
1364 // If there is different text event dispatcher listener for handling
1365 // text event dispatcher, that means that native keyboard events and
1366 // IME events are handled in this process. Therefore, we don't need
1367 // to send any requests and notifications to the parent process.
1368 if (mNativeTextEventDispatcherListener
) {
1369 return NS_ERROR_NOT_IMPLEMENTED
;
1372 switch (aIMENotification
.mMessage
) {
1373 case REQUEST_TO_COMMIT_COMPOSITION
:
1374 return RequestIMEToCommitComposition(false);
1375 case REQUEST_TO_CANCEL_COMPOSITION
:
1376 return RequestIMEToCommitComposition(true);
1377 case NOTIFY_IME_OF_FOCUS
:
1378 case NOTIFY_IME_OF_BLUR
:
1379 return NotifyIMEOfFocusChange(aIMENotification
);
1380 case NOTIFY_IME_OF_SELECTION_CHANGE
:
1381 return NotifyIMEOfSelectionChange(aIMENotification
);
1382 case NOTIFY_IME_OF_TEXT_CHANGE
:
1383 return NotifyIMEOfTextChange(aIMENotification
);
1384 case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED
:
1385 return NotifyIMEOfCompositionUpdate(aIMENotification
);
1386 case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT
:
1387 return NotifyIMEOfMouseButtonEvent(aIMENotification
);
1388 case NOTIFY_IME_OF_POSITION_CHANGE
:
1389 return NotifyIMEOfPositionChange(aIMENotification
);
1391 return NS_ERROR_NOT_IMPLEMENTED
;
1394 return NS_ERROR_NOT_IMPLEMENTED
;
1397 NS_IMETHODIMP_(IMENotificationRequests
)
1398 PuppetWidget::GetIMENotificationRequests() {
1399 if (mInputContext
.mIMEState
.mEnabled
== IMEState::PLUGIN
) {
1400 // If a plugin has focus, we cannot receive text nor selection change
1401 // in the plugin. Therefore, PuppetWidget needs to receive only position
1402 // change event for updating the editor rect cache.
1403 return IMENotificationRequests(
1404 mIMENotificationRequestsOfParent
.mWantUpdates
|
1405 IMENotificationRequests::NOTIFY_POSITION_CHANGE
);
1407 return IMENotificationRequests(
1408 mIMENotificationRequestsOfParent
.mWantUpdates
|
1409 IMENotificationRequests::NOTIFY_TEXT_CHANGE
|
1410 IMENotificationRequests::NOTIFY_POSITION_CHANGE
);
1413 NS_IMETHODIMP_(void)
1414 PuppetWidget::OnRemovedFrom(TextEventDispatcher
* aTextEventDispatcher
) {
1415 MOZ_ASSERT(aTextEventDispatcher
== mTextEventDispatcher
);
1418 NS_IMETHODIMP_(void)
1419 PuppetWidget::WillDispatchKeyboardEvent(
1420 TextEventDispatcher
* aTextEventDispatcher
,
1421 WidgetKeyboardEvent
& aKeyboardEvent
, uint32_t aIndexOfKeypress
,
1423 MOZ_ASSERT(aTextEventDispatcher
== mTextEventDispatcher
);
1426 nsresult
PuppetWidget::SetSystemFont(const nsCString
& aFontName
) {
1427 if (!mBrowserChild
) {
1428 return NS_ERROR_FAILURE
;
1431 mBrowserChild
->SendSetSystemFont(aFontName
);
1435 nsresult
PuppetWidget::GetSystemFont(nsCString
& aFontName
) {
1436 if (!mBrowserChild
) {
1437 return NS_ERROR_FAILURE
;
1439 mBrowserChild
->SendGetSystemFont(&aFontName
);
1443 nsresult
PuppetWidget::SetPrefersReducedMotionOverrideForTest(bool aValue
) {
1444 if (!mBrowserChild
) {
1445 return NS_ERROR_FAILURE
;
1448 mBrowserChild
->SendSetPrefersReducedMotionOverrideForTest(aValue
);
1452 nsresult
PuppetWidget::ResetPrefersReducedMotionOverrideForTest() {
1453 if (!mBrowserChild
) {
1454 return NS_ERROR_FAILURE
;
1457 mBrowserChild
->SendResetPrefersReducedMotionOverrideForTest();
1461 } // namespace widget
1462 } // namespace mozilla