Bug 1608587 [wpt PR 21137] - Update wpt metadata, a=testonly
[gecko.git] / widget / PuppetWidget.cpp
blob36726e6dd32e8cbae40f68b50c0ffd33fc6b8e9b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
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"
32 #include "nsView.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());
50 /*static*/
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();
60 namespace mozilla {
61 namespace widget {
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);
72 #else
73 return false;
74 #endif
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),
86 mDPI(-1),
87 mRounding(1),
88 mDefaultScale(-1),
89 mCursorHotspotX(0),
90 mCursorHotspotY(0),
91 mEnabled(false),
92 mVisible(false),
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);
109 mBounds = aRect;
110 mEnabled = true;
111 mVisible = true;
113 mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
114 IntSize(1, 1), SurfaceFormat::B8G8R8A8);
116 mNeedIMEStateInit = MightNeedIMEFocus(aInitData);
118 PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
119 if (parent) {
120 parent->SetChild(this);
121 mLayerManager = parent->GetLayerManager();
122 } else {
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);
132 return NS_OK;
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)))
152 ? widget.forget()
153 : nullptr);
156 void PuppetWidget::Destroy() {
157 if (mOnDestroyCalled) {
158 return;
160 mOnDestroyCalled = true;
162 Base::OnDestroy();
163 Base::Destroy();
164 mPaintTask.Revoke();
165 if (mMemoryPressureObserver) {
166 mMemoryPressureObserver->Unregister();
167 mMemoryPressureObserver = nullptr;
169 mChild = nullptr;
170 if (mLayerManager) {
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;
182 mVisible = aState;
184 if (mChild) {
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
196 // bug 1323586).
197 mPreviouslyAttachedWidgetListener = nullptr;
198 Resize(mBounds.Width(), mBounds.Height(), false);
199 Invalidate(mBounds);
203 void PuppetWidget::Resize(double aWidth, double aHeight, bool aRepaint) {
204 LayoutDeviceIntRect oldBounds = mBounds;
205 mBounds.SizeTo(
206 LayoutDeviceIntSize(NSToIntRound(aWidth), NSToIntRound(aHeight)));
208 if (mChild) {
209 mChild->Resize(aWidth, aHeight, aRepaint);
210 return;
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(),
228 mBounds.Height());
230 mAttachedWidgetListener->WindowResized(this, mBounds.Width(),
231 mBounds.Height());
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(),
246 true);
247 } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
248 w->Move(configuration.mBounds.X(), configuration.mBounds.Y());
250 w->SetWindowClipRegion(configuration.mClipRegion, false);
252 return NS_OK;
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) {
262 #ifdef DEBUG
263 debug_DumpInvalidate(stderr, this, &aRect, "PuppetWidget", 0);
264 #endif
266 if (mChild) {
267 mChild->Invalidate(aRect);
268 return;
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());
277 return;
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);
294 } else {
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) {
303 #ifdef DEBUG
304 debug_DumpEvent(stdout, aEvent->mWidget, aEvent, "PuppetWidget", 0);
305 #endif
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 "
314 "all types "
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;
326 return NS_OK;
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();
335 #ifdef DEBUG
336 if (mNativeIMEContext.IsValid() &&
337 mNativeIMEContext != compositionEvent->mNativeIMEContext) {
338 RefPtr<TextComposition> composition =
339 IMEStateManager::GetTextCompositionFor(this);
340 MOZ_ASSERT(
341 !composition,
342 "When there is composition caused by old native IME context, "
343 "composition events caused by different native IME context are not "
344 "allowed");
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
355 // with events here.
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(
371 NS_SUCCEEDED(rv),
372 "The text event dispatcher should always succeed to start input "
373 "transaction for the event");
377 aStatus = nsEventStatus_eIgnore;
379 if (GetCurrentWidgetListener()) {
380 aStatus =
381 GetCurrentWidgetListener()->HandleEvent(aEvent, mUseAttachedEvents);
384 return NS_OK;
387 nsEventStatus PuppetWidget::DispatchInputEvent(WidgetInputEvent* aEvent) {
388 if (!AsyncPanZoomEnabled()) {
389 nsEventStatus status = nsEventStatus_eIgnore;
390 DispatchEvent(aEvent, status);
391 return 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());
410 break;
411 case eMouseEventClass:
412 Unused << mBrowserChild->SendDispatchMouseEvent(*aEvent->AsMouseEvent());
413 break;
414 case eKeyboardEventClass:
415 Unused << mBrowserChild->SendDispatchKeyboardEvent(
416 *aEvent->AsKeyboardEvent());
417 break;
418 default:
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());
437 return NS_OK;
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());
449 return NS_OK;
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());
459 return NS_OK;
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());
473 return NS_OK;
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());
487 return NS_OK;
490 nsresult PuppetWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint,
491 bool aLongTap,
492 nsIObserver* aObserver) {
493 AutoObserverNotifier notifier(aObserver, "touchtap");
494 if (!mBrowserChild) {
495 return NS_ERROR_FAILURE;
497 mBrowserChild->SendSynthesizeNativeTouchTap(aPoint, aLongTap,
498 notifier.SaveObserver());
499 return NS_OK;
502 nsresult PuppetWidget::ClearNativeTouchSequence(nsIObserver* aObserver) {
503 AutoObserverNotifier notifier(aObserver, "cleartouch");
504 if (!mBrowserChild) {
505 return NS_ERROR_FAILURE;
507 mBrowserChild->SendClearNativeTouchSequence(notifier.SaveObserver());
508 return NS_OK;
511 void PuppetWidget::SetConfirmedTargetAPZC(
512 uint64_t aInputBlockId,
513 const nsTArray<SLGuidAndRenderRoot>& aTargets) const {
514 if (mBrowserChild) {
515 mBrowserChild->SetTargetAPZC(aInputBlockId, aTargets);
519 void PuppetWidget::UpdateZoomConstraints(
520 const uint32_t& aPresShellId, const ScrollableLayerGuid::ViewID& aViewId,
521 const Maybe<ZoomConstraints>& aConstraints) {
522 if (mBrowserChild) {
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))) {
536 return false;
538 if (NS_WARN_IF(!mBrowserChild)) {
539 return false;
541 mBrowserChild->RequestEditCommands(aType, aEvent, aCommands);
542 return true;
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);
575 } else {
576 lm = new ClientLayerManager(this);
579 if (!aInitializeFunc(lm)) {
580 return false;
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();
589 return true;
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())) {
601 return NS_OK;
604 // We've already requested to commit/cancel composition.
605 if (NS_WARN_IF(mIgnoreCompositionEvents)) {
606 #ifdef DEBUG
607 RefPtr<TextComposition> composition =
608 IMEStateManager::GetTextCompositionFor(this);
609 MOZ_ASSERT(!composition);
610 #endif // #ifdef DEBUG
611 return NS_OK;
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)) {
618 return NS_OK;
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.
635 if (!isCommitted) {
636 return NS_OK;
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);
646 #ifdef DEBUG
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.
660 return NS_OK;
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);
691 return NS_OK;
694 void PuppetWidget::SetPluginFocused(bool& aFocused) {
695 if (mBrowserChild) {
696 mBrowserChild->SendSetPluginFocused(aFocused);
700 void PuppetWidget::DefaultProcOfPluginEvent(const WidgetPluginEvent& aEvent) {
701 if (!mBrowserChild) {
702 return;
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) {
722 return;
724 mBrowserChild->SendSetInputContext(aContext, aAction);
727 InputContext PuppetWidget::GetInputContext() {
728 // XXX Currently, we don't support retrieving IME open state from child
729 // process.
731 // If the cache of input context is valid, we can avoid to use synchronous
732 // IPC.
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;
743 if (mBrowserChild) {
744 mBrowserChild->SendGetInputContext(&context.mIMEState);
746 return context;
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;
760 if (gotFocus) {
761 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN) {
762 // When IME gets focus, we should initalize all information of the
763 // content.
764 if (NS_WARN_IF(!mContentCache.CacheAll(this, &aIMENotification))) {
765 return NS_ERROR_FAILURE;
767 } else {
768 // However, if a plugin has focus, only the editor rect information is
769 // available.
770 if (NS_WARN_IF(!mContentCache.CacheEditorRect(this, &aIMENotification))) {
771 return NS_ERROR_FAILURE;
774 } else {
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)
783 ->Then(
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.");
796 return NS_OK;
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,
810 aIMENotification);
811 return NS_OK;
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);
839 } else {
840 mBrowserChild->SendUpdateContentCache(mContentCache);
842 return NS_OK;
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
854 // available.
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);
869 return NS_OK;
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
879 // available.
880 if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
881 return NS_ERROR_FAILURE;
884 bool consumedByIME = false;
885 if (!mBrowserChild->SendNotifyIMEMouseButtonEvent(aIMENotification,
886 &consumedByIME)) {
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);
910 } else {
911 mBrowserChild->SendUpdateContentCache(mContentCache);
913 return NS_OK;
916 struct CursorSurface {
917 UniquePtr<char[]> mData;
918 IntSize mSize;
921 void PuppetWidget::SetCursor(nsCursor aCursor, imgIContainer* aCursorImage,
922 uint32_t aHotspotX, uint32_t aHotspotY) {
923 if (!mBrowserChild) {
924 return;
927 // Don't cache on windows, Windowless flash breaks this via async cursor
928 // updates.
929 #if !defined(XP_WIN)
930 if (!mUpdateCursor && mCursor == aCursor && mCustomCursor == aCursorImage &&
931 (!aCursorImage ||
932 (mCursorHotspotX == aHotspotX && mCursorHotspotY == aHotspotY))) {
933 return;
935 #endif
937 bool hasCustomCursor = false;
938 UniquePtr<char[]> customCursorData;
939 size_t length = 0;
940 IntSize customCursorSize;
941 int32_t stride = 0;
942 auto format = SurfaceFormat::B8G8R8A8;
943 bool force = mUpdateCursor;
945 if (aCursorImage) {
946 RefPtr<SourceSurface> surface = aCursorImage->GetFrame(
947 imgIContainer::FRAME_CURRENT,
948 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
949 if (surface) {
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() : "",
963 length);
964 if (!mBrowserChild->SendSetCursor(aCursor, hasCustomCursor, cursorData,
965 customCursorSize.width,
966 customCursorSize.height, stride, format,
967 aHotspotX, aHotspotY, force)) {
968 return;
971 mCursor = aCursor;
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();
992 mPaintTask.Revoke();
994 RefPtr<PuppetWidget> strongThis(this);
996 GetCurrentWidgetListener()->WillPaintWindow(this);
998 if (GetCurrentWidgetListener()) {
999 #ifdef DEBUG
1000 debug_DumpPaintEvent(stderr, this, region.ToUnknownRegion(), "PuppetWidget",
1002 #endif
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);
1018 if (!ctx) {
1019 gfxDevCrash(LogReason::InvalidContext)
1020 << "PuppetWidget context problem " << gfx::hexa(mDrawTarget);
1021 return NS_ERROR_FAILURE;
1023 ctx->Rectangle(gfxRect(0, 0, 0, 0));
1024 ctx->Clip();
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();
1038 return NS_OK;
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");
1046 mChild = aChild;
1049 NS_IMETHODIMP
1050 PuppetWidget::PaintTask::Run() {
1051 if (mWidget) {
1052 mWidget->Paint();
1054 return NS_OK;
1057 void PuppetWidget::PaintNowIfNeeded() {
1058 if (IsVisible() && mPaintTask.IsPending()) {
1059 Paint();
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
1072 // here
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!");
1077 return false;
1080 return mVisible;
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).
1107 break;
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:
1113 default:
1114 NS_WARNING("nsWindow::GetNativeData called with bad value");
1115 break;
1117 return nullptr;
1120 #if defined(XP_WIN)
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);
1128 break;
1129 default:
1130 NS_WARNING("SetNativeData called with unsupported data type.");
1133 #endif
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;
1149 NS_ENSURE_SUCCESS(
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();
1163 if (!visibleRect) {
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);
1185 return config;
1188 nsIntSize PuppetWidget::GetScreenDimensions() {
1189 nsIntRect r = ScreenConfig().rect();
1190 return nsIntSize(r.Width(), r.Height());
1193 NS_IMETHODIMP
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);
1198 return NS_OK;
1201 NS_IMETHODIMP
1202 PuppetScreen::GetAvailRect(int32_t* outLeft, int32_t* outTop, int32_t* outWidth,
1203 int32_t* outHeight) {
1204 return GetRect(outLeft, outTop, outWidth, outHeight);
1207 NS_IMETHODIMP
1208 PuppetScreen::GetPixelDepth(int32_t* aPixelDepth) {
1209 *aPixelDepth = ScreenConfig().pixelDepth();
1210 return NS_OK;
1213 NS_IMETHODIMP
1214 PuppetScreen::GetColorDepth(int32_t* aColorDepth) {
1215 *aColorDepth = ScreenConfig().colorDepth();
1216 return NS_OK;
1219 NS_IMPL_ISUPPORTS(PuppetScreenManager, nsIScreenManager)
1221 PuppetScreenManager::PuppetScreenManager() {
1222 mOneScreen = new PuppetScreen(nullptr);
1225 PuppetScreenManager::~PuppetScreenManager() {}
1227 NS_IMETHODIMP
1228 PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen) {
1229 NS_IF_ADDREF(*outScreen = mOneScreen.get());
1230 return NS_OK;
1233 NS_IMETHODIMP
1234 PuppetScreenManager::GetTotalScreenPixels(int64_t* aTotalScreenPixels) {
1235 MOZ_ASSERT(aTotalScreenPixels);
1236 if (mOneScreen) {
1237 int32_t x, y, width, height;
1238 x = y = width = height = 0;
1239 mOneScreen->GetRect(&x, &y, &width, &height);
1240 *aTotalScreenPixels = width * height;
1241 } else {
1242 *aTotalScreenPixels = 0;
1244 return NS_OK;
1247 NS_IMETHODIMP
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) {
1269 return;
1272 mBrowserChild->SendSetCandidateWindowForPlugin(aPosition);
1275 void PuppetWidget::EnableIMEForPlugin(bool aEnable) {
1276 if (!mBrowserChild) {
1277 return;
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)) {
1284 return;
1287 // We don't have valid state in cache or state is plugin, so delegate to
1288 // chrome process.
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) {
1296 return;
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) {
1306 return;
1309 mBrowserChild->SendLookUpDictionary(nsString(aText), aFontRangeArray,
1310 aIsVertical, aPoint);
1313 bool PuppetWidget::HasPendingInputEvent() {
1314 if (!mBrowserChild) {
1315 return false;
1318 bool ret = false;
1320 mBrowserChild->GetIPCChannel()->PeekMessages(
1321 [&ret](const IPC::Message& aMsg) -> bool {
1322 if (nsContentUtils::IsMessageInputEvent(aMsg)) {
1323 ret = true;
1324 return false; // Stop peeking.
1326 return true;
1329 return ret;
1332 void PuppetWidget::HandledWindowedPluginKeyEvent(
1333 const NativeEventData& aKeyEventData, bool aIsConsumed) {
1334 if (NS_WARN_IF(mKeyEventInPluginCallbacks.IsEmpty())) {
1335 return;
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
1359 NS_IMETHODIMP
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);
1390 default:
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,
1422 void* aData) {
1423 MOZ_ASSERT(aTextEventDispatcher == mTextEventDispatcher);
1426 nsresult PuppetWidget::SetSystemFont(const nsCString& aFontName) {
1427 if (!mBrowserChild) {
1428 return NS_ERROR_FAILURE;
1431 mBrowserChild->SendSetSystemFont(aFontName);
1432 return NS_OK;
1435 nsresult PuppetWidget::GetSystemFont(nsCString& aFontName) {
1436 if (!mBrowserChild) {
1437 return NS_ERROR_FAILURE;
1439 mBrowserChild->SendGetSystemFont(&aFontName);
1440 return NS_OK;
1443 nsresult PuppetWidget::SetPrefersReducedMotionOverrideForTest(bool aValue) {
1444 if (!mBrowserChild) {
1445 return NS_ERROR_FAILURE;
1448 mBrowserChild->SendSetPrefersReducedMotionOverrideForTest(aValue);
1449 return NS_OK;
1452 nsresult PuppetWidget::ResetPrefersReducedMotionOverrideForTest() {
1453 if (!mBrowserChild) {
1454 return NS_ERROR_FAILURE;
1457 mBrowserChild->SendResetPrefersReducedMotionOverrideForTest();
1458 return NS_OK;
1461 } // namespace widget
1462 } // namespace mozilla