Bug 1673311 [wpt PR 26282] - Fieldset NG: Percentage heights for content elements...
[gecko.git] / widget / PuppetWidget.cpp
blobf5b1eefcd3d2213b2ebef9d5dabad79b7e8cfd26
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 "nsRefreshDriver.h"
13 #include "mozilla/dom/BrowserChild.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/SchedulerGroup.h"
23 #include "mozilla/StaticPrefs_browser.h"
24 #include "mozilla/TextComposition.h"
25 #include "mozilla/TextEventDispatcher.h"
26 #include "mozilla/TextEvents.h"
27 #include "mozilla/Unused.h"
28 #include "BasicLayers.h"
29 #include "PuppetWidget.h"
30 #include "nsContentUtils.h"
31 #include "nsIWidgetListener.h"
32 #include "imgIContainer.h"
33 #include "nsView.h"
34 #include "nsXPLookAndFeel.h"
35 #include "nsPrintfCString.h"
37 using namespace mozilla;
38 using namespace mozilla::dom;
39 using namespace mozilla::hal;
40 using namespace mozilla::gfx;
41 using namespace mozilla::layers;
42 using namespace mozilla::widget;
44 static void InvalidateRegion(nsIWidget* aWidget,
45 const LayoutDeviceIntRegion& aRegion) {
46 for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
47 aWidget->Invalidate(iter.Get());
51 /*static*/
52 already_AddRefed<nsIWidget> nsIWidget::CreatePuppetWidget(
53 BrowserChild* aBrowserChild) {
54 MOZ_ASSERT(!aBrowserChild || nsIWidget::UsePuppetWidgets(),
55 "PuppetWidgets not allowed in this configuration");
57 nsCOMPtr<nsIWidget> widget = new PuppetWidget(aBrowserChild);
58 return widget.forget();
61 namespace mozilla {
62 namespace widget {
64 static bool IsPopup(const nsWidgetInitData* aInitData) {
65 return aInitData && aInitData->mWindowType == eWindowType_popup;
68 static bool MightNeedIMEFocus(const nsWidgetInitData* aInitData) {
69 // In the puppet-widget world, popup widgets are just dummies and
70 // shouldn't try to mess with IME state.
71 #ifdef MOZ_CROSS_PROCESS_IME
72 return !IsPopup(aInitData);
73 #else
74 return false;
75 #endif
78 // Arbitrary, fungible.
79 const size_t PuppetWidget::kMaxDimension = 4000;
81 NS_IMPL_ISUPPORTS_INHERITED(PuppetWidget, nsBaseWidget,
82 TextEventDispatcherListener)
84 PuppetWidget::PuppetWidget(BrowserChild* aBrowserChild)
85 : mBrowserChild(aBrowserChild),
86 mMemoryPressureObserver(nullptr),
87 mDPI(-1),
88 mRounding(1),
89 mDefaultScale(-1),
90 mCursorHotspotX(0),
91 mCursorHotspotY(0),
92 mEnabled(false),
93 mVisible(false),
94 mNeedIMEStateInit(false),
95 mIgnoreCompositionEvents(false) {
96 // Setting 'Unknown' means "not yet cached".
97 mInputContext.mIMEState.mEnabled = IMEState::UNKNOWN;
100 PuppetWidget::~PuppetWidget() { Destroy(); }
102 void PuppetWidget::InfallibleCreate(nsIWidget* aParent,
103 nsNativeWidget aNativeParent,
104 const LayoutDeviceIntRect& aRect,
105 nsWidgetInitData* aInitData) {
106 MOZ_ASSERT(!aNativeParent, "got a non-Puppet native parent");
108 BaseCreate(nullptr, aInitData);
110 mBounds = aRect;
111 mEnabled = true;
112 mVisible = true;
114 mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
115 IntSize(1, 1), SurfaceFormat::B8G8R8A8);
117 mNeedIMEStateInit = MightNeedIMEFocus(aInitData);
119 PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
120 if (parent) {
121 parent->SetChild(this);
122 mLayerManager = parent->GetLayerManager();
123 } else {
124 Resize(mBounds.X(), mBounds.Y(), mBounds.Width(), mBounds.Height(), false);
126 mMemoryPressureObserver = MemoryPressureObserver::Create(this);
129 nsresult PuppetWidget::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
130 const LayoutDeviceIntRect& aRect,
131 nsWidgetInitData* aInitData) {
132 InfallibleCreate(aParent, aNativeParent, aRect, aInitData);
133 return NS_OK;
136 void PuppetWidget::InitIMEState() {
137 MOZ_ASSERT(mBrowserChild);
138 if (mNeedIMEStateInit) {
139 mContentCache.Clear();
140 mBrowserChild->SendUpdateContentCache(mContentCache);
141 mIMENotificationRequestsOfParent = IMENotificationRequests();
142 mNeedIMEStateInit = false;
146 already_AddRefed<nsIWidget> PuppetWidget::CreateChild(
147 const LayoutDeviceIntRect& aRect, nsWidgetInitData* aInitData,
148 bool aForceUseIWidgetParent) {
149 bool isPopup = IsPopup(aInitData);
150 nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(mBrowserChild);
151 return ((widget && NS_SUCCEEDED(widget->Create(isPopup ? nullptr : this,
152 nullptr, aRect, aInitData)))
153 ? widget.forget()
154 : nullptr);
157 void PuppetWidget::Destroy() {
158 if (mOnDestroyCalled) {
159 return;
161 mOnDestroyCalled = true;
163 Base::OnDestroy();
164 Base::Destroy();
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 if (mBrowserChild && !aRect.IsEmpty()) {
272 if (RefPtr<nsRefreshDriver> refreshDriver = GetTopLevelRefreshDriver()) {
273 refreshDriver->ScheduleViewManagerFlush();
278 mozilla::LayoutDeviceToLayoutDeviceMatrix4x4
279 PuppetWidget::WidgetToTopLevelWidgetTransform() {
280 if (!GetOwningBrowserChild()) {
281 NS_WARNING("PuppetWidget without Tab does not have transform information.");
282 return mozilla::LayoutDeviceToLayoutDeviceMatrix4x4();
284 return GetOwningBrowserChild()->GetChildToParentConversionMatrix();
287 void PuppetWidget::InitEvent(WidgetGUIEvent& aEvent,
288 LayoutDeviceIntPoint* aPoint) {
289 if (nullptr == aPoint) {
290 aEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
291 } else {
292 // use the point override if provided
293 aEvent.mRefPoint = *aPoint;
295 aEvent.mTime = PR_Now() / 1000;
298 nsresult PuppetWidget::DispatchEvent(WidgetGUIEvent* aEvent,
299 nsEventStatus& aStatus) {
300 #ifdef DEBUG
301 debug_DumpEvent(stdout, aEvent->mWidget, aEvent, "PuppetWidget", 0);
302 #endif
304 MOZ_ASSERT(!mChild || mChild->mWindowType == eWindowType_popup,
305 "Unexpected event dispatch!");
307 MOZ_ASSERT(!aEvent->AsKeyboardEvent() ||
308 aEvent->mFlags.mIsSynthesizedForTests ||
309 aEvent->AsKeyboardEvent()->AreAllEditCommandsInitialized(),
310 "Non-sysnthesized keyboard events should have edit commands for "
311 "all types "
312 "before dispatched");
314 if (aEvent->mClass == eCompositionEventClass) {
315 // If we've already requested to commit/cancel the latest composition,
316 // TextComposition for the old composition has been destroyed. Then,
317 // the DOM tree needs to listen to next eCompositionStart and its
318 // following events. So, until we meet new eCompositionStart, let's
319 // discard all unnecessary composition events here.
320 if (mIgnoreCompositionEvents) {
321 if (aEvent->mMessage != eCompositionStart) {
322 aStatus = nsEventStatus_eIgnore;
323 return NS_OK;
325 // Now, we receive new eCompositionStart. Let's restart to handle
326 // composition in this process.
327 mIgnoreCompositionEvents = false;
329 // Store the latest native IME context of parent process's widget or
330 // TextEventDispatcher if it's in this process.
331 WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
332 #ifdef DEBUG
333 if (mNativeIMEContext.IsValid() &&
334 mNativeIMEContext != compositionEvent->mNativeIMEContext) {
335 RefPtr<TextComposition> composition =
336 IMEStateManager::GetTextCompositionFor(this);
337 MOZ_ASSERT(
338 !composition,
339 "When there is composition caused by old native IME context, "
340 "composition events caused by different native IME context are not "
341 "allowed");
343 #endif // #ifdef DEBUG
344 mNativeIMEContext = compositionEvent->mNativeIMEContext;
347 // If the event is a composition event or a keyboard event, it should be
348 // dispatched with TextEventDispatcher if we could do that with current
349 // design. However, we cannot do that without big changes and the behavior
350 // is not so complicated for now. Therefore, we should just notify it
351 // of dispatching events and TextEventDispatcher should emulate the state
352 // with events here.
353 if (aEvent->mClass == eCompositionEventClass ||
354 aEvent->mClass == eKeyboardEventClass) {
355 TextEventDispatcher* dispatcher = GetTextEventDispatcher();
356 // However, if the event is being dispatched by the text event dispatcher
357 // or, there is native text event dispatcher listener, that means that
358 // native text input event handler is in this process like on Android,
359 // and the event is not synthesized for tests, the event is coming from
360 // the TextEventDispatcher. In these cases, we shouldn't notify
361 // TextEventDispatcher of dispatching the event.
362 if (!dispatcher->IsDispatchingEvent() &&
363 !(mNativeTextEventDispatcherListener &&
364 !aEvent->mFlags.mIsSynthesizedForTests)) {
365 DebugOnly<nsresult> rv =
366 dispatcher->BeginInputTransactionFor(aEvent, this);
367 NS_WARNING_ASSERTION(
368 NS_SUCCEEDED(rv),
369 "The text event dispatcher should always succeed to start input "
370 "transaction for the event");
374 aStatus = nsEventStatus_eIgnore;
376 if (GetCurrentWidgetListener()) {
377 aStatus =
378 GetCurrentWidgetListener()->HandleEvent(aEvent, mUseAttachedEvents);
381 return NS_OK;
384 nsEventStatus PuppetWidget::DispatchInputEvent(WidgetInputEvent* aEvent) {
385 if (!AsyncPanZoomEnabled()) {
386 nsEventStatus status = nsEventStatus_eIgnore;
387 DispatchEvent(aEvent, status);
388 return status;
391 if (!mBrowserChild) {
392 return nsEventStatus_eIgnore;
395 switch (aEvent->mClass) {
396 case eWheelEventClass:
397 Unused << mBrowserChild->SendDispatchWheelEvent(*aEvent->AsWheelEvent());
398 break;
399 case eMouseEventClass:
400 Unused << mBrowserChild->SendDispatchMouseEvent(*aEvent->AsMouseEvent());
401 break;
402 case eKeyboardEventClass:
403 Unused << mBrowserChild->SendDispatchKeyboardEvent(
404 *aEvent->AsKeyboardEvent());
405 break;
406 default:
407 MOZ_ASSERT_UNREACHABLE("unsupported event type");
410 return nsEventStatus_eIgnore;
413 nsresult PuppetWidget::SynthesizeNativeKeyEvent(
414 int32_t aNativeKeyboardLayout, int32_t aNativeKeyCode,
415 uint32_t aModifierFlags, const nsAString& aCharacters,
416 const nsAString& aUnmodifiedCharacters, nsIObserver* aObserver) {
417 AutoObserverNotifier notifier(aObserver, "keyevent");
418 if (!mBrowserChild) {
419 return NS_ERROR_FAILURE;
421 mBrowserChild->SendSynthesizeNativeKeyEvent(
422 aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags,
423 nsString(aCharacters), nsString(aUnmodifiedCharacters),
424 notifier.SaveObserver());
425 return NS_OK;
428 nsresult PuppetWidget::SynthesizeNativeMouseEvent(
429 mozilla::LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
430 uint32_t aModifierFlags, nsIObserver* aObserver) {
431 AutoObserverNotifier notifier(aObserver, "mouseevent");
432 if (!mBrowserChild) {
433 return NS_ERROR_FAILURE;
435 mBrowserChild->SendSynthesizeNativeMouseEvent(
436 aPoint, aNativeMessage, aModifierFlags, notifier.SaveObserver());
437 return NS_OK;
440 nsresult PuppetWidget::SynthesizeNativeMouseMove(
441 mozilla::LayoutDeviceIntPoint aPoint, nsIObserver* aObserver) {
442 AutoObserverNotifier notifier(aObserver, "mousemove");
443 if (!mBrowserChild) {
444 return NS_ERROR_FAILURE;
446 mBrowserChild->SendSynthesizeNativeMouseMove(aPoint, notifier.SaveObserver());
447 return NS_OK;
450 nsresult PuppetWidget::SynthesizeNativeMouseScrollEvent(
451 mozilla::LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
452 double aDeltaX, double aDeltaY, double aDeltaZ, uint32_t aModifierFlags,
453 uint32_t aAdditionalFlags, nsIObserver* aObserver) {
454 AutoObserverNotifier notifier(aObserver, "mousescrollevent");
455 if (!mBrowserChild) {
456 return NS_ERROR_FAILURE;
458 mBrowserChild->SendSynthesizeNativeMouseScrollEvent(
459 aPoint, aNativeMessage, aDeltaX, aDeltaY, aDeltaZ, aModifierFlags,
460 aAdditionalFlags, notifier.SaveObserver());
461 return NS_OK;
464 nsresult PuppetWidget::SynthesizeNativeTouchPoint(
465 uint32_t aPointerId, TouchPointerState aPointerState,
466 LayoutDeviceIntPoint aPoint, double aPointerPressure,
467 uint32_t aPointerOrientation, nsIObserver* aObserver) {
468 AutoObserverNotifier notifier(aObserver, "touchpoint");
469 if (!mBrowserChild) {
470 return NS_ERROR_FAILURE;
472 mBrowserChild->SendSynthesizeNativeTouchPoint(
473 aPointerId, aPointerState, aPoint, aPointerPressure, aPointerOrientation,
474 notifier.SaveObserver());
475 return NS_OK;
478 nsresult PuppetWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint,
479 bool aLongTap,
480 nsIObserver* aObserver) {
481 AutoObserverNotifier notifier(aObserver, "touchtap");
482 if (!mBrowserChild) {
483 return NS_ERROR_FAILURE;
485 mBrowserChild->SendSynthesizeNativeTouchTap(aPoint, aLongTap,
486 notifier.SaveObserver());
487 return NS_OK;
490 nsresult PuppetWidget::ClearNativeTouchSequence(nsIObserver* aObserver) {
491 AutoObserverNotifier notifier(aObserver, "cleartouch");
492 if (!mBrowserChild) {
493 return NS_ERROR_FAILURE;
495 mBrowserChild->SendClearNativeTouchSequence(notifier.SaveObserver());
496 return NS_OK;
499 void PuppetWidget::SetConfirmedTargetAPZC(
500 uint64_t aInputBlockId,
501 const nsTArray<ScrollableLayerGuid>& aTargets) const {
502 if (mBrowserChild) {
503 mBrowserChild->SetTargetAPZC(aInputBlockId, aTargets);
507 void PuppetWidget::UpdateZoomConstraints(
508 const uint32_t& aPresShellId, const ScrollableLayerGuid::ViewID& aViewId,
509 const Maybe<ZoomConstraints>& aConstraints) {
510 if (mBrowserChild) {
511 mBrowserChild->DoUpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
515 bool PuppetWidget::AsyncPanZoomEnabled() const {
516 return mBrowserChild && mBrowserChild->AsyncPanZoomEnabled();
519 bool PuppetWidget::GetEditCommands(NativeKeyBindingsType aType,
520 const WidgetKeyboardEvent& aEvent,
521 nsTArray<CommandInt>& aCommands) {
522 // Validate the arguments.
523 if (NS_WARN_IF(!nsIWidget::GetEditCommands(aType, aEvent, aCommands))) {
524 return false;
526 if (NS_WARN_IF(!mBrowserChild)) {
527 return false;
529 mBrowserChild->RequestEditCommands(aType, aEvent, aCommands);
530 return true;
533 LayerManager* PuppetWidget::GetLayerManager(
534 PLayerTransactionChild* aShadowManager, LayersBackend aBackendHint,
535 LayerManagerPersistence aPersistence) {
536 if (!mLayerManager) {
537 if (XRE_IsParentProcess()) {
538 // On the parent process there is no CompositorBridgeChild which confuses
539 // some layers code, so we use basic layers instead. Note that we create
540 // a non-retaining layer manager since we don't care about performance.
541 mLayerManager = new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN);
542 return mLayerManager;
545 // If we know for sure that the parent side of this BrowserChild is not
546 // connected to the compositor, we don't want to use a "remote" layer
547 // manager like WebRender or Client. Instead we use a Basic one which
548 // can do drawing in this process.
549 MOZ_ASSERT(!mBrowserChild ||
550 mBrowserChild->IsLayersConnected() != Some(true));
551 mLayerManager = new BasicLayerManager(this);
554 return mLayerManager;
557 bool PuppetWidget::CreateRemoteLayerManager(
558 const std::function<bool(LayerManager*)>& aInitializeFunc) {
559 RefPtr<LayerManager> lm;
560 MOZ_ASSERT(mBrowserChild);
561 if (mBrowserChild->GetCompositorOptions().UseWebRender()) {
562 lm = new WebRenderLayerManager(this);
563 } else {
564 lm = new ClientLayerManager(this);
567 if (!aInitializeFunc(lm)) {
568 return false;
571 // Force the old LM to self destruct, otherwise if the reference dangles we
572 // could fail to revoke the most recent transaction. We only want to replace
573 // it if we successfully create its successor because a partially initialized
574 // layer manager is worse than a fully initialized but shutdown layer manager.
575 DestroyLayerManager();
576 mLayerManager = std::move(lm);
577 return true;
580 nsresult PuppetWidget::RequestIMEToCommitComposition(bool aCancel) {
581 if (!mBrowserChild) {
582 return NS_ERROR_FAILURE;
585 MOZ_ASSERT(!Destroyed());
587 // There must not be composition which is caused by the PuppetWidget instance.
588 if (NS_WARN_IF(!mNativeIMEContext.IsValid())) {
589 return NS_OK;
592 // We've already requested to commit/cancel composition.
593 if (NS_WARN_IF(mIgnoreCompositionEvents)) {
594 #ifdef DEBUG
595 RefPtr<TextComposition> composition =
596 IMEStateManager::GetTextCompositionFor(this);
597 MOZ_ASSERT(!composition);
598 #endif // #ifdef DEBUG
599 return NS_OK;
602 RefPtr<TextComposition> composition =
603 IMEStateManager::GetTextCompositionFor(this);
604 // This method shouldn't be called when there is no text composition instance.
605 if (NS_WARN_IF(!composition)) {
606 return NS_OK;
609 MOZ_DIAGNOSTIC_ASSERT(
610 composition->IsRequestingCommitOrCancelComposition(),
611 "Requesting commit or cancel composition should be requested via "
612 "TextComposition instance");
614 bool isCommitted = false;
615 nsAutoString committedString;
616 if (NS_WARN_IF(!mBrowserChild->SendRequestIMEToCommitComposition(
617 aCancel, &isCommitted, &committedString))) {
618 return NS_ERROR_FAILURE;
621 // If the composition wasn't committed synchronously, we need to wait async
622 // composition events for destroying the TextComposition instance.
623 if (!isCommitted) {
624 return NS_OK;
627 // Dispatch eCompositionCommit event.
628 WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommit, this);
629 InitEvent(compositionCommitEvent, nullptr);
630 compositionCommitEvent.mData = committedString;
631 nsEventStatus status = nsEventStatus_eIgnore;
632 DispatchEvent(&compositionCommitEvent, status);
634 #ifdef DEBUG
635 RefPtr<TextComposition> currentComposition =
636 IMEStateManager::GetTextCompositionFor(this);
637 MOZ_ASSERT(!currentComposition);
638 #endif // #ifdef DEBUG
640 // Ignore the following composition events until we receive new
641 // eCompositionStart event.
642 mIgnoreCompositionEvents = true;
644 Unused << mBrowserChild->SendOnEventNeedingAckHandled(
645 eCompositionCommitRequestHandled);
647 // NOTE: PuppetWidget might be destroyed already.
648 return NS_OK;
651 nsresult PuppetWidget::StartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
652 int32_t aPanelX, int32_t aPanelY,
653 nsString& aCommitted) {
654 DebugOnly<bool> propagationAlreadyStopped =
655 aKeyboardEvent.mFlags.mPropagationStopped;
656 DebugOnly<bool> immediatePropagationAlreadyStopped =
657 aKeyboardEvent.mFlags.mImmediatePropagationStopped;
658 if (!mBrowserChild || !mBrowserChild->SendStartPluginIME(
659 aKeyboardEvent, aPanelX, aPanelY, &aCommitted)) {
660 return NS_ERROR_FAILURE;
662 // BrowserChild::SendStartPluginIME() sends back the keyboard event to the
663 // main process synchronously. At this time,
664 // ParamTraits<WidgetEvent>::Write() marks the event as "posted to remote
665 // process". However, this is not correct here since the event has been
666 // handled synchronously in the main process. So, we adjust the cross process
667 // dispatching state here.
668 const_cast<WidgetKeyboardEvent&>(aKeyboardEvent)
669 .ResetCrossProcessDispatchingState();
670 // Although it shouldn't occur in content process,
671 // ResetCrossProcessDispatchingState() may reset propagation state too
672 // if the event was posted to a remote process and we're waiting its
673 // result. So, if you saw hitting the following assertions, you'd
674 // need to restore the propagation state too.
675 MOZ_ASSERT(propagationAlreadyStopped ==
676 aKeyboardEvent.mFlags.mPropagationStopped);
677 MOZ_ASSERT(immediatePropagationAlreadyStopped ==
678 aKeyboardEvent.mFlags.mImmediatePropagationStopped);
679 return NS_OK;
682 void PuppetWidget::SetPluginFocused(bool& aFocused) {
683 if (mBrowserChild) {
684 mBrowserChild->SendSetPluginFocused(aFocused);
688 void PuppetWidget::DefaultProcOfPluginEvent(const WidgetPluginEvent& aEvent) {
689 if (!mBrowserChild) {
690 return;
692 mBrowserChild->SendDefaultProcOfPluginEvent(aEvent);
695 // When this widget caches input context and currently managed by
696 // IMEStateManager, the cache is valid.
697 bool PuppetWidget::HaveValidInputContextCache() const {
698 return (mInputContext.mIMEState.mEnabled != IMEState::UNKNOWN &&
699 IMEStateManager::GetWidgetForActiveInputContext() == this);
702 nsRefreshDriver* PuppetWidget::GetTopLevelRefreshDriver() const {
703 if (!mBrowserChild) {
704 return nullptr;
707 if (PresShell* presShell = mBrowserChild->GetTopLevelPresShell()) {
708 return presShell->GetRefreshDriver();
711 return nullptr;
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 MOZ_ASSERT(IMEStateManager::CanSendNotificationToWidget());
757 if (!mBrowserChild) {
758 return NS_ERROR_FAILURE;
761 bool gotFocus = aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS;
762 if (gotFocus) {
763 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN) {
764 // When IME gets focus, we should initalize all information of the
765 // content.
766 if (NS_WARN_IF(!mContentCache.CacheAll(this, &aIMENotification))) {
767 return NS_ERROR_FAILURE;
769 } else {
770 // However, if a plugin has focus, only the editor rect information is
771 // available.
772 if (NS_WARN_IF(!mContentCache.CacheEditorRect(this, &aIMENotification))) {
773 return NS_ERROR_FAILURE;
776 } else {
777 // When IME loses focus, we don't need to store anything.
778 mContentCache.Clear();
781 mIMENotificationRequestsOfParent =
782 IMENotificationRequests(IMENotificationRequests::NOTIFY_ALL);
783 RefPtr<PuppetWidget> self = this;
784 mBrowserChild->SendNotifyIMEFocus(mContentCache, aIMENotification)
785 ->Then(
786 GetMainThreadSerialEventTarget(), __func__,
787 [self](IMENotificationRequests&& aRequests) {
788 self->mIMENotificationRequestsOfParent = aRequests;
789 if (TextEventDispatcher* dispatcher =
790 self->GetTextEventDispatcher()) {
791 dispatcher->OnWidgetChangeIMENotificationRequests(self);
794 [self](mozilla::ipc::ResponseRejectReason&& aReason) {
795 NS_WARNING("SendNotifyIMEFocus got rejected.");
798 return NS_OK;
801 nsresult PuppetWidget::NotifyIMEOfCompositionUpdate(
802 const IMENotification& aIMENotification) {
803 MOZ_ASSERT(IMEStateManager::CanSendNotificationToWidget());
805 if (NS_WARN_IF(!mBrowserChild)) {
806 return NS_ERROR_FAILURE;
809 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
810 NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
811 return NS_ERROR_FAILURE;
813 mBrowserChild->SendNotifyIMECompositionUpdate(mContentCache,
814 aIMENotification);
815 return NS_OK;
818 nsresult PuppetWidget::NotifyIMEOfTextChange(
819 const IMENotification& aIMENotification) {
820 MOZ_ASSERT(IMEStateManager::CanSendNotificationToWidget());
821 MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
822 "Passed wrong notification");
824 if (!mBrowserChild) {
825 return NS_ERROR_FAILURE;
828 // While a plugin has focus, text change notification shouldn't be available.
829 if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
830 return NS_ERROR_FAILURE;
833 // FYI: text change notification is the first notification after
834 // a user operation changes the content. So, we need to modify
835 // the cache as far as possible here.
837 if (NS_WARN_IF(!mContentCache.CacheText(this, &aIMENotification))) {
838 return NS_ERROR_FAILURE;
841 // BrowserParent doesn't this this to cache. we don't send the notification
842 // if parent process doesn't request NOTIFY_TEXT_CHANGE.
843 if (mIMENotificationRequestsOfParent.WantTextChange()) {
844 mBrowserChild->SendNotifyIMETextChange(mContentCache, aIMENotification);
845 } else {
846 mBrowserChild->SendUpdateContentCache(mContentCache);
848 return NS_OK;
851 nsresult PuppetWidget::NotifyIMEOfSelectionChange(
852 const IMENotification& aIMENotification) {
853 MOZ_ASSERT(IMEStateManager::CanSendNotificationToWidget());
854 MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE,
855 "Passed wrong notification");
856 if (!mBrowserChild) {
857 return NS_ERROR_FAILURE;
860 // While a plugin has focus, selection change notification shouldn't be
861 // available.
862 if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
863 return NS_ERROR_FAILURE;
866 // Note that selection change must be notified after text change if it occurs.
867 // Therefore, we don't need to query text content again here.
868 mContentCache.SetSelection(
869 this, aIMENotification.mSelectionChangeData.mOffset,
870 aIMENotification.mSelectionChangeData.Length(),
871 aIMENotification.mSelectionChangeData.mReversed,
872 aIMENotification.mSelectionChangeData.GetWritingMode());
874 mBrowserChild->SendNotifyIMESelection(mContentCache, aIMENotification);
876 return NS_OK;
879 nsresult PuppetWidget::NotifyIMEOfMouseButtonEvent(
880 const IMENotification& aIMENotification) {
881 MOZ_ASSERT(IMEStateManager::CanSendNotificationToWidget());
882 if (!mBrowserChild) {
883 return NS_ERROR_FAILURE;
886 // While a plugin has focus, mouse button event notification shouldn't be
887 // available.
888 if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
889 return NS_ERROR_FAILURE;
892 bool consumedByIME = false;
893 if (!mBrowserChild->SendNotifyIMEMouseButtonEvent(aIMENotification,
894 &consumedByIME)) {
895 return NS_ERROR_FAILURE;
898 return consumedByIME ? NS_SUCCESS_EVENT_CONSUMED : NS_OK;
901 nsresult PuppetWidget::NotifyIMEOfPositionChange(
902 const IMENotification& aIMENotification) {
903 MOZ_ASSERT(IMEStateManager::CanSendNotificationToWidget());
904 if (NS_WARN_IF(!mBrowserChild)) {
905 return NS_ERROR_FAILURE;
908 if (NS_WARN_IF(!mContentCache.CacheEditorRect(this, &aIMENotification))) {
909 return NS_ERROR_FAILURE;
911 // While a plugin has focus, selection range isn't available. So, we don't
912 // need to cache it at that time.
913 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
914 NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
915 return NS_ERROR_FAILURE;
917 if (mIMENotificationRequestsOfParent.WantPositionChanged()) {
918 mBrowserChild->SendNotifyIMEPositionChange(mContentCache, aIMENotification);
919 } else {
920 mBrowserChild->SendUpdateContentCache(mContentCache);
922 return NS_OK;
925 struct CursorSurface {
926 UniquePtr<char[]> mData;
927 IntSize mSize;
930 void PuppetWidget::SetCursor(nsCursor aCursor, imgIContainer* aCursorImage,
931 uint32_t aHotspotX, uint32_t aHotspotY) {
932 if (!mBrowserChild) {
933 return;
936 // Don't cache on windows, Windowless flash breaks this via async cursor
937 // updates.
938 #if !defined(XP_WIN)
939 if (!mUpdateCursor && mCursor == aCursor && mCustomCursor == aCursorImage &&
940 (!aCursorImage ||
941 (mCursorHotspotX == aHotspotX && mCursorHotspotY == aHotspotY))) {
942 return;
944 #endif
946 bool hasCustomCursor = false;
947 UniquePtr<char[]> customCursorData;
948 size_t length = 0;
949 IntSize customCursorSize;
950 int32_t stride = 0;
951 auto format = SurfaceFormat::B8G8R8A8;
952 bool force = mUpdateCursor;
954 if (aCursorImage) {
955 RefPtr<SourceSurface> surface = aCursorImage->GetFrame(
956 imgIContainer::FRAME_CURRENT,
957 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
958 if (surface) {
959 if (RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface()) {
960 hasCustomCursor = true;
961 customCursorData = nsContentUtils::GetSurfaceData(
962 WrapNotNull(dataSurface), &length, &stride);
963 customCursorSize = dataSurface->GetSize();
964 format = dataSurface->GetFormat();
969 mCustomCursor = nullptr;
971 nsDependentCString cursorData(customCursorData ? customCursorData.get() : "",
972 length);
973 if (!mBrowserChild->SendSetCursor(aCursor, hasCustomCursor, cursorData,
974 customCursorSize.width,
975 customCursorSize.height, stride, format,
976 aHotspotX, aHotspotY, force)) {
977 return;
980 mCursor = aCursor;
981 mCustomCursor = aCursorImage;
982 mCursorHotspotX = aHotspotX;
983 mCursorHotspotY = aHotspotY;
984 mUpdateCursor = false;
987 void PuppetWidget::ClearCachedCursor() {
988 nsBaseWidget::ClearCachedCursor();
989 mCustomCursor = nullptr;
992 void PuppetWidget::SetChild(PuppetWidget* aChild) {
993 MOZ_ASSERT(this != aChild, "can't parent a widget to itself");
994 MOZ_ASSERT(!aChild->mChild,
995 "fake widget 'hierarchy' only expected to have one level");
997 mChild = aChild;
1000 void PuppetWidget::PaintNowIfNeeded() {
1001 if (IsVisible()) {
1002 if (RefPtr<nsRefreshDriver> refreshDriver = GetTopLevelRefreshDriver()) {
1003 refreshDriver->DoTick();
1008 void PuppetWidget::OnMemoryPressure(layers::MemoryPressureReason aWhy) {
1009 if (aWhy != MemoryPressureReason::LOW_MEMORY_ONGOING && !mVisible &&
1010 mLayerManager && XRE_IsContentProcess()) {
1011 mLayerManager->ClearCachedResources();
1015 bool PuppetWidget::NeedsPaint() {
1016 // e10s popups are handled by the parent process, so never should be painted
1017 // here
1018 if (XRE_IsContentProcess() &&
1019 StaticPrefs::browser_tabs_remote_desktopbehavior() &&
1020 mWindowType == eWindowType_popup) {
1021 NS_WARNING("Trying to paint an e10s popup in the child process!");
1022 return false;
1025 return mVisible;
1028 float PuppetWidget::GetDPI() { return mDPI; }
1030 double PuppetWidget::GetDefaultScaleInternal() { return mDefaultScale; }
1032 int32_t PuppetWidget::RoundsWidgetCoordinatesTo() { return mRounding; }
1034 void* PuppetWidget::GetNativeData(uint32_t aDataType) {
1035 switch (aDataType) {
1036 case NS_NATIVE_SHAREABLE_WINDOW: {
1037 // NOTE: We can not have a tab child in some situations, such as when
1038 // we're rendering to a fake widget for thumbnails.
1039 if (!mBrowserChild) {
1040 NS_WARNING("Need BrowserChild to get the nativeWindow from!");
1042 mozilla::WindowsHandle nativeData = 0;
1043 if (mBrowserChild) {
1044 nativeData = mBrowserChild->WidgetNativeData();
1046 return (void*)nativeData;
1048 case NS_NATIVE_WINDOW:
1049 case NS_NATIVE_WIDGET:
1050 case NS_NATIVE_DISPLAY:
1051 // These types are ignored (see bug 1183828, bug 1240891).
1052 break;
1053 case NS_RAW_NATIVE_IME_CONTEXT:
1054 MOZ_CRASH("You need to call GetNativeIMEContext() instead");
1055 case NS_NATIVE_PLUGIN_PORT:
1056 case NS_NATIVE_GRAPHIC:
1057 case NS_NATIVE_SHELLWIDGET:
1058 default:
1059 NS_WARNING("nsWindow::GetNativeData called with bad value");
1060 break;
1062 return nullptr;
1065 #if defined(XP_WIN)
1066 void PuppetWidget::SetNativeData(uint32_t aDataType, uintptr_t aVal) {
1067 switch (aDataType) {
1068 case NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW:
1069 MOZ_ASSERT(mBrowserChild, "Need BrowserChild to send the message.");
1070 if (mBrowserChild) {
1071 mBrowserChild->SendSetNativeChildOfShareableWindow(aVal);
1073 break;
1074 default:
1075 NS_WARNING("SetNativeData called with unsupported data type.");
1078 #endif
1080 LayoutDeviceIntPoint PuppetWidget::GetChromeOffset() {
1081 if (!GetOwningBrowserChild()) {
1082 NS_WARNING("PuppetWidget without Tab does not have chrome information.");
1083 return LayoutDeviceIntPoint();
1085 return GetOwningBrowserChild()->GetChromeOffset();
1088 LayoutDeviceIntPoint PuppetWidget::WidgetToScreenOffset() {
1089 auto positionRalativeToWindow =
1090 WidgetToTopLevelWidgetTransform().TransformPoint(LayoutDevicePoint());
1092 return GetWindowPosition() +
1093 LayoutDeviceIntPoint::Round(positionRalativeToWindow);
1096 LayoutDeviceIntPoint PuppetWidget::GetWindowPosition() {
1097 if (!GetOwningBrowserChild()) {
1098 return LayoutDeviceIntPoint();
1101 int32_t winX, winY, winW, winH;
1102 NS_ENSURE_SUCCESS(
1103 GetOwningBrowserChild()->GetDimensions(0, &winX, &winY, &winW, &winH),
1104 LayoutDeviceIntPoint());
1105 return LayoutDeviceIntPoint(winX, winY) +
1106 GetOwningBrowserChild()->GetClientOffset();
1109 LayoutDeviceIntRect PuppetWidget::GetScreenBounds() {
1110 return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
1113 uint32_t PuppetWidget::GetMaxTouchPoints() const {
1114 return mBrowserChild ? mBrowserChild->MaxTouchPoints() : 0;
1117 void PuppetWidget::StartAsyncScrollbarDrag(
1118 const AsyncDragMetrics& aDragMetrics) {
1119 mBrowserChild->StartScrollbarDrag(aDragMetrics);
1122 PuppetScreen::PuppetScreen(void* nativeScreen) {}
1124 PuppetScreen::~PuppetScreen() = default;
1126 static ScreenConfiguration ScreenConfig() {
1127 ScreenConfiguration config;
1128 hal::GetCurrentScreenConfiguration(&config);
1129 return config;
1132 nsIntSize PuppetWidget::GetScreenDimensions() {
1133 nsIntRect r = ScreenConfig().rect();
1134 return nsIntSize(r.Width(), r.Height());
1137 NS_IMETHODIMP
1138 PuppetScreen::GetRect(int32_t* outLeft, int32_t* outTop, int32_t* outWidth,
1139 int32_t* outHeight) {
1140 nsIntRect r = ScreenConfig().rect();
1141 r.GetRect(outLeft, outTop, outWidth, outHeight);
1142 return NS_OK;
1145 NS_IMETHODIMP
1146 PuppetScreen::GetAvailRect(int32_t* outLeft, int32_t* outTop, int32_t* outWidth,
1147 int32_t* outHeight) {
1148 return GetRect(outLeft, outTop, outWidth, outHeight);
1151 NS_IMETHODIMP
1152 PuppetScreen::GetPixelDepth(int32_t* aPixelDepth) {
1153 *aPixelDepth = ScreenConfig().pixelDepth();
1154 return NS_OK;
1157 NS_IMETHODIMP
1158 PuppetScreen::GetColorDepth(int32_t* aColorDepth) {
1159 *aColorDepth = ScreenConfig().colorDepth();
1160 return NS_OK;
1163 NS_IMPL_ISUPPORTS(PuppetScreenManager, nsIScreenManager)
1165 PuppetScreenManager::PuppetScreenManager() {
1166 mOneScreen = new PuppetScreen(nullptr);
1169 PuppetScreenManager::~PuppetScreenManager() = default;
1171 NS_IMETHODIMP
1172 PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen) {
1173 NS_IF_ADDREF(*outScreen = mOneScreen.get());
1174 return NS_OK;
1177 NS_IMETHODIMP
1178 PuppetScreenManager::GetTotalScreenPixels(int64_t* aTotalScreenPixels) {
1179 MOZ_ASSERT(aTotalScreenPixels);
1180 if (mOneScreen) {
1181 int32_t x, y, width, height;
1182 x = y = width = height = 0;
1183 mOneScreen->GetRect(&x, &y, &width, &height);
1184 *aTotalScreenPixels = width * height;
1185 } else {
1186 *aTotalScreenPixels = 0;
1188 return NS_OK;
1191 NS_IMETHODIMP
1192 PuppetScreenManager::ScreenForRect(int32_t inLeft, int32_t inTop,
1193 int32_t inWidth, int32_t inHeight,
1194 nsIScreen** outScreen) {
1195 return GetPrimaryScreen(outScreen);
1198 ScreenIntMargin PuppetWidget::GetSafeAreaInsets() const {
1199 return mSafeAreaInsets;
1202 void PuppetWidget::UpdateSafeAreaInsets(
1203 const ScreenIntMargin& aSafeAreaInsets) {
1204 mSafeAreaInsets = aSafeAreaInsets;
1207 nsIWidgetListener* PuppetWidget::GetCurrentWidgetListener() {
1208 if (!mPreviouslyAttachedWidgetListener || !mAttachedWidgetListener) {
1209 return mAttachedWidgetListener;
1212 if (mAttachedWidgetListener->GetView()->IsPrimaryFramePaintSuppressed()) {
1213 return mPreviouslyAttachedWidgetListener;
1216 return mAttachedWidgetListener;
1219 void PuppetWidget::SetCandidateWindowForPlugin(
1220 const CandidateWindowPosition& aPosition) {
1221 if (!mBrowserChild) {
1222 return;
1225 mBrowserChild->SendSetCandidateWindowForPlugin(aPosition);
1228 void PuppetWidget::EnableIMEForPlugin(bool aEnable) {
1229 if (!mBrowserChild) {
1230 return;
1233 // If current IME state isn't plugin, we ignore this call.
1234 if (NS_WARN_IF(HaveValidInputContextCache() &&
1235 mInputContext.mIMEState.mEnabled != IMEState::UNKNOWN &&
1236 mInputContext.mIMEState.mEnabled != IMEState::PLUGIN)) {
1237 return;
1240 // We don't have valid state in cache or state is plugin, so delegate to
1241 // chrome process.
1242 mBrowserChild->SendEnableIMEForPlugin(aEnable);
1245 void PuppetWidget::ZoomToRect(const uint32_t& aPresShellId,
1246 const ScrollableLayerGuid::ViewID& aViewId,
1247 const CSSRect& aRect, const uint32_t& aFlags) {
1248 if (!mBrowserChild) {
1249 return;
1252 mBrowserChild->ZoomToRect(aPresShellId, aViewId, aRect, aFlags);
1255 void PuppetWidget::LookUpDictionary(
1256 const nsAString& aText, const nsTArray<mozilla::FontRange>& aFontRangeArray,
1257 const bool aIsVertical, const LayoutDeviceIntPoint& aPoint) {
1258 if (!mBrowserChild) {
1259 return;
1262 mBrowserChild->SendLookUpDictionary(nsString(aText), aFontRangeArray,
1263 aIsVertical, aPoint);
1266 bool PuppetWidget::HasPendingInputEvent() {
1267 if (!mBrowserChild) {
1268 return false;
1271 bool ret = false;
1273 mBrowserChild->GetIPCChannel()->PeekMessages(
1274 [&ret](const IPC::Message& aMsg) -> bool {
1275 if (nsContentUtils::IsMessageInputEvent(aMsg)) {
1276 ret = true;
1277 return false; // Stop peeking.
1279 return true;
1282 return ret;
1285 void PuppetWidget::HandledWindowedPluginKeyEvent(
1286 const NativeEventData& aKeyEventData, bool aIsConsumed) {
1287 if (NS_WARN_IF(mKeyEventInPluginCallbacks.IsEmpty())) {
1288 return;
1290 nsCOMPtr<nsIKeyEventInPluginCallback> callback =
1291 mKeyEventInPluginCallbacks[0];
1292 MOZ_ASSERT(callback);
1293 mKeyEventInPluginCallbacks.RemoveElementAt(0);
1294 callback->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
1297 nsresult PuppetWidget::OnWindowedPluginKeyEvent(
1298 const NativeEventData& aKeyEventData,
1299 nsIKeyEventInPluginCallback* aCallback) {
1300 if (NS_WARN_IF(!mBrowserChild)) {
1301 return NS_ERROR_NOT_AVAILABLE;
1303 if (NS_WARN_IF(!mBrowserChild->SendOnWindowedPluginKeyEvent(aKeyEventData))) {
1304 return NS_ERROR_FAILURE;
1306 mKeyEventInPluginCallbacks.AppendElement(aCallback);
1307 return NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY;
1310 // TextEventDispatcherListener
1312 NS_IMETHODIMP
1313 PuppetWidget::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
1314 const IMENotification& aIMENotification) {
1315 MOZ_ASSERT(aTextEventDispatcher == mTextEventDispatcher);
1317 // If there is different text event dispatcher listener for handling
1318 // text event dispatcher, that means that native keyboard events and
1319 // IME events are handled in this process. Therefore, we don't need
1320 // to send any requests and notifications to the parent process.
1321 if (mNativeTextEventDispatcherListener) {
1322 return NS_ERROR_NOT_IMPLEMENTED;
1325 switch (aIMENotification.mMessage) {
1326 case REQUEST_TO_COMMIT_COMPOSITION:
1327 return RequestIMEToCommitComposition(false);
1328 case REQUEST_TO_CANCEL_COMPOSITION:
1329 return RequestIMEToCommitComposition(true);
1330 case NOTIFY_IME_OF_FOCUS:
1331 case NOTIFY_IME_OF_BLUR:
1332 return NotifyIMEOfFocusChange(aIMENotification);
1333 case NOTIFY_IME_OF_SELECTION_CHANGE:
1334 return NotifyIMEOfSelectionChange(aIMENotification);
1335 case NOTIFY_IME_OF_TEXT_CHANGE:
1336 return NotifyIMEOfTextChange(aIMENotification);
1337 case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED:
1338 return NotifyIMEOfCompositionUpdate(aIMENotification);
1339 case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
1340 return NotifyIMEOfMouseButtonEvent(aIMENotification);
1341 case NOTIFY_IME_OF_POSITION_CHANGE:
1342 return NotifyIMEOfPositionChange(aIMENotification);
1343 default:
1344 return NS_ERROR_NOT_IMPLEMENTED;
1347 return NS_ERROR_NOT_IMPLEMENTED;
1350 NS_IMETHODIMP_(IMENotificationRequests)
1351 PuppetWidget::GetIMENotificationRequests() {
1352 if (mInputContext.mIMEState.mEnabled == IMEState::PLUGIN) {
1353 // If a plugin has focus, we cannot receive text nor selection change
1354 // in the plugin. Therefore, PuppetWidget needs to receive only position
1355 // change event for updating the editor rect cache.
1356 return IMENotificationRequests(
1357 mIMENotificationRequestsOfParent.mWantUpdates |
1358 IMENotificationRequests::NOTIFY_POSITION_CHANGE);
1360 return IMENotificationRequests(
1361 mIMENotificationRequestsOfParent.mWantUpdates |
1362 IMENotificationRequests::NOTIFY_TEXT_CHANGE |
1363 IMENotificationRequests::NOTIFY_POSITION_CHANGE);
1366 NS_IMETHODIMP_(void)
1367 PuppetWidget::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) {
1368 MOZ_ASSERT(aTextEventDispatcher == mTextEventDispatcher);
1371 NS_IMETHODIMP_(void)
1372 PuppetWidget::WillDispatchKeyboardEvent(
1373 TextEventDispatcher* aTextEventDispatcher,
1374 WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress,
1375 void* aData) {
1376 MOZ_ASSERT(aTextEventDispatcher == mTextEventDispatcher);
1379 nsresult PuppetWidget::SetSystemFont(const nsCString& aFontName) {
1380 if (!mBrowserChild) {
1381 return NS_ERROR_FAILURE;
1384 mBrowserChild->SendSetSystemFont(aFontName);
1385 return NS_OK;
1388 nsresult PuppetWidget::GetSystemFont(nsCString& aFontName) {
1389 if (!mBrowserChild) {
1390 return NS_ERROR_FAILURE;
1392 mBrowserChild->SendGetSystemFont(&aFontName);
1393 return NS_OK;
1396 } // namespace widget
1397 } // namespace mozilla