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 /**
9  * This "puppet widget" isn't really a platform widget.  It's intended
10  * to be used in widgetless rendering contexts, such as sandboxed
11  * content processes.  If any "real" widgetry is needed, the request
12  * is forwarded to and/or data received from elsewhere.
13  */
14 
15 #ifndef mozilla_widget_PuppetWidget_h__
16 #define mozilla_widget_PuppetWidget_h__
17 
18 #include "mozilla/gfx/2D.h"
19 #include "mozilla/RefPtr.h"
20 #include "nsBaseScreen.h"
21 #include "nsBaseWidget.h"
22 #include "nsCOMArray.h"
23 #include "nsIKeyEventInPluginCallback.h"
24 #include "nsIScreenManager.h"
25 #include "nsThreadUtils.h"
26 #include "mozilla/Attributes.h"
27 #include "mozilla/ContentCache.h"
28 #include "mozilla/EventForwards.h"
29 
30 namespace mozilla {
31 
32 namespace dom {
33 class TabChild;
34 } // namespace dom
35 
36 namespace widget {
37 
38 struct AutoCacheNativeKeyCommands;
39 
40 class PuppetWidget : public nsBaseWidget
41 {
42   typedef mozilla::dom::TabChild TabChild;
43   typedef mozilla::gfx::DrawTarget DrawTarget;
44   typedef nsBaseWidget Base;
45   typedef mozilla::CSSRect CSSRect;
46 
47   // The width and height of the "widget" are clamped to this.
48   static const size_t kMaxDimension;
49 
50 public:
51   explicit PuppetWidget(TabChild* aTabChild);
52 
53 protected:
54   virtual ~PuppetWidget();
55 
56 public:
57   NS_DECL_ISUPPORTS_INHERITED
58 
59   // PuppetWidget creation is infallible, hence InfallibleCreate(), which
60   // Create() calls.
61   using nsBaseWidget::Create; // for Create signature not overridden here
62   virtual nsresult Create(nsIWidget* aParent,
63                           nsNativeWidget aNativeParent,
64                           const LayoutDeviceIntRect& aRect,
65                           nsWidgetInitData* aInitData = nullptr)
66                           override;
67   void InfallibleCreate(nsIWidget* aParent,
68                         nsNativeWidget aNativeParent,
69                         const LayoutDeviceIntRect& aRect,
70                         nsWidgetInitData* aInitData = nullptr);
71 
72   void InitIMEState();
73 
74   virtual already_AddRefed<nsIWidget>
75   CreateChild(const LayoutDeviceIntRect& aRect,
76               nsWidgetInitData* aInitData = nullptr,
77               bool aForceUseIWidgetParent = false) override;
78 
79   virtual void Destroy() override;
80 
81   NS_IMETHOD Show(bool aState) override;
82 
IsVisible()83   virtual bool IsVisible() const override
84   { return mVisible; }
85 
ConstrainPosition(bool,int32_t * aX,int32_t * aY)86   virtual void ConstrainPosition(bool     /*ignored aAllowSlop*/,
87                                  int32_t* aX,
88                                  int32_t* aY) override
89   { *aX = kMaxDimension; *aY = kMaxDimension; }
90 
91   // Widget position is controlled by the parent process via TabChild.
Move(double aX,double aY)92   NS_IMETHOD Move(double aX, double aY) override
93   { return NS_OK; }
94 
95   NS_IMETHOD Resize(double aWidth,
96                     double aHeight,
97                     bool   aRepaint) override;
Resize(double aX,double aY,double aWidth,double aHeight,bool aRepaint)98   NS_IMETHOD Resize(double aX,
99                     double aY,
100                     double aWidth,
101                     double aHeight,
102                     bool   aRepaint) override
103   {
104     if (mBounds.x != aX || mBounds.y != aY) {
105       NotifyWindowMoved(aX, aY);
106     }
107     mBounds.x = aX;
108     mBounds.y = aY;
109     return Resize(aWidth, aHeight, aRepaint);
110   }
111 
112   // XXX/cjones: copying gtk behavior here; unclear what disabling a
113   // widget is supposed to entail
Enable(bool aState)114   NS_IMETHOD Enable(bool aState) override
115   { mEnabled = aState;  return NS_OK; }
IsEnabled()116   virtual bool IsEnabled() const override
117   { return mEnabled; }
118 
119   NS_IMETHOD SetFocus(bool aRaise = false) override;
120 
121   virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
122 
123   NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect) override;
124 
125   // PuppetWidgets don't have native data, as they're purely nonnative.
126   virtual void* GetNativeData(uint32_t aDataType) override;
127 #if defined(XP_WIN)
128   void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
129 #endif
130 
131   // PuppetWidgets don't have any concept of titles.
SetTitle(const nsAString & aTitle)132   NS_IMETHOD SetTitle(const nsAString& aTitle) override
133   { return NS_ERROR_UNEXPECTED; }
134 
WidgetToScreenOffset()135   virtual LayoutDeviceIntPoint WidgetToScreenOffset() override
136   { return LayoutDeviceIntPoint::FromUnknownPoint(GetWindowPosition() + GetChromeDimensions()); }
137 
138   int32_t RoundsWidgetCoordinatesTo() override;
139 
140   void InitEvent(WidgetGUIEvent& aEvent,
141                  LayoutDeviceIntPoint* aPoint = nullptr);
142 
143   NS_IMETHOD DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) override;
144   nsEventStatus DispatchInputEvent(WidgetInputEvent* aEvent) override;
145   void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
146                               const nsTArray<ScrollableLayerGuid>& aTargets) const override;
147   void UpdateZoomConstraints(const uint32_t& aPresShellId,
148                              const FrameMetrics::ViewID& aViewId,
149                              const mozilla::Maybe<ZoomConstraints>& aConstraints) override;
150   bool AsyncPanZoomEnabled() const override;
151 
152   NS_IMETHOD_(bool)
153   ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
154                           const mozilla::WidgetKeyboardEvent& aEvent,
155                           DoCommandCallback aCallback,
156                           void* aCallbackData) override;
157 
158   friend struct AutoCacheNativeKeyCommands;
159 
160   //
161   // nsBaseWidget methods we override
162   //
163 
164   // Documents loaded in child processes are always subdocuments of
165   // other docs in an ancestor process.  To ensure that the
166   // backgrounds of those documents are painted like those of
167   // same-process subdocuments, we force the widget here to be
168   // transparent, which in turn will cause layout to use a transparent
169   // backstop background color.
GetTransparencyMode()170   virtual nsTransparencyMode GetTransparencyMode() override
171   { return eTransparencyTransparent; }
172 
173   virtual LayerManager*
174   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
175                   LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
176                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
177 
178   // This is used after a compositor reset.
179   LayerManager* RecreateLayerManager(PLayerTransactionChild* aShadowManager);
180 
181   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
182                                     const InputContextAction& aAction) override;
183   NS_IMETHOD_(InputContext) GetInputContext() override;
184   NS_IMETHOD_(NativeIMEContext) GetNativeIMEContext() override;
185   virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
186 
187   NS_IMETHOD SetCursor(nsCursor aCursor) override;
188   NS_IMETHOD SetCursor(imgIContainer* aCursor,
189                        uint32_t aHotspotX, uint32_t aHotspotY) override;
190 
191   virtual void ClearCachedCursor() override;
192 
193   // Gets the DPI of the screen corresponding to this widget.
194   // Contacts the parent process which gets the DPI from the
195   // proper widget there. TODO: Handle DPI changes that happen
196   // later on.
197   virtual float GetDPI() override;
198   virtual double GetDefaultScaleInternal() override;
199 
200   virtual bool NeedsPaint() override;
201 
202   // Paint the widget immediately if any paints are queued up.
203   void PaintNowIfNeeded();
204 
GetOwningTabChild()205   virtual TabChild* GetOwningTabChild() override { return mTabChild; }
206 
UpdateBackingScaleCache(float aDpi,int32_t aRounding,double aScale)207   void UpdateBackingScaleCache(float aDpi, int32_t aRounding, double aScale)
208   {
209     mDPI = aDpi;
210     mRounding = aRounding;
211     mDefaultScale = aScale;
212   }
213 
214   nsIntSize GetScreenDimensions();
215 
216   // Get the size of the chrome of the window that this tab belongs to.
217   nsIntPoint GetChromeDimensions();
218 
219   // Get the screen position of the application window.
220   nsIntPoint GetWindowPosition();
221 
222   virtual LayoutDeviceIntRect GetScreenBounds() override;
223 
224   NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
225                             int32_t aPanelX, int32_t aPanelY,
226                             nsString& aCommitted) override;
227 
228   virtual void SetPluginFocused(bool& aFocused) override;
229   virtual void DefaultProcOfPluginEvent(
230                  const mozilla::WidgetPluginEvent& aEvent) override;
231 
232   virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
233                                             int32_t aNativeKeyCode,
234                                             uint32_t aModifierFlags,
235                                             const nsAString& aCharacters,
236                                             const nsAString& aUnmodifiedCharacters,
237                                             nsIObserver* aObserver) override;
238   virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
239                                               uint32_t aNativeMessage,
240                                               uint32_t aModifierFlags,
241                                               nsIObserver* aObserver) override;
242   virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
243                                              nsIObserver* aObserver) override;
244   virtual nsresult SynthesizeNativeMouseScrollEvent(LayoutDeviceIntPoint aPoint,
245                                                     uint32_t aNativeMessage,
246                                                     double aDeltaX,
247                                                     double aDeltaY,
248                                                     double aDeltaZ,
249                                                     uint32_t aModifierFlags,
250                                                     uint32_t aAdditionalFlags,
251                                                     nsIObserver* aObserver) override;
252   virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
253                                               TouchPointerState aPointerState,
254                                               LayoutDeviceIntPoint aPoint,
255                                               double aPointerPressure,
256                                               uint32_t aPointerOrientation,
257                                               nsIObserver* aObserver) override;
258   virtual nsresult SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint,
259                                             bool aLongTap,
260                                             nsIObserver* aObserver) override;
261   virtual nsresult ClearNativeTouchSequence(nsIObserver* aObserver) override;
262   virtual uint32_t GetMaxTouchPoints() const override;
263 
264   virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
265 
266   virtual void SetCandidateWindowForPlugin(
267                  const CandidateWindowPosition& aPosition) override;
268 
269   virtual void ZoomToRect(const uint32_t& aPresShellId,
270                           const FrameMetrics::ViewID& aViewId,
271                           const CSSRect& aRect,
272                           const uint32_t& aFlags) override;
273 
274   virtual bool HasPendingInputEvent() override;
275 
276   void HandledWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
277                                      bool aIsConsumed);
278   virtual nsresult OnWindowedPluginKeyEvent(
279                      const NativeEventData& aKeyEventData,
280                      nsIKeyEventInPluginCallback* aCallback) override;
281 
282   virtual void LookUpDictionary(
283                  const nsAString& aText,
284                  const nsTArray<mozilla::FontRange>& aFontRangeArray,
285                  const bool aIsVertical,
286                  const LayoutDeviceIntPoint& aPoint) override;
287 
288 protected:
289   virtual nsresult NotifyIMEInternal(
290                      const IMENotification& aIMENotification) override;
291 
292 private:
293   nsresult Paint();
294 
295   void SetChild(PuppetWidget* aChild);
296 
297   nsresult RequestIMEToCommitComposition(bool aCancel);
298   nsresult NotifyIMEOfFocusChange(const IMENotification& aIMENotification);
299   nsresult NotifyIMEOfSelectionChange(const IMENotification& aIMENotification);
300   nsresult NotifyIMEOfCompositionUpdate(const IMENotification& aIMENotification);
301   nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification);
302   nsresult NotifyIMEOfMouseButtonEvent(const IMENotification& aIMENotification);
303   nsresult NotifyIMEOfPositionChange(const IMENotification& aIMENotification);
304 
305   bool CacheEditorRect();
306   bool CacheCompositionRects(uint32_t& aStartOffset,
307                              nsTArray<LayoutDeviceIntRect>& aRectArray,
308                              uint32_t& aTargetCauseOffset);
309   bool GetCaretRect(LayoutDeviceIntRect& aCaretRect, uint32_t aCaretOffset);
310   uint32_t GetCaretOffset();
311 
312   nsIWidgetListener* GetCurrentWidgetListener();
313 
314   class PaintTask : public Runnable {
315   public:
316     NS_DECL_NSIRUNNABLE
PaintTask(PuppetWidget * widget)317     explicit PaintTask(PuppetWidget* widget) : mWidget(widget) {}
Revoke()318     void Revoke() { mWidget = nullptr; }
319   private:
320     PuppetWidget* mWidget;
321   };
322 
323   class MemoryPressureObserver : public nsIObserver {
324   public:
325     NS_DECL_ISUPPORTS
326     NS_DECL_NSIOBSERVER
MemoryPressureObserver(PuppetWidget * aWidget)327     explicit MemoryPressureObserver(PuppetWidget* aWidget) : mWidget(aWidget) {}
328     void Remove();
329   private:
~MemoryPressureObserver()330     virtual ~MemoryPressureObserver() {}
331     PuppetWidget* mWidget;
332   };
333   friend class MemoryPressureObserver;
334 
335   // TabChild normally holds a strong reference to this PuppetWidget
336   // or its root ancestor, but each PuppetWidget also needs a
337   // reference back to TabChild (e.g. to delegate nsIWidget IME calls
338   // to chrome) So we hold a weak reference to TabChild here.  Since
339   // it's possible for TabChild to outlive the PuppetWidget, we clear
340   // this weak reference in Destroy()
341   TabChild* mTabChild;
342   // The "widget" to which we delegate events if we don't have an
343   // event handler.
344   RefPtr<PuppetWidget> mChild;
345   LayoutDeviceIntRegion mDirtyRegion;
346   nsRevocableEventPtr<PaintTask> mPaintTask;
347   RefPtr<MemoryPressureObserver> mMemoryPressureObserver;
348   // XXX/cjones: keeping this around until we teach LayerManager to do
349   // retained-content-only transactions
350   RefPtr<DrawTarget> mDrawTarget;
351   // IME
352   nsIMEUpdatePreference mIMEPreferenceOfParent;
353   InputContext mInputContext;
354   // mNativeIMEContext is initialized when this dispatches every composition
355   // event both from parent process's widget and TextEventDispatcher in same
356   // process.  If it hasn't been started composition yet, this isn't necessary
357   // for XP code since there is no TextComposition instance which is caused by
358   // the PuppetWidget instance.
359   NativeIMEContext mNativeIMEContext;
360   ContentCacheInChild mContentCache;
361 
362   // The DPI of the screen corresponding to this widget
363   float mDPI;
364   int32_t mRounding;
365   double mDefaultScale;
366 
367   // Precomputed answers for ExecuteNativeKeyBinding
368   InfallibleTArray<mozilla::CommandInt> mSingleLineCommands;
369   InfallibleTArray<mozilla::CommandInt> mMultiLineCommands;
370   InfallibleTArray<mozilla::CommandInt> mRichTextCommands;
371 
372   nsCOMPtr<imgIContainer> mCustomCursor;
373   uint32_t mCursorHotspotX, mCursorHotspotY;
374 
375   nsCOMArray<nsIKeyEventInPluginCallback> mKeyEventInPluginCallbacks;
376 
377 protected:
378   bool mEnabled;
379   bool mVisible;
380 
381 private:
382   bool mNeedIMEStateInit;
383   bool mNativeKeyCommandsValid;
384 };
385 
386 struct AutoCacheNativeKeyCommands
387 {
AutoCacheNativeKeyCommandsAutoCacheNativeKeyCommands388   explicit AutoCacheNativeKeyCommands(PuppetWidget* aWidget)
389     : mWidget(aWidget)
390   {
391     mSavedValid = mWidget->mNativeKeyCommandsValid;
392     mSavedSingleLine = mWidget->mSingleLineCommands;
393     mSavedMultiLine = mWidget->mMultiLineCommands;
394     mSavedRichText = mWidget->mRichTextCommands;
395   }
396 
CacheAutoCacheNativeKeyCommands397   void Cache(const InfallibleTArray<mozilla::CommandInt>& aSingleLineCommands,
398              const InfallibleTArray<mozilla::CommandInt>& aMultiLineCommands,
399              const InfallibleTArray<mozilla::CommandInt>& aRichTextCommands)
400   {
401     mWidget->mNativeKeyCommandsValid = true;
402     mWidget->mSingleLineCommands = aSingleLineCommands;
403     mWidget->mMultiLineCommands = aMultiLineCommands;
404     mWidget->mRichTextCommands = aRichTextCommands;
405   }
406 
CacheNoCommandsAutoCacheNativeKeyCommands407   void CacheNoCommands()
408   {
409     mWidget->mNativeKeyCommandsValid = true;
410     mWidget->mSingleLineCommands.Clear();
411     mWidget->mMultiLineCommands.Clear();
412     mWidget->mRichTextCommands.Clear();
413   }
414 
~AutoCacheNativeKeyCommandsAutoCacheNativeKeyCommands415   ~AutoCacheNativeKeyCommands()
416   {
417     mWidget->mNativeKeyCommandsValid = mSavedValid;
418     mWidget->mSingleLineCommands = mSavedSingleLine;
419     mWidget->mMultiLineCommands = mSavedMultiLine;
420     mWidget->mRichTextCommands = mSavedRichText;
421   }
422 
423 private:
424   PuppetWidget* mWidget;
425   bool mSavedValid;
426   InfallibleTArray<mozilla::CommandInt> mSavedSingleLine;
427   InfallibleTArray<mozilla::CommandInt> mSavedMultiLine;
428   InfallibleTArray<mozilla::CommandInt> mSavedRichText;
429 };
430 
431 class PuppetScreen : public nsBaseScreen
432 {
433 public:
434     explicit PuppetScreen(void* nativeScreen);
435     ~PuppetScreen();
436 
437     NS_IMETHOD GetId(uint32_t* aId) override;
438     NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) override;
439     NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) override;
440     NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override;
441     NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override;
442     NS_IMETHOD GetRotation(uint32_t* aRotation) override;
443     NS_IMETHOD SetRotation(uint32_t  aRotation) override;
444 };
445 
446 class PuppetScreenManager final : public nsIScreenManager
447 {
448     ~PuppetScreenManager();
449 
450 public:
451     PuppetScreenManager();
452 
453     NS_DECL_ISUPPORTS
454     NS_DECL_NSISCREENMANAGER
455 
456 protected:
457     nsCOMPtr<nsIScreen> mOneScreen;
458 };
459 
460 } // namespace widget
461 } // namespace mozilla
462 
463 #endif  // mozilla_widget_PuppetWidget_h__
464