Coverage Report

Created: 2018-09-25 14:53

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