Line data Source code
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/. */
7 :
8 : #include "base/basictypes.h"
9 :
10 : #include "ClientLayerManager.h"
11 : #include "gfxPlatform.h"
12 : #include "mozilla/dom/TabChild.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/TextComposition.h"
22 : #include "mozilla/TextEventDispatcher.h"
23 : #include "mozilla/TextEvents.h"
24 : #include "mozilla/Unused.h"
25 : #include "BasicLayers.h"
26 : #include "PuppetWidget.h"
27 : #include "nsContentUtils.h"
28 : #include "nsIWidgetListener.h"
29 : #include "imgIContainer.h"
30 : #include "nsView.h"
31 :
32 : using namespace mozilla;
33 : using namespace mozilla::dom;
34 : using namespace mozilla::hal;
35 : using namespace mozilla::gfx;
36 : using namespace mozilla::layers;
37 : using namespace mozilla::widget;
38 :
39 : static void
40 2 : InvalidateRegion(nsIWidget* aWidget, const LayoutDeviceIntRegion& aRegion)
41 : {
42 5 : for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
43 3 : aWidget->Invalidate(iter.Get());
44 : }
45 2 : }
46 :
47 : /*static*/ already_AddRefed<nsIWidget>
48 1 : nsIWidget::CreatePuppetWidget(TabChild* aTabChild)
49 : {
50 1 : MOZ_ASSERT(!aTabChild || nsIWidget::UsePuppetWidgets(),
51 : "PuppetWidgets not allowed in this configuration");
52 :
53 2 : nsCOMPtr<nsIWidget> widget = new PuppetWidget(aTabChild);
54 2 : return widget.forget();
55 : }
56 :
57 : namespace mozilla {
58 : namespace widget {
59 :
60 : static bool
61 1 : IsPopup(const nsWidgetInitData* aInitData)
62 : {
63 1 : return aInitData && aInitData->mWindowType == eWindowType_popup;
64 : }
65 :
66 : static bool
67 1 : MightNeedIMEFocus(const nsWidgetInitData* aInitData)
68 : {
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 1 : return !IsPopup(aInitData);
73 : #else
74 : return false;
75 : #endif
76 : }
77 :
78 : // Arbitrary, fungible.
79 : const size_t PuppetWidget::kMaxDimension = 4000;
80 :
81 : static bool gRemoteDesktopBehaviorEnabled = false;
82 : static bool gRemoteDesktopBehaviorInitialized = false;
83 :
84 217 : NS_IMPL_ISUPPORTS_INHERITED(PuppetWidget, nsBaseWidget
85 : , TextEventDispatcherListener)
86 :
87 1 : PuppetWidget::PuppetWidget(TabChild* aTabChild)
88 : : mTabChild(aTabChild)
89 : , mMemoryPressureObserver(nullptr)
90 : , mDPI(-1)
91 : , mRounding(-1)
92 : , mDefaultScale(-1)
93 : , mCursorHotspotX(0)
94 1 : , mCursorHotspotY(0)
95 : {
96 : // Setting 'Unknown' means "not yet cached".
97 1 : mInputContext.mIMEState.mEnabled = IMEState::UNKNOWN;
98 :
99 1 : if (!gRemoteDesktopBehaviorInitialized) {
100 1 : Preferences::AddBoolVarCache(&gRemoteDesktopBehaviorEnabled, "browser.tabs.remote.desktopbehavior", false);
101 1 : gRemoteDesktopBehaviorInitialized = true;
102 : }
103 1 : }
104 :
105 0 : PuppetWidget::~PuppetWidget()
106 : {
107 0 : Destroy();
108 0 : }
109 :
110 : void
111 1 : PuppetWidget::InfallibleCreate(nsIWidget* aParent,
112 : nsNativeWidget aNativeParent,
113 : const LayoutDeviceIntRect& aRect,
114 : nsWidgetInitData* aInitData)
115 : {
116 1 : MOZ_ASSERT(!aNativeParent, "got a non-Puppet native parent");
117 :
118 1 : BaseCreate(nullptr, aInitData);
119 :
120 1 : mBounds = aRect;
121 1 : mEnabled = true;
122 1 : mVisible = true;
123 :
124 : mDrawTarget = gfxPlatform::GetPlatform()->
125 1 : CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8);
126 :
127 1 : mNeedIMEStateInit = MightNeedIMEFocus(aInitData);
128 :
129 1 : PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
130 1 : if (parent) {
131 0 : parent->SetChild(this);
132 0 : mLayerManager = parent->GetLayerManager();
133 : }
134 : else {
135 1 : Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
136 : }
137 2 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
138 1 : if (obs) {
139 1 : mMemoryPressureObserver = new MemoryPressureObserver(this);
140 1 : obs->AddObserver(mMemoryPressureObserver, "memory-pressure", false);
141 : }
142 1 : }
143 :
144 : nsresult
145 0 : PuppetWidget::Create(nsIWidget* aParent,
146 : nsNativeWidget aNativeParent,
147 : const LayoutDeviceIntRect& aRect,
148 : nsWidgetInitData* aInitData)
149 : {
150 0 : InfallibleCreate(aParent, aNativeParent, aRect, aInitData);
151 0 : return NS_OK;
152 : }
153 :
154 : void
155 1 : PuppetWidget::InitIMEState()
156 : {
157 1 : MOZ_ASSERT(mTabChild);
158 1 : if (mNeedIMEStateInit) {
159 1 : mContentCache.Clear();
160 1 : mTabChild->SendUpdateContentCache(mContentCache);
161 1 : mIMENotificationRequestsOfParent = IMENotificationRequests();
162 1 : mNeedIMEStateInit = false;
163 : }
164 1 : }
165 :
166 : already_AddRefed<nsIWidget>
167 0 : PuppetWidget::CreateChild(const LayoutDeviceIntRect& aRect,
168 : nsWidgetInitData* aInitData,
169 : bool aForceUseIWidgetParent)
170 : {
171 0 : bool isPopup = IsPopup(aInitData);
172 0 : nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(mTabChild);
173 0 : return ((widget &&
174 0 : NS_SUCCEEDED(widget->Create(isPopup ? nullptr: this, nullptr, aRect,
175 0 : aInitData))) ?
176 0 : widget.forget() : nullptr);
177 : }
178 :
179 : void
180 0 : PuppetWidget::Destroy()
181 : {
182 0 : if (mOnDestroyCalled) {
183 0 : return;
184 : }
185 0 : mOnDestroyCalled = true;
186 :
187 0 : Base::OnDestroy();
188 0 : Base::Destroy();
189 0 : mPaintTask.Revoke();
190 0 : if (mMemoryPressureObserver) {
191 0 : mMemoryPressureObserver->Remove();
192 : }
193 0 : mMemoryPressureObserver = nullptr;
194 0 : mChild = nullptr;
195 0 : if (mLayerManager) {
196 0 : mLayerManager->Destroy();
197 : }
198 0 : mLayerManager = nullptr;
199 0 : mTabChild = nullptr;
200 : }
201 :
202 : void
203 0 : PuppetWidget::Show(bool aState)
204 : {
205 0 : NS_ASSERTION(mEnabled,
206 : "does it make sense to Show()/Hide() a disabled widget?");
207 :
208 0 : bool wasVisible = mVisible;
209 0 : mVisible = aState;
210 :
211 0 : if (mChild) {
212 0 : mChild->mVisible = aState;
213 : }
214 :
215 0 : if (!wasVisible && mVisible) {
216 : // The previously attached widget listener is handy if
217 : // we're transitioning from page to page without dropping
218 : // layers (since we'll continue to show the old layers
219 : // associated with that old widget listener). If the
220 : // PuppetWidget was hidden, those layers are dropped,
221 : // so the previously attached widget listener is really
222 : // of no use anymore (and is actually actively harmful - see
223 : // bug 1323586).
224 0 : mPreviouslyAttachedWidgetListener = nullptr;
225 0 : Resize(mBounds.width, mBounds.height, false);
226 0 : Invalidate(mBounds);
227 : }
228 0 : }
229 :
230 : void
231 4 : PuppetWidget::Resize(double aWidth,
232 : double aHeight,
233 : bool aRepaint)
234 : {
235 4 : LayoutDeviceIntRect oldBounds = mBounds;
236 8 : mBounds.SizeTo(LayoutDeviceIntSize(NSToIntRound(aWidth),
237 4 : NSToIntRound(aHeight)));
238 :
239 4 : if (mChild) {
240 0 : mChild->Resize(aWidth, aHeight, aRepaint);
241 0 : return;
242 : }
243 :
244 : // XXX: roc says that |aRepaint| dictates whether or not to
245 : // invalidate the expanded area
246 4 : if (oldBounds.Size() < mBounds.Size() && aRepaint) {
247 4 : LayoutDeviceIntRegion dirty(mBounds);
248 2 : dirty.Sub(dirty, oldBounds);
249 2 : InvalidateRegion(this, dirty);
250 : }
251 :
252 : // call WindowResized() on both the current listener, and possibly
253 : // also the previous one if we're in a state where we're drawing that one
254 : // because the current one is paint suppressed
255 4 : if (!oldBounds.IsEqualEdges(mBounds) && mAttachedWidgetListener) {
256 4 : if (GetCurrentWidgetListener() &&
257 2 : GetCurrentWidgetListener() != mAttachedWidgetListener) {
258 0 : GetCurrentWidgetListener()->WindowResized(this, mBounds.width, mBounds.height);
259 : }
260 2 : mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
261 : }
262 : }
263 :
264 : nsresult
265 0 : PuppetWidget::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
266 : {
267 0 : for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
268 0 : const Configuration& configuration = aConfigurations[i];
269 0 : PuppetWidget* w = static_cast<PuppetWidget*>(configuration.mChild.get());
270 0 : NS_ASSERTION(w->GetParent() == this,
271 : "Configured widget is not a child");
272 0 : w->SetWindowClipRegion(configuration.mClipRegion, true);
273 0 : LayoutDeviceIntRect bounds = w->GetBounds();
274 0 : if (bounds.Size() != configuration.mBounds.Size()) {
275 0 : w->Resize(configuration.mBounds.x, configuration.mBounds.y,
276 0 : configuration.mBounds.width, configuration.mBounds.height,
277 0 : true);
278 0 : } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) {
279 0 : w->Move(configuration.mBounds.x, configuration.mBounds.y);
280 : }
281 0 : w->SetWindowClipRegion(configuration.mClipRegion, false);
282 : }
283 0 : return NS_OK;
284 : }
285 :
286 : nsresult
287 0 : PuppetWidget::SetFocus(bool aRaise)
288 : {
289 0 : if (aRaise && mTabChild) {
290 0 : mTabChild->SendRequestFocus(true);
291 : }
292 :
293 0 : return NS_OK;
294 : }
295 :
296 : void
297 3 : PuppetWidget::Invalidate(const LayoutDeviceIntRect& aRect)
298 : {
299 : #ifdef DEBUG
300 3 : debug_DumpInvalidate(stderr, this, &aRect, "PuppetWidget", 0);
301 : #endif
302 :
303 3 : if (mChild) {
304 0 : mChild->Invalidate(aRect);
305 0 : return;
306 : }
307 :
308 3 : mDirtyRegion.Or(mDirtyRegion, aRect);
309 :
310 3 : if (mTabChild && !mDirtyRegion.IsEmpty() && !mPaintTask.IsPending()) {
311 2 : mPaintTask = new PaintTask(this);
312 4 : nsCOMPtr<nsIRunnable> event(mPaintTask.get());
313 2 : mTabChild->TabGroup()->Dispatch("PuppetWidget::Invalidate", TaskCategory::Other, event.forget());
314 2 : return;
315 : }
316 : }
317 :
318 : void
319 0 : PuppetWidget::InitEvent(WidgetGUIEvent& aEvent, LayoutDeviceIntPoint* aPoint)
320 : {
321 0 : if (nullptr == aPoint) {
322 0 : aEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
323 : } else {
324 : // use the point override if provided
325 0 : aEvent.mRefPoint = *aPoint;
326 : }
327 0 : aEvent.mTime = PR_Now() / 1000;
328 0 : }
329 :
330 : nsresult
331 6 : PuppetWidget::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
332 : {
333 : #ifdef DEBUG
334 6 : debug_DumpEvent(stdout, aEvent->mWidget, aEvent, "PuppetWidget", 0);
335 : #endif
336 :
337 6 : MOZ_ASSERT(!mChild || mChild->mWindowType == eWindowType_popup,
338 : "Unexpected event dispatch!");
339 :
340 6 : MOZ_ASSERT(!aEvent->AsKeyboardEvent() ||
341 : aEvent->mFlags.mIsSynthesizedForTests ||
342 : aEvent->AsKeyboardEvent()->AreAllEditCommandsInitialized(),
343 : "Non-sysnthesized keyboard events should have edit commands for all types "
344 : "before dispatched");
345 :
346 6 : if (aEvent->mClass == eCompositionEventClass) {
347 : // Store the latest native IME context of parent process's widget or
348 : // TextEventDispatcher if it's in this process.
349 0 : WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
350 : #ifdef DEBUG
351 0 : if (mNativeIMEContext.IsValid() &&
352 0 : mNativeIMEContext != compositionEvent->mNativeIMEContext) {
353 : RefPtr<TextComposition> composition =
354 0 : IMEStateManager::GetTextCompositionFor(this);
355 0 : MOZ_ASSERT(!composition,
356 : "When there is composition caused by old native IME context, "
357 : "composition events caused by different native IME context are not "
358 : "allowed");
359 : }
360 : #endif // #ifdef DEBUG
361 0 : mNativeIMEContext = compositionEvent->mNativeIMEContext;
362 : }
363 :
364 6 : aStatus = nsEventStatus_eIgnore;
365 :
366 6 : if (GetCurrentWidgetListener()) {
367 6 : aStatus =
368 6 : GetCurrentWidgetListener()->HandleEvent(aEvent, mUseAttachedEvents);
369 : }
370 :
371 6 : return NS_OK;
372 : }
373 :
374 : nsEventStatus
375 0 : PuppetWidget::DispatchInputEvent(WidgetInputEvent* aEvent)
376 : {
377 0 : if (!AsyncPanZoomEnabled()) {
378 0 : nsEventStatus status = nsEventStatus_eIgnore;
379 0 : DispatchEvent(aEvent, status);
380 0 : return status;
381 : }
382 :
383 0 : if (!mTabChild) {
384 0 : return nsEventStatus_eIgnore;
385 : }
386 :
387 0 : switch (aEvent->mClass) {
388 : case eWheelEventClass:
389 : Unused <<
390 0 : mTabChild->SendDispatchWheelEvent(*aEvent->AsWheelEvent());
391 0 : break;
392 : case eMouseEventClass:
393 : Unused <<
394 0 : mTabChild->SendDispatchMouseEvent(*aEvent->AsMouseEvent());
395 0 : break;
396 : case eKeyboardEventClass:
397 : Unused <<
398 0 : mTabChild->SendDispatchKeyboardEvent(*aEvent->AsKeyboardEvent());
399 0 : break;
400 : default:
401 0 : MOZ_ASSERT_UNREACHABLE("unsupported event type");
402 : }
403 :
404 0 : return nsEventStatus_eIgnore;
405 : }
406 :
407 : nsresult
408 0 : PuppetWidget::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
409 : int32_t aNativeKeyCode,
410 : uint32_t aModifierFlags,
411 : const nsAString& aCharacters,
412 : const nsAString& aUnmodifiedCharacters,
413 : nsIObserver* aObserver)
414 : {
415 0 : AutoObserverNotifier notifier(aObserver, "keyevent");
416 0 : if (!mTabChild) {
417 0 : return NS_ERROR_FAILURE;
418 : }
419 0 : mTabChild->SendSynthesizeNativeKeyEvent(aNativeKeyboardLayout, aNativeKeyCode,
420 0 : aModifierFlags, nsString(aCharacters),
421 0 : nsString(aUnmodifiedCharacters),
422 0 : notifier.SaveObserver());
423 0 : return NS_OK;
424 : }
425 :
426 : nsresult
427 0 : PuppetWidget::SynthesizeNativeMouseEvent(mozilla::LayoutDeviceIntPoint aPoint,
428 : uint32_t aNativeMessage,
429 : uint32_t aModifierFlags,
430 : nsIObserver* aObserver)
431 : {
432 0 : AutoObserverNotifier notifier(aObserver, "mouseevent");
433 0 : if (!mTabChild) {
434 0 : return NS_ERROR_FAILURE;
435 : }
436 0 : mTabChild->SendSynthesizeNativeMouseEvent(aPoint, aNativeMessage,
437 : aModifierFlags,
438 0 : notifier.SaveObserver());
439 0 : return NS_OK;
440 : }
441 :
442 : nsresult
443 0 : PuppetWidget::SynthesizeNativeMouseMove(mozilla::LayoutDeviceIntPoint aPoint,
444 : nsIObserver* aObserver)
445 : {
446 0 : AutoObserverNotifier notifier(aObserver, "mousemove");
447 0 : if (!mTabChild) {
448 0 : return NS_ERROR_FAILURE;
449 : }
450 0 : mTabChild->SendSynthesizeNativeMouseMove(aPoint, notifier.SaveObserver());
451 0 : return NS_OK;
452 : }
453 :
454 : nsresult
455 0 : PuppetWidget::SynthesizeNativeMouseScrollEvent(
456 : mozilla::LayoutDeviceIntPoint aPoint,
457 : uint32_t aNativeMessage,
458 : double aDeltaX,
459 : double aDeltaY,
460 : double aDeltaZ,
461 : uint32_t aModifierFlags,
462 : uint32_t aAdditionalFlags,
463 : nsIObserver* aObserver)
464 : {
465 0 : AutoObserverNotifier notifier(aObserver, "mousescrollevent");
466 0 : if (!mTabChild) {
467 0 : return NS_ERROR_FAILURE;
468 : }
469 0 : mTabChild->SendSynthesizeNativeMouseScrollEvent(aPoint, aNativeMessage,
470 : aDeltaX, aDeltaY, aDeltaZ,
471 : aModifierFlags,
472 : aAdditionalFlags,
473 0 : notifier.SaveObserver());
474 0 : return NS_OK;
475 : }
476 :
477 : nsresult
478 0 : PuppetWidget::SynthesizeNativeTouchPoint(uint32_t aPointerId,
479 : TouchPointerState aPointerState,
480 : LayoutDeviceIntPoint aPoint,
481 : double aPointerPressure,
482 : uint32_t aPointerOrientation,
483 : nsIObserver* aObserver)
484 : {
485 0 : AutoObserverNotifier notifier(aObserver, "touchpoint");
486 0 : if (!mTabChild) {
487 0 : return NS_ERROR_FAILURE;
488 : }
489 0 : mTabChild->SendSynthesizeNativeTouchPoint(aPointerId, aPointerState,
490 : aPoint, aPointerPressure,
491 : aPointerOrientation,
492 0 : notifier.SaveObserver());
493 0 : return NS_OK;
494 : }
495 :
496 : nsresult
497 0 : PuppetWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint,
498 : bool aLongTap,
499 : nsIObserver* aObserver)
500 : {
501 0 : AutoObserverNotifier notifier(aObserver, "touchtap");
502 0 : if (!mTabChild) {
503 0 : return NS_ERROR_FAILURE;
504 : }
505 0 : mTabChild->SendSynthesizeNativeTouchTap(aPoint, aLongTap,
506 0 : notifier.SaveObserver());
507 0 : return NS_OK;
508 : }
509 :
510 : nsresult
511 0 : PuppetWidget::ClearNativeTouchSequence(nsIObserver* aObserver)
512 : {
513 0 : AutoObserverNotifier notifier(aObserver, "cleartouch");
514 0 : if (!mTabChild) {
515 0 : return NS_ERROR_FAILURE;
516 : }
517 0 : mTabChild->SendClearNativeTouchSequence(notifier.SaveObserver());
518 0 : return NS_OK;
519 : }
520 :
521 : void
522 0 : PuppetWidget::SetConfirmedTargetAPZC(
523 : uint64_t aInputBlockId,
524 : const nsTArray<ScrollableLayerGuid>& aTargets) const
525 : {
526 0 : if (mTabChild) {
527 0 : mTabChild->SetTargetAPZC(aInputBlockId, aTargets);
528 : }
529 0 : }
530 :
531 : void
532 1 : PuppetWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
533 : const FrameMetrics::ViewID& aViewId,
534 : const Maybe<ZoomConstraints>& aConstraints)
535 : {
536 1 : if (mTabChild) {
537 1 : mTabChild->DoUpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
538 : }
539 1 : }
540 :
541 : bool
542 16 : PuppetWidget::AsyncPanZoomEnabled() const
543 : {
544 16 : return mTabChild && mTabChild->AsyncPanZoomEnabled();
545 : }
546 :
547 : void
548 0 : PuppetWidget::GetEditCommands(NativeKeyBindingsType aType,
549 : const WidgetKeyboardEvent& aEvent,
550 : nsTArray<CommandInt>& aCommands)
551 : {
552 : // Validate the arguments.
553 0 : nsIWidget::GetEditCommands(aType, aEvent, aCommands);
554 :
555 0 : mTabChild->RequestEditCommands(aType, aEvent, aCommands);
556 0 : }
557 :
558 : LayerManager*
559 128 : PuppetWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
560 : LayersBackend aBackendHint,
561 : LayerManagerPersistence aPersistence)
562 : {
563 128 : if (!mLayerManager) {
564 1 : if (XRE_IsParentProcess()) {
565 : // On the parent process there is no CompositorBridgeChild which confuses
566 : // some layers code, so we use basic layers instead. Note that we create
567 : // a non-retaining layer manager since we don't care about performance.
568 0 : mLayerManager = new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN);
569 0 : return mLayerManager;
570 : }
571 :
572 1 : if (mTabChild && !mTabChild->IsLayersConnected()) {
573 : // If we know for sure that the parent side of this TabChild is not
574 : // connected to the compositor, we don't want to use a "remote" layer
575 : // manager like WebRender or Client. Instead we use a Basic one which
576 : // can do drawing in this process.
577 0 : mLayerManager = new BasicLayerManager(this);
578 1 : } else if (gfxVars::UseWebRender()) {
579 0 : MOZ_ASSERT(!aShadowManager);
580 0 : mLayerManager = new WebRenderLayerManager(this);
581 : } else {
582 1 : mLayerManager = new ClientLayerManager(this);
583 : }
584 : }
585 :
586 : // Attach a shadow forwarder if none exists.
587 128 : ShadowLayerForwarder* lf = mLayerManager->AsShadowForwarder();
588 128 : if (lf && !lf->HasShadowManager() && aShadowManager) {
589 0 : lf->SetShadowManager(aShadowManager);
590 : }
591 :
592 128 : return mLayerManager;
593 : }
594 :
595 : LayerManager*
596 0 : PuppetWidget::RecreateLayerManager(PLayerTransactionChild* aShadowManager)
597 : {
598 : // Force the old LM to self destruct, otherwise if the reference dangles we
599 : // could fail to revoke the most recent transaction.
600 0 : DestroyLayerManager();
601 :
602 0 : MOZ_ASSERT(mTabChild);
603 0 : if (gfxVars::UseWebRender()) {
604 0 : MOZ_ASSERT(!aShadowManager);
605 0 : mLayerManager = new WebRenderLayerManager(this);
606 : } else {
607 0 : mLayerManager = new ClientLayerManager(this);
608 : }
609 0 : if (ShadowLayerForwarder* lf = mLayerManager->AsShadowForwarder()) {
610 0 : lf->SetShadowManager(aShadowManager);
611 : }
612 0 : return mLayerManager;
613 : }
614 :
615 : nsresult
616 0 : PuppetWidget::RequestIMEToCommitComposition(bool aCancel)
617 : {
618 0 : if (!mTabChild) {
619 0 : return NS_ERROR_FAILURE;
620 : }
621 :
622 0 : MOZ_ASSERT(!Destroyed());
623 :
624 : // There must not be composition which is caused by the PuppetWidget instance.
625 0 : if (NS_WARN_IF(!mNativeIMEContext.IsValid())) {
626 0 : return NS_OK;
627 : }
628 :
629 : RefPtr<TextComposition> composition =
630 0 : IMEStateManager::GetTextCompositionFor(this);
631 : // This method shouldn't be called when there is no text composition instance.
632 0 : if (NS_WARN_IF(!composition)) {
633 0 : return NS_OK;
634 : }
635 :
636 0 : bool isCommitted = false;
637 0 : nsAutoString committedString;
638 0 : if (NS_WARN_IF(!mTabChild->SendRequestIMEToCommitComposition(
639 : aCancel, &isCommitted, &committedString))) {
640 0 : return NS_ERROR_FAILURE;
641 : }
642 :
643 : // If the composition wasn't committed synchronously, we need to wait async
644 : // composition events for destroying the TextComposition instance.
645 0 : if (!isCommitted) {
646 0 : return NS_OK;
647 : }
648 :
649 : // Dispatch eCompositionCommit event.
650 0 : WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommit, this);
651 0 : InitEvent(compositionCommitEvent, nullptr);
652 0 : compositionCommitEvent.mData = committedString;
653 0 : nsEventStatus status = nsEventStatus_eIgnore;
654 0 : DispatchEvent(&compositionCommitEvent, status);
655 :
656 : Unused <<
657 0 : mTabChild->SendOnEventNeedingAckHandled(eCompositionCommitRequestHandled);
658 :
659 : // NOTE: PuppetWidget might be destroyed already.
660 0 : return NS_OK;
661 : }
662 :
663 : nsresult
664 0 : PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
665 : {
666 0 : if (mNativeTextEventDispatcherListener) {
667 : // Use mNativeTextEventDispatcherListener for IME notifications.
668 0 : return NS_ERROR_NOT_IMPLEMENTED;
669 : }
670 :
671 0 : switch (aIMENotification.mMessage) {
672 : case REQUEST_TO_COMMIT_COMPOSITION:
673 0 : return RequestIMEToCommitComposition(false);
674 : case REQUEST_TO_CANCEL_COMPOSITION:
675 0 : return RequestIMEToCommitComposition(true);
676 : case NOTIFY_IME_OF_FOCUS:
677 : case NOTIFY_IME_OF_BLUR:
678 0 : return NotifyIMEOfFocusChange(aIMENotification);
679 : case NOTIFY_IME_OF_SELECTION_CHANGE:
680 0 : return NotifyIMEOfSelectionChange(aIMENotification);
681 : case NOTIFY_IME_OF_TEXT_CHANGE:
682 0 : return NotifyIMEOfTextChange(aIMENotification);
683 : case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED:
684 0 : return NotifyIMEOfCompositionUpdate(aIMENotification);
685 : case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
686 0 : return NotifyIMEOfMouseButtonEvent(aIMENotification);
687 : case NOTIFY_IME_OF_POSITION_CHANGE:
688 0 : return NotifyIMEOfPositionChange(aIMENotification);
689 : default:
690 0 : return NS_ERROR_NOT_IMPLEMENTED;
691 : }
692 : }
693 :
694 : nsresult
695 0 : PuppetWidget::StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
696 : int32_t aPanelX, int32_t aPanelY,
697 : nsString& aCommitted)
698 : {
699 0 : if (!mTabChild ||
700 0 : !mTabChild->SendStartPluginIME(aKeyboardEvent, aPanelX,
701 : aPanelY, &aCommitted)) {
702 0 : return NS_ERROR_FAILURE;
703 : }
704 0 : return NS_OK;
705 : }
706 :
707 : void
708 0 : PuppetWidget::SetPluginFocused(bool& aFocused)
709 : {
710 0 : if (mTabChild) {
711 0 : mTabChild->SendSetPluginFocused(aFocused);
712 : }
713 0 : }
714 :
715 : void
716 0 : PuppetWidget::DefaultProcOfPluginEvent(const WidgetPluginEvent& aEvent)
717 : {
718 0 : if (!mTabChild) {
719 0 : return;
720 : }
721 0 : mTabChild->SendDefaultProcOfPluginEvent(aEvent);
722 : }
723 :
724 : void
725 3 : PuppetWidget::SetInputContext(const InputContext& aContext,
726 : const InputContextAction& aAction)
727 : {
728 3 : mInputContext = aContext;
729 : // Any widget instances cannot cache IME open state because IME open state
730 : // can be changed by user but native IME may not notify us of changing the
731 : // open state on some platforms.
732 3 : mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
733 3 : if (!mTabChild) {
734 0 : return;
735 : }
736 6 : mTabChild->SendSetInputContext(
737 6 : static_cast<int32_t>(aContext.mIMEState.mEnabled),
738 6 : static_cast<int32_t>(aContext.mIMEState.mOpen),
739 : aContext.mHTMLInputType,
740 : aContext.mHTMLInputInputmode,
741 : aContext.mActionHint,
742 6 : static_cast<int32_t>(aAction.mCause),
743 9 : static_cast<int32_t>(aAction.mFocusChange));
744 : }
745 :
746 : InputContext
747 1 : PuppetWidget::GetInputContext()
748 : {
749 : // XXX Currently, we don't support retrieving IME open state from child
750 : // process.
751 :
752 : // When this widget caches input context and currently managed by
753 : // IMEStateManager, the cache is valid. Only in this case, we can
754 : // avoid to use synchronous IPC.
755 2 : if (mInputContext.mIMEState.mEnabled != IMEState::UNKNOWN &&
756 1 : IMEStateManager::GetWidgetForActiveInputContext() == this) {
757 1 : return mInputContext;
758 : }
759 :
760 0 : NS_WARNING("PuppetWidget::GetInputContext() needs to retrieve it with IPC");
761 :
762 : // Don't cache InputContext here because this process isn't managing IME
763 : // state of the chrome widget. So, we cannot modify mInputContext when
764 : // chrome widget is set to new context.
765 0 : InputContext context;
766 0 : if (mTabChild) {
767 : int32_t enabled, open;
768 0 : mTabChild->SendGetInputContext(&enabled, &open);
769 0 : context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(enabled);
770 0 : context.mIMEState.mOpen = static_cast<IMEState::Open>(open);
771 : }
772 0 : return context;
773 : }
774 :
775 : NativeIMEContext
776 0 : PuppetWidget::GetNativeIMEContext()
777 : {
778 0 : return mNativeIMEContext;
779 : }
780 :
781 : nsresult
782 0 : PuppetWidget::NotifyIMEOfFocusChange(const IMENotification& aIMENotification)
783 : {
784 0 : if (!mTabChild) {
785 0 : return NS_ERROR_FAILURE;
786 : }
787 :
788 0 : bool gotFocus = aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS;
789 0 : if (gotFocus) {
790 0 : if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN) {
791 : // When IME gets focus, we should initalize all information of the
792 : // content.
793 0 : if (NS_WARN_IF(!mContentCache.CacheAll(this, &aIMENotification))) {
794 0 : return NS_ERROR_FAILURE;
795 : }
796 : } else {
797 : // However, if a plugin has focus, only the editor rect information is
798 : // available.
799 0 : if (NS_WARN_IF(!mContentCache.CacheEditorRect(this, &aIMENotification))) {
800 0 : return NS_ERROR_FAILURE;
801 : }
802 : }
803 : } else {
804 : // When IME loses focus, we don't need to store anything.
805 0 : mContentCache.Clear();
806 : }
807 :
808 0 : mIMENotificationRequestsOfParent = IMENotificationRequests();
809 0 : if (!mTabChild->SendNotifyIMEFocus(mContentCache, aIMENotification,
810 : &mIMENotificationRequestsOfParent)) {
811 0 : return NS_ERROR_FAILURE;
812 : }
813 0 : return NS_OK;
814 : }
815 :
816 : nsresult
817 0 : PuppetWidget::NotifyIMEOfCompositionUpdate(
818 : const IMENotification& aIMENotification)
819 : {
820 0 : if (NS_WARN_IF(!mTabChild)) {
821 0 : return NS_ERROR_FAILURE;
822 : }
823 :
824 0 : if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
825 0 : NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
826 0 : return NS_ERROR_FAILURE;
827 : }
828 0 : mTabChild->SendNotifyIMECompositionUpdate(mContentCache, aIMENotification);
829 0 : return NS_OK;
830 : }
831 :
832 : nsresult
833 0 : PuppetWidget::NotifyIMEOfTextChange(const IMENotification& aIMENotification)
834 : {
835 0 : MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
836 : "Passed wrong notification");
837 0 : if (!mTabChild) {
838 0 : return NS_ERROR_FAILURE;
839 : }
840 :
841 : // While a plugin has focus, text change notification shouldn't be available.
842 0 : if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
843 0 : return NS_ERROR_FAILURE;
844 : }
845 :
846 : // FYI: text change notification is the first notification after
847 : // a user operation changes the content. So, we need to modify
848 : // the cache as far as possible here.
849 :
850 0 : if (NS_WARN_IF(!mContentCache.CacheText(this, &aIMENotification))) {
851 0 : return NS_ERROR_FAILURE;
852 : }
853 :
854 : // TabParent doesn't this this to cache. we don't send the notification
855 : // if parent process doesn't request NOTIFY_TEXT_CHANGE.
856 0 : if (mIMENotificationRequestsOfParent.WantTextChange()) {
857 0 : mTabChild->SendNotifyIMETextChange(mContentCache, aIMENotification);
858 : } else {
859 0 : mTabChild->SendUpdateContentCache(mContentCache);
860 : }
861 0 : return NS_OK;
862 : }
863 :
864 : nsresult
865 0 : PuppetWidget::NotifyIMEOfSelectionChange(
866 : const IMENotification& aIMENotification)
867 : {
868 0 : MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE,
869 : "Passed wrong notification");
870 0 : if (!mTabChild) {
871 0 : return NS_ERROR_FAILURE;
872 : }
873 :
874 : // While a plugin has focus, selection change notification shouldn't be
875 : // available.
876 0 : if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
877 0 : return NS_ERROR_FAILURE;
878 : }
879 :
880 : // Note that selection change must be notified after text change if it occurs.
881 : // Therefore, we don't need to query text content again here.
882 0 : mContentCache.SetSelection(
883 : this,
884 0 : aIMENotification.mSelectionChangeData.mOffset,
885 : aIMENotification.mSelectionChangeData.Length(),
886 0 : aIMENotification.mSelectionChangeData.mReversed,
887 0 : aIMENotification.mSelectionChangeData.GetWritingMode());
888 :
889 0 : mTabChild->SendNotifyIMESelection(mContentCache, aIMENotification);
890 :
891 0 : return NS_OK;
892 : }
893 :
894 : nsresult
895 0 : PuppetWidget::NotifyIMEOfMouseButtonEvent(
896 : const IMENotification& aIMENotification)
897 : {
898 0 : if (!mTabChild) {
899 0 : return NS_ERROR_FAILURE;
900 : }
901 :
902 : // While a plugin has focus, mouse button event notification shouldn't be
903 : // available.
904 0 : if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
905 0 : return NS_ERROR_FAILURE;
906 : }
907 :
908 :
909 0 : bool consumedByIME = false;
910 0 : if (!mTabChild->SendNotifyIMEMouseButtonEvent(aIMENotification,
911 : &consumedByIME)) {
912 0 : return NS_ERROR_FAILURE;
913 : }
914 :
915 0 : return consumedByIME ? NS_SUCCESS_EVENT_CONSUMED : NS_OK;
916 : }
917 :
918 : nsresult
919 0 : PuppetWidget::NotifyIMEOfPositionChange(const IMENotification& aIMENotification)
920 : {
921 0 : if (NS_WARN_IF(!mTabChild)) {
922 0 : return NS_ERROR_FAILURE;
923 : }
924 :
925 0 : if (NS_WARN_IF(!mContentCache.CacheEditorRect(this, &aIMENotification))) {
926 0 : return NS_ERROR_FAILURE;
927 : }
928 : // While a plugin has focus, selection range isn't available. So, we don't
929 : // need to cache it at that time.
930 0 : if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
931 0 : NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
932 0 : return NS_ERROR_FAILURE;
933 : }
934 0 : if (mIMENotificationRequestsOfParent.WantPositionChanged()) {
935 0 : mTabChild->SendNotifyIMEPositionChange(mContentCache, aIMENotification);
936 : } else {
937 0 : mTabChild->SendUpdateContentCache(mContentCache);
938 : }
939 0 : return NS_OK;
940 : }
941 :
942 : void
943 0 : PuppetWidget::SetCursor(nsCursor aCursor)
944 : {
945 : // Don't cache on windows, Windowless flash breaks this via async cursor updates.
946 : #if !defined(XP_WIN)
947 0 : if (mCursor == aCursor && !mCustomCursor && !mUpdateCursor) {
948 0 : return;
949 : }
950 : #endif
951 :
952 0 : mCustomCursor = nullptr;
953 :
954 0 : if (mTabChild &&
955 0 : !mTabChild->SendSetCursor(aCursor, mUpdateCursor)) {
956 0 : return;
957 : }
958 :
959 0 : mCursor = aCursor;
960 0 : mUpdateCursor = false;
961 : }
962 :
963 : nsresult
964 0 : PuppetWidget::SetCursor(imgIContainer* aCursor,
965 : uint32_t aHotspotX, uint32_t aHotspotY)
966 : {
967 0 : if (!aCursor || !mTabChild) {
968 0 : return NS_OK;
969 : }
970 :
971 : #if !defined(XP_WIN)
972 0 : if (mCustomCursor == aCursor &&
973 0 : mCursorHotspotX == aHotspotX &&
974 0 : mCursorHotspotY == aHotspotY &&
975 0 : !mUpdateCursor) {
976 0 : return NS_OK;
977 : }
978 : #endif
979 :
980 : RefPtr<mozilla::gfx::SourceSurface> surface =
981 0 : aCursor->GetFrame(imgIContainer::FRAME_CURRENT,
982 0 : imgIContainer::FLAG_SYNC_DECODE);
983 0 : if (!surface) {
984 0 : return NS_ERROR_FAILURE;
985 : }
986 :
987 : RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
988 0 : surface->GetDataSurface();
989 0 : if (!dataSurface) {
990 0 : return NS_ERROR_FAILURE;
991 : }
992 :
993 : size_t length;
994 : int32_t stride;
995 : mozilla::UniquePtr<char[]> surfaceData =
996 0 : nsContentUtils::GetSurfaceData(WrapNotNull(dataSurface), &length, &stride);
997 :
998 0 : nsDependentCString cursorData(surfaceData.get(), length);
999 0 : mozilla::gfx::IntSize size = dataSurface->GetSize();
1000 0 : if (!mTabChild->SendSetCustomCursor(cursorData, size.width, size.height, stride,
1001 0 : static_cast<uint8_t>(dataSurface->GetFormat()),
1002 : aHotspotX, aHotspotY, mUpdateCursor)) {
1003 0 : return NS_ERROR_FAILURE;
1004 : }
1005 :
1006 0 : mCursor = nsCursor(-1);
1007 0 : mCustomCursor = aCursor;
1008 0 : mCursorHotspotX = aHotspotX;
1009 0 : mCursorHotspotY = aHotspotY;
1010 0 : mUpdateCursor = false;
1011 :
1012 0 : return NS_OK;
1013 : }
1014 :
1015 : void
1016 0 : PuppetWidget::ClearCachedCursor()
1017 : {
1018 0 : nsBaseWidget::ClearCachedCursor();
1019 0 : mCustomCursor = nullptr;
1020 0 : }
1021 :
1022 : nsresult
1023 2 : PuppetWidget::Paint()
1024 : {
1025 2 : MOZ_ASSERT(!mDirtyRegion.IsEmpty(), "paint event logic messed up");
1026 :
1027 2 : if (!GetCurrentWidgetListener())
1028 0 : return NS_OK;
1029 :
1030 4 : LayoutDeviceIntRegion region = mDirtyRegion;
1031 :
1032 : // reset repaint tracking
1033 2 : mDirtyRegion.SetEmpty();
1034 2 : mPaintTask.Revoke();
1035 :
1036 4 : RefPtr<PuppetWidget> strongThis(this);
1037 :
1038 2 : GetCurrentWidgetListener()->WillPaintWindow(this);
1039 :
1040 2 : if (GetCurrentWidgetListener()) {
1041 : #ifdef DEBUG
1042 4 : debug_DumpPaintEvent(stderr, this, region.ToUnknownRegion(),
1043 2 : "PuppetWidget", 0);
1044 : #endif
1045 :
1046 2 : if (mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_CLIENT ||
1047 0 : mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_WR) {
1048 : // Do nothing, the compositor will handle drawing
1049 2 : if (mTabChild) {
1050 2 : mTabChild->NotifyPainted();
1051 : }
1052 0 : } else if (mozilla::layers::LayersBackend::LAYERS_BASIC == mLayerManager->GetBackendType()) {
1053 0 : RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(mDrawTarget);
1054 0 : if (!ctx) {
1055 0 : gfxDevCrash(LogReason::InvalidContext) << "PuppetWidget context problem " << gfx::hexa(mDrawTarget);
1056 0 : return NS_ERROR_FAILURE;
1057 : }
1058 0 : ctx->Rectangle(gfxRect(0,0,0,0));
1059 0 : ctx->Clip();
1060 : AutoLayerManagerSetup setupLayerManager(this, ctx,
1061 0 : BufferMode::BUFFER_NONE);
1062 0 : GetCurrentWidgetListener()->PaintWindow(this, region);
1063 0 : if (mTabChild) {
1064 0 : mTabChild->NotifyPainted();
1065 : }
1066 : }
1067 : }
1068 :
1069 2 : if (GetCurrentWidgetListener()) {
1070 2 : GetCurrentWidgetListener()->DidPaintWindow();
1071 : }
1072 :
1073 2 : return NS_OK;
1074 : }
1075 :
1076 : void
1077 0 : PuppetWidget::SetChild(PuppetWidget* aChild)
1078 : {
1079 0 : MOZ_ASSERT(this != aChild, "can't parent a widget to itself");
1080 0 : MOZ_ASSERT(!aChild->mChild,
1081 : "fake widget 'hierarchy' only expected to have one level");
1082 :
1083 0 : mChild = aChild;
1084 0 : }
1085 :
1086 : NS_IMETHODIMP
1087 2 : PuppetWidget::PaintTask::Run()
1088 : {
1089 2 : if (mWidget) {
1090 2 : mWidget->Paint();
1091 : }
1092 2 : return NS_OK;
1093 : }
1094 :
1095 : void
1096 0 : PuppetWidget::PaintNowIfNeeded()
1097 : {
1098 0 : if (IsVisible() && mPaintTask.IsPending()) {
1099 0 : Paint();
1100 : }
1101 0 : }
1102 :
1103 2 : NS_IMPL_ISUPPORTS(PuppetWidget::MemoryPressureObserver, nsIObserver)
1104 :
1105 : NS_IMETHODIMP
1106 0 : PuppetWidget::MemoryPressureObserver::Observe(nsISupports* aSubject,
1107 : const char* aTopic,
1108 : const char16_t* aData)
1109 : {
1110 0 : if (!mWidget) {
1111 0 : return NS_OK;
1112 : }
1113 :
1114 0 : if (strcmp("memory-pressure", aTopic) == 0 &&
1115 0 : !NS_LITERAL_STRING("lowering-priority").Equals(aData)) {
1116 0 : if (!mWidget->mVisible && mWidget->mLayerManager &&
1117 0 : XRE_IsContentProcess()) {
1118 0 : mWidget->mLayerManager->ClearCachedResources();
1119 : }
1120 : }
1121 0 : return NS_OK;
1122 : }
1123 :
1124 : void
1125 0 : PuppetWidget::MemoryPressureObserver::Remove()
1126 : {
1127 0 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1128 0 : if (obs) {
1129 0 : obs->RemoveObserver(this, "memory-pressure");
1130 : }
1131 0 : mWidget = nullptr;
1132 0 : }
1133 :
1134 : bool
1135 4 : PuppetWidget::NeedsPaint()
1136 : {
1137 : // e10s popups are handled by the parent process, so never should be painted here
1138 12 : if (XRE_IsContentProcess() &&
1139 8 : gRemoteDesktopBehaviorEnabled &&
1140 4 : mWindowType == eWindowType_popup) {
1141 0 : NS_WARNING("Trying to paint an e10s popup in the child process!");
1142 0 : return false;
1143 : }
1144 :
1145 4 : return mVisible;
1146 : }
1147 :
1148 : float
1149 8 : PuppetWidget::GetDPI()
1150 : {
1151 8 : if (mDPI < 0) {
1152 2 : if (mTabChild) {
1153 2 : mTabChild->GetDPI(&mDPI);
1154 : } else {
1155 0 : mDPI = 96.0;
1156 : }
1157 : }
1158 :
1159 8 : return mDPI;
1160 : }
1161 :
1162 : double
1163 20 : PuppetWidget::GetDefaultScaleInternal()
1164 : {
1165 20 : if (mDefaultScale < 0) {
1166 2 : if (mTabChild) {
1167 2 : mTabChild->GetDefaultScale(&mDefaultScale);
1168 : } else {
1169 0 : mDefaultScale = 1;
1170 : }
1171 : }
1172 :
1173 20 : return mDefaultScale;
1174 : }
1175 :
1176 : int32_t
1177 0 : PuppetWidget::RoundsWidgetCoordinatesTo()
1178 : {
1179 0 : if (mRounding < 0) {
1180 0 : if (mTabChild) {
1181 0 : mTabChild->GetWidgetRounding(&mRounding);
1182 : } else {
1183 0 : mRounding = 1;
1184 : }
1185 : }
1186 :
1187 0 : return mRounding;
1188 : }
1189 :
1190 : void*
1191 1 : PuppetWidget::GetNativeData(uint32_t aDataType)
1192 : {
1193 1 : switch (aDataType) {
1194 : case NS_NATIVE_SHAREABLE_WINDOW: {
1195 : // NOTE: We can not have a tab child in some situations, such as when we're
1196 : // rendering to a fake widget for thumbnails.
1197 0 : if (!mTabChild) {
1198 0 : NS_WARNING("Need TabChild to get the nativeWindow from!");
1199 : }
1200 0 : mozilla::WindowsHandle nativeData = 0;
1201 0 : if (mTabChild) {
1202 0 : nativeData = mTabChild->WidgetNativeData();
1203 : }
1204 0 : return (void*)nativeData;
1205 : }
1206 : case NS_NATIVE_WINDOW:
1207 : case NS_NATIVE_WIDGET:
1208 : case NS_NATIVE_DISPLAY:
1209 : // These types are ignored (see bug 1183828, bug 1240891).
1210 1 : break;
1211 : case NS_RAW_NATIVE_IME_CONTEXT:
1212 0 : MOZ_CRASH("You need to call GetNativeIMEContext() instead");
1213 : case NS_NATIVE_PLUGIN_PORT:
1214 : case NS_NATIVE_GRAPHIC:
1215 : case NS_NATIVE_SHELLWIDGET:
1216 : default:
1217 0 : NS_WARNING("nsWindow::GetNativeData called with bad value");
1218 0 : break;
1219 : }
1220 1 : return nullptr;
1221 : }
1222 :
1223 : #if defined(XP_WIN)
1224 : void
1225 : PuppetWidget::SetNativeData(uint32_t aDataType, uintptr_t aVal)
1226 : {
1227 : switch (aDataType) {
1228 : case NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW:
1229 : MOZ_ASSERT(mTabChild, "Need TabChild to send the message.");
1230 : if (mTabChild) {
1231 : mTabChild->SendSetNativeChildOfShareableWindow(aVal);
1232 : }
1233 : break;
1234 : default:
1235 : NS_WARNING("SetNativeData called with unsupported data type.");
1236 : }
1237 : }
1238 : #endif
1239 :
1240 : nsIntPoint
1241 0 : PuppetWidget::GetChromeDimensions()
1242 : {
1243 0 : if (!GetOwningTabChild()) {
1244 0 : NS_WARNING("PuppetWidget without Tab does not have chrome information.");
1245 0 : return nsIntPoint();
1246 : }
1247 0 : return GetOwningTabChild()->GetChromeDisplacement().ToUnknownPoint();
1248 : }
1249 :
1250 : nsIntPoint
1251 0 : PuppetWidget::GetWindowPosition()
1252 : {
1253 0 : if (!GetOwningTabChild()) {
1254 0 : return nsIntPoint();
1255 : }
1256 :
1257 : int32_t winX, winY, winW, winH;
1258 0 : NS_ENSURE_SUCCESS(GetOwningTabChild()->GetDimensions(0, &winX, &winY, &winW, &winH), nsIntPoint());
1259 0 : return nsIntPoint(winX, winY) + GetOwningTabChild()->GetClientOffset().ToUnknownPoint();
1260 : }
1261 :
1262 : LayoutDeviceIntRect
1263 0 : PuppetWidget::GetScreenBounds()
1264 : {
1265 0 : return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
1266 : }
1267 :
1268 0 : uint32_t PuppetWidget::GetMaxTouchPoints() const
1269 : {
1270 0 : uint32_t maxTouchPoints = 0;
1271 0 : if (mTabChild) {
1272 0 : mTabChild->GetMaxTouchPoints(&maxTouchPoints);
1273 : }
1274 0 : return maxTouchPoints;
1275 : }
1276 :
1277 : void
1278 0 : PuppetWidget::StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics)
1279 : {
1280 0 : mTabChild->StartScrollbarDrag(aDragMetrics);
1281 0 : }
1282 :
1283 0 : PuppetScreen::PuppetScreen(void *nativeScreen)
1284 : {
1285 0 : }
1286 :
1287 0 : PuppetScreen::~PuppetScreen()
1288 : {
1289 0 : }
1290 :
1291 : static ScreenConfiguration
1292 0 : ScreenConfig()
1293 : {
1294 0 : ScreenConfiguration config;
1295 0 : hal::GetCurrentScreenConfiguration(&config);
1296 0 : return config;
1297 : }
1298 :
1299 : nsIntSize
1300 0 : PuppetWidget::GetScreenDimensions()
1301 : {
1302 0 : nsIntRect r = ScreenConfig().rect();
1303 0 : return nsIntSize(r.width, r.height);
1304 : }
1305 :
1306 : NS_IMETHODIMP
1307 0 : PuppetScreen::GetRect(int32_t *outLeft, int32_t *outTop,
1308 : int32_t *outWidth, int32_t *outHeight)
1309 : {
1310 0 : nsIntRect r = ScreenConfig().rect();
1311 0 : *outLeft = r.x;
1312 0 : *outTop = r.y;
1313 0 : *outWidth = r.width;
1314 0 : *outHeight = r.height;
1315 0 : return NS_OK;
1316 : }
1317 :
1318 : NS_IMETHODIMP
1319 0 : PuppetScreen::GetAvailRect(int32_t *outLeft, int32_t *outTop,
1320 : int32_t *outWidth, int32_t *outHeight)
1321 : {
1322 0 : return GetRect(outLeft, outTop, outWidth, outHeight);
1323 : }
1324 :
1325 : NS_IMETHODIMP
1326 0 : PuppetScreen::GetPixelDepth(int32_t *aPixelDepth)
1327 : {
1328 0 : *aPixelDepth = ScreenConfig().pixelDepth();
1329 0 : return NS_OK;
1330 : }
1331 :
1332 : NS_IMETHODIMP
1333 0 : PuppetScreen::GetColorDepth(int32_t *aColorDepth)
1334 : {
1335 0 : *aColorDepth = ScreenConfig().colorDepth();
1336 0 : return NS_OK;
1337 : }
1338 :
1339 0 : NS_IMPL_ISUPPORTS(PuppetScreenManager, nsIScreenManager)
1340 :
1341 0 : PuppetScreenManager::PuppetScreenManager()
1342 : {
1343 0 : mOneScreen = new PuppetScreen(nullptr);
1344 0 : }
1345 :
1346 0 : PuppetScreenManager::~PuppetScreenManager()
1347 : {
1348 0 : }
1349 :
1350 : NS_IMETHODIMP
1351 0 : PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen)
1352 : {
1353 0 : NS_IF_ADDREF(*outScreen = mOneScreen.get());
1354 0 : return NS_OK;
1355 : }
1356 :
1357 : NS_IMETHODIMP
1358 0 : PuppetScreenManager::ScreenForRect(int32_t inLeft,
1359 : int32_t inTop,
1360 : int32_t inWidth,
1361 : int32_t inHeight,
1362 : nsIScreen** outScreen)
1363 : {
1364 0 : return GetPrimaryScreen(outScreen);
1365 : }
1366 :
1367 : nsIWidgetListener*
1368 26 : PuppetWidget::GetCurrentWidgetListener()
1369 : {
1370 26 : if (!mPreviouslyAttachedWidgetListener ||
1371 0 : !mAttachedWidgetListener) {
1372 26 : return mAttachedWidgetListener;
1373 : }
1374 :
1375 0 : if (mAttachedWidgetListener->GetView()->IsPrimaryFramePaintSuppressed()) {
1376 0 : return mPreviouslyAttachedWidgetListener;
1377 : }
1378 :
1379 0 : return mAttachedWidgetListener;
1380 : }
1381 :
1382 : void
1383 0 : PuppetWidget::SetCandidateWindowForPlugin(
1384 : const CandidateWindowPosition& aPosition)
1385 : {
1386 0 : if (!mTabChild) {
1387 0 : return;
1388 : }
1389 :
1390 0 : mTabChild->SendSetCandidateWindowForPlugin(aPosition);
1391 : }
1392 :
1393 : void
1394 0 : PuppetWidget::ZoomToRect(const uint32_t& aPresShellId,
1395 : const FrameMetrics::ViewID& aViewId,
1396 : const CSSRect& aRect,
1397 : const uint32_t& aFlags)
1398 : {
1399 0 : if (!mTabChild) {
1400 0 : return;
1401 : }
1402 :
1403 0 : mTabChild->ZoomToRect(aPresShellId, aViewId, aRect, aFlags);
1404 : }
1405 :
1406 : void
1407 0 : PuppetWidget::LookUpDictionary(
1408 : const nsAString& aText,
1409 : const nsTArray<mozilla::FontRange>& aFontRangeArray,
1410 : const bool aIsVertical,
1411 : const LayoutDeviceIntPoint& aPoint)
1412 : {
1413 0 : if (!mTabChild) {
1414 0 : return;
1415 : }
1416 :
1417 0 : mTabChild->SendLookUpDictionary(nsString(aText), aFontRangeArray, aIsVertical, aPoint);
1418 : }
1419 :
1420 : bool
1421 0 : PuppetWidget::HasPendingInputEvent()
1422 : {
1423 0 : if (!mTabChild) {
1424 0 : return false;
1425 : }
1426 :
1427 0 : bool ret = false;
1428 :
1429 0 : mTabChild->GetIPCChannel()->PeekMessages(
1430 0 : [&ret](const IPC::Message& aMsg) -> bool {
1431 0 : if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart)
1432 : == mozilla::dom::PBrowser::PBrowserStart) {
1433 0 : switch (aMsg.type()) {
1434 : case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID:
1435 : case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID:
1436 : case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID:
1437 : case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID:
1438 : case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID:
1439 : case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID:
1440 : case mozilla::dom::PBrowser::Msg_RealDragEvent__ID:
1441 : case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID:
1442 : case mozilla::dom::PBrowser::Msg_MouseEvent__ID:
1443 : case mozilla::dom::PBrowser::Msg_KeyEvent__ID:
1444 : case mozilla::dom::PBrowser::Msg_SetDocShellIsActive__ID:
1445 0 : ret = true;
1446 0 : return false; // Stop peeking.
1447 : }
1448 : }
1449 0 : return true;
1450 : }
1451 0 : );
1452 :
1453 0 : return ret;
1454 : }
1455 :
1456 : void
1457 0 : PuppetWidget::HandledWindowedPluginKeyEvent(
1458 : const NativeEventData& aKeyEventData,
1459 : bool aIsConsumed)
1460 : {
1461 0 : if (NS_WARN_IF(mKeyEventInPluginCallbacks.IsEmpty())) {
1462 0 : return;
1463 : }
1464 : nsCOMPtr<nsIKeyEventInPluginCallback> callback =
1465 0 : mKeyEventInPluginCallbacks[0];
1466 0 : MOZ_ASSERT(callback);
1467 0 : mKeyEventInPluginCallbacks.RemoveElementAt(0);
1468 0 : callback->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
1469 : }
1470 :
1471 : nsresult
1472 0 : PuppetWidget::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
1473 : nsIKeyEventInPluginCallback* aCallback)
1474 : {
1475 0 : if (NS_WARN_IF(!mTabChild)) {
1476 0 : return NS_ERROR_NOT_AVAILABLE;
1477 : }
1478 0 : if (NS_WARN_IF(!mTabChild->SendOnWindowedPluginKeyEvent(aKeyEventData))) {
1479 0 : return NS_ERROR_FAILURE;
1480 : }
1481 0 : mKeyEventInPluginCallbacks.AppendElement(aCallback);
1482 0 : return NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY;
1483 : }
1484 :
1485 : // TextEventDispatcherListener
1486 :
1487 : NS_IMETHODIMP
1488 0 : PuppetWidget::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
1489 : const IMENotification& aNotification)
1490 : {
1491 0 : MOZ_ASSERT(aTextEventDispatcher == mTextEventDispatcher);
1492 0 : return NS_ERROR_NOT_IMPLEMENTED;
1493 : }
1494 :
1495 : NS_IMETHODIMP_(IMENotificationRequests)
1496 0 : PuppetWidget::GetIMENotificationRequests()
1497 : {
1498 0 : if (mInputContext.mIMEState.mEnabled == IMEState::PLUGIN) {
1499 : // If a plugin has focus, we cannot receive text nor selection change
1500 : // in the plugin. Therefore, PuppetWidget needs to receive only position
1501 : // change event for updating the editor rect cache.
1502 0 : return IMENotificationRequests(
1503 0 : mIMENotificationRequestsOfParent.mWantUpdates |
1504 0 : IMENotificationRequests::NOTIFY_POSITION_CHANGE);
1505 : }
1506 0 : return IMENotificationRequests(
1507 0 : mIMENotificationRequestsOfParent.mWantUpdates |
1508 0 : IMENotificationRequests::NOTIFY_TEXT_CHANGE |
1509 0 : IMENotificationRequests::NOTIFY_POSITION_CHANGE);
1510 : }
1511 :
1512 : NS_IMETHODIMP_(void)
1513 0 : PuppetWidget::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
1514 : {
1515 0 : MOZ_ASSERT(aTextEventDispatcher == mTextEventDispatcher);
1516 0 : }
1517 :
1518 : NS_IMETHODIMP_(void)
1519 0 : PuppetWidget::WillDispatchKeyboardEvent(
1520 : TextEventDispatcher* aTextEventDispatcher,
1521 : WidgetKeyboardEvent& aKeyboardEvent,
1522 : uint32_t aIndexOfKeypress,
1523 : void* aData)
1524 : {
1525 0 : MOZ_ASSERT(aTextEventDispatcher == mTextEventDispatcher);
1526 0 : }
1527 :
1528 : } // namespace widget
1529 : } // namespace mozilla
|