summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsPluginFrame.h
blob: 7a1509c876dd18e86c996538f176537be934530c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* rendering objects for replaced elements implemented by a plugin */

#ifndef nsPluginFrame_h___
#define nsPluginFrame_h___

#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/UniquePtr.h"
#include "nsIObjectFrame.h"
#include "nsIFrame.h"
#include "nsRegion.h"
#include "nsDisplayList.h"
#include "nsIReflowCallback.h"
#include "Units.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/webrender/WebRenderAPI.h"

#ifdef XP_WIN
#  include <windows.h>  // For HWND :(
// Undo the windows.h damage
#  undef GetMessage
#  undef CreateEvent
#  undef GetClassName
#  undef GetBinaryType
#  undef RemoveDirectory
#  undef LoadIcon
#  undef LoadImage
#  undef GetObject
#endif

class nsPresContext;
class nsRootPresContext;
class nsDisplayPlugin;
class PluginBackgroundSink;
class nsPluginInstanceOwner;

namespace mozilla {
class PresShell;
namespace layers {
class ImageContainer;
class Layer;
class LayerManager;
}  // namespace layers
}  // namespace mozilla

class PluginFrameDidCompositeObserver;

class nsPluginFrame final : public nsIFrame,
                            public nsIObjectFrame,
                            public nsIReflowCallback {
 public:
  typedef mozilla::LayerState LayerState;
  typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
  typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
  typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
  typedef mozilla::layers::Layer Layer;
  typedef mozilla::layers::LayerManager LayerManager;
  typedef mozilla::layers::ImageContainer ImageContainer;
  typedef mozilla::layers::StackingContextHelper StackingContextHelper;
  typedef mozilla::layers::RenderRootStateManager RenderRootStateManager;
  typedef mozilla::layers::WebRenderParentCommand WebRenderParentCommand;
  typedef mozilla::ContainerLayerParameters ContainerLayerParameters;

  NS_DECL_FRAMEARENA_HELPERS(nsPluginFrame)
  NS_DECL_QUERYFRAME

  friend nsIFrame* NS_NewObjectFrame(mozilla::PresShell* aPresShell,
                                     ComputedStyle* aStyle);

  virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
                    nsIFrame* aPrevInFlow) override;
  virtual nscoord GetMinISize(gfxContext* aRenderingContext) override;
  virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;
  virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
                      const ReflowInput& aReflowInput,
                      nsReflowStatus& aStatus) override;
  virtual void DidReflow(nsPresContext* aPresContext,
                         const ReflowInput* aReflowInput) override;
  virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
                                const nsDisplayListSet& aLists) override;

  MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual nsresult HandleEvent(
      nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent,
      nsEventStatus* aEventStatus) override;

  virtual bool IsFrameOfType(uint32_t aFlags) const override {
    return nsIFrame::IsFrameOfType(
        aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing));
  }

#ifdef DEBUG_FRAME_DUMP
  virtual nsresult GetFrameName(nsAString& aResult) const override;
#endif

  virtual void DestroyFrom(nsIFrame* aDestructRoot,
                           PostDestroyData& aPostDestroyData) override;

  virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;

  nsNPAPIPluginInstance* GetPluginInstance() override;

  virtual void SetIsDocumentActive(bool aIsActive) override;

  mozilla::Maybe<Cursor> GetCursor(const nsPoint&) override;

  // APIs used by nsRootPresContext to set up the widget position/size/clip
  // region.
  /**
   * Set the next widget configuration for the plugin to the desired
   * position of the plugin's widget, on the assumption that it is not visible
   * (clipped out or covered by opaque content).
   * This will only be called for plugins which have been registered
   * with the root pres context for geometry updates.
   * If there is no widget associated with the plugin, this will have no effect.
   */
  void SetEmptyWidgetConfiguration() {
    mNextConfigurationBounds = LayoutDeviceIntRect(0, 0, 0, 0);
    mNextConfigurationClipRegion.Clear();
  }
  /**
   * Append the desired widget configuration to aConfigurations.
   */
  void GetWidgetConfiguration(
      nsTArray<nsIWidget::Configuration>* aConfigurations);

  LayoutDeviceIntRect GetWidgetlessClipRect() {
    return RegionFromArray(mNextConfigurationClipRegion).GetBounds();
  }

  /**
   * Called after all widget position/size/clip regions have been changed
   * (even if there isn't a widget for this plugin).
   */
  void DidSetWidgetGeometry();

  // accessibility support
#ifdef ACCESSIBILITY
  virtual mozilla::a11y::AccType AccessibleType() override;
#  ifdef XP_WIN
  NS_IMETHOD GetPluginPort(HWND* aPort);
#  endif
#endif

  // local methods
  nsresult PrepForDrawing(nsIWidget* aWidget);

  // for a given aRoot, this walks the frame tree looking for the next outFrame
  static nsIObjectFrame* GetNextObjectFrame(nsPresContext* aPresContext,
                                            nsIFrame* aRoot);

  // nsIReflowCallback
  virtual bool ReflowFinished() override;
  virtual void ReflowCallbackCanceled() override;

  /**
   * Builds either an ImageLayer or a ReadbackLayer, depending on the type
   * of aItem (TYPE_PLUGIN or TYPE_PLUGIN_READBACK respectively).
   */
  already_AddRefed<Layer> BuildLayer(
      nsDisplayListBuilder* aBuilder, LayerManager* aManager,
      nsDisplayItem* aItem,
      const ContainerLayerParameters& aContainerParameters);

  LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                           LayerManager* aManager);

  /**
   * Get the rectangle (relative to this frame) which it will paint. Normally
   * the frame's content-box but may be smaller if the plugin is rendering
   * asynchronously and has a different-sized image temporarily.
   */
  nsRect GetPaintedRect(const nsDisplayPlugin* aItem) const;

  /**
   * If aSupports has a nsPluginFrame, then prepare it for a DocShell swap.
   * @see nsSubDocumentFrame::BeginSwapDocShells.
   * There will be a call to EndSwapDocShells after we were moved to the
   * new view tree.
   */
  static void BeginSwapDocShells(nsISupports* aSupports);
  /**
   * If aSupports has a nsPluginFrame, then set it up after a DocShell swap.
   * @see nsSubDocumentFrame::EndSwapDocShells.
   */
  static void EndSwapDocShells(nsISupports* aSupports);

  nsIWidget* GetWidget() override {
    if (!mInnerView) {
      return nullptr;
    }
    return mWidget;
  }

  /**
   * Adjust the plugin's idea of its size, using aSize as its new size.
   * (aSize must be in twips)
   */
  void FixupWindow(const nsSize& aSize);

  /*
   * Sets up the plugin window and calls SetWindow on the plugin.
   */
  nsresult CallSetWindow(bool aCheckIsHidden = true);

  void SetInstanceOwner(nsPluginInstanceOwner* aOwner);

  /**
   * HandleWheelEventAsDefaultAction() handles eWheel event as default action.
   * This should be called only when WantsToHandleWheelEventAsDefaultAction()
   * returns true.
   */
  void HandleWheelEventAsDefaultAction(mozilla::WidgetWheelEvent* aEvent);

  /**
   * WantsToHandleWheelEventAsDefaultAction() returns true if the plugin
   * may want to handle wheel events as default action.
   */
  bool WantsToHandleWheelEventAsDefaultAction() const;

  bool CreateWebRenderCommands(
      nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
      mozilla::wr::IpcResourceUpdateQueue& aResources,
      const StackingContextHelper& aSc,
      mozilla::layers::RenderRootStateManager* aManager,
      nsDisplayListBuilder* aDisplayListBuilder);

 protected:
  explicit nsPluginFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
  virtual ~nsPluginFrame();

  // NOTE:  This frame class does not inherit from |nsLeafFrame|, so
  // this is not a virtual method implementation.
  void GetDesiredSize(nsPresContext* aPresContext,
                      const ReflowInput& aReflowInput,
                      ReflowOutput& aDesiredSize);

  // check attributes and optionally CSS to see if we should display anything
  bool IsHidden(bool aCheckVisibilityStyle = true) const;

  bool IsOpaque() const;
  bool IsTransparentMode() const;
  bool IsPaintedByGecko() const;

  nsIntPoint GetWindowOriginInPixels(bool aWindowless);

  /*
   * If this frame is in a remote tab, return the tab offset to
   * the origin of the chrome window. In non-e10s, this return 0,0.
   * This api sends a sync ipc request so be careful about use.
   */
  LayoutDeviceIntPoint GetRemoteTabChromeOffset();

  static void PaintPrintPlugin(nsIFrame* aFrame, gfxContext* aRenderingContext,
                               const nsRect& aDirtyRect, nsPoint aPt);
  void PrintPlugin(gfxContext& aRenderingContext, const nsRect& aDirtyRect);
  void PaintPlugin(nsDisplayListBuilder* aBuilder,
                   gfxContext& aRenderingContext, const nsRect& aDirtyRect,
                   const nsRect& aPluginRect);

  void NotifyPluginReflowObservers();

  friend class nsPluginInstanceOwner;
  friend class nsDisplayPlugin;
  friend class PluginBackgroundSink;

  nsView* GetViewInternal() const override { return mOuterView; }
  void SetViewInternal(nsView* aView) override { mOuterView = aView; }
  bool GetBounds(nsDisplayItem* aItem, mozilla::gfx::IntSize& aSize,
                 gfxRect& aRect);

 private:
  // Registers the plugin for a geometry update, and requests a geometry
  // update. This caches the root pres context in
  // mRootPresContextRegisteredWith, so that we can be sure we unregister
  // from the right root prest context in UnregisterPluginForGeometryUpdates.
  void RegisterPluginForGeometryUpdates();

  // Unregisters the plugin for geometry updated with the root pres context
  // stored in mRootPresContextRegisteredWith.
  void UnregisterPluginForGeometryUpdates();

  static const LayoutDeviceIntRegion RegionFromArray(
      const nsTArray<LayoutDeviceIntRect>& aRects) {
    LayoutDeviceIntRegion region;
    for (uint32_t i = 0; i < aRects.Length(); ++i) {
      region.Or(region, aRects[i]);
    }
    return region;
  }

  class PluginEventNotifier : public mozilla::Runnable {
   public:
    explicit PluginEventNotifier(const nsString& aEventType)
        : mozilla::Runnable("nsPluginFrame::PluginEventNotifier"),
          mEventType(aEventType) {}

    NS_IMETHOD Run() override;

   private:
    nsString mEventType;
  };

  nsPluginInstanceOwner* mInstanceOwner;  // WEAK
  nsView* mOuterView;
  nsView* mInnerView;
  nsCOMPtr<nsIWidget> mWidget;
  nsIntRect mWindowlessRect;
  /**
   * This is owned by the ReadbackLayer for this nsPluginFrame. It is
   * automatically cleared if the PluginBackgroundSink is destroyed.
   */
  PluginBackgroundSink* mBackgroundSink;

  /**
   * Bounds that we should set the plugin's widget to in the next composite,
   * for plugins with widgets. For plugins without widgets, bounds in device
   * pixels relative to the nearest frame that's a display list reference frame.
   */
  LayoutDeviceIntRect mNextConfigurationBounds;
  /**
   * Clip region that we should set the plugin's widget to
   * in the next composite. Only meaningful for plugins with widgets.
   */
  nsTArray<LayoutDeviceIntRect> mNextConfigurationClipRegion;

  bool mReflowCallbackPosted;

  // We keep this reference to ensure we can always unregister the
  // plugins we register on the root PresContext.
  // This is only non-null while we have a plugin registered for geometry
  // updates.
  RefPtr<nsRootPresContext> mRootPresContextRegisteredWith;

  mozilla::UniquePtr<PluginFrameDidCompositeObserver> mDidCompositeObserver;
};

class nsDisplayPluginGeometry : public nsDisplayItemGenericGeometry {
 public:
  nsDisplayPluginGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
      : nsDisplayItemGenericGeometry(aItem, aBuilder) {}

  // Plugins MozPaintWait event depends on sync decode, so we always want
  // to rebuild the display list when sync decoding.
  virtual bool InvalidateForSyncDecodeImages() const override { return true; }
};

class nsDisplayPlugin final : public nsPaintedDisplayItem {
 public:
  nsDisplayPlugin(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
      : nsPaintedDisplayItem(aBuilder, aFrame) {
    MOZ_COUNT_CTOR(nsDisplayPlugin);
    aBuilder->SetContainsPluginItem();
  }
  MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayPlugin)

  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                           bool* aSnap) const override;
  virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                   bool* aSnap) const override;
  virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
  virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                 nsRegion* aVisibleRegion) override;

  NS_DISPLAY_DECL_NAME("Plugin", TYPE_PLUGIN)

  virtual already_AddRefed<Layer> BuildLayer(
      nsDisplayListBuilder* aBuilder, LayerManager* aManager,
      const ContainerLayerParameters& aContainerParameters) override {
    return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(
        aBuilder, aManager, this, aContainerParameters);
  }

  virtual LayerState GetLayerState(
      nsDisplayListBuilder* aBuilder, LayerManager* aManager,
      const ContainerLayerParameters& aParameters) override {
    return static_cast<nsPluginFrame*>(mFrame)->GetLayerState(aBuilder,
                                                              aManager);
  }

  virtual nsDisplayItemGeometry* AllocateGeometry(
      nsDisplayListBuilder* aBuilder) override {
    return new nsDisplayPluginGeometry(this, aBuilder);
  }

  virtual bool CreateWebRenderCommands(
      mozilla::wr::DisplayListBuilder& aBuilder,
      mozilla::wr::IpcResourceUpdateQueue& aResources,
      const StackingContextHelper& aSc,
      mozilla::layers::RenderRootStateManager* aManager,
      nsDisplayListBuilder* aDisplayListBuilder) override;
};

#endif /* nsPluginFrame_h___ */