Bug 1365660: Part 2 - Add a HasRemoteContent flag to popup widgets that contain remote browsers. r?kats,bas.schouten draft
authorKris Maglione <maglione.k@gmail.com>
Wed, 17 May 2017 10:16:25 -0700
changeset 579705 400c8681004568a5840180f23213ce5cc2ea5805
parent 579704 f8477d8181c3df23f00642277815664b5d4a3816
child 579706 12c6833607f8cede5eb0eafc420794907e53c0a3
child 579864 5d302681d2a65eac15bdb7d1cacd9d7c92f8dde3
push id59345
push usermaglione.k@gmail.com
push dateWed, 17 May 2017 17:38:08 +0000
reviewerskats, bas.schouten
bugs1365660
milestone55.0a1
Bug 1365660: Part 2 - Add a HasRemoteContent flag to popup widgets that contain remote browsers. r?kats,bas.schouten There are several behaviors that we only need to apply to popups which are known to contain remote content. And since those behaviors can cause issues elsewhere, we need to be able to identify popups which should contain remote content, and treat them specially, where appropriate. MozReview-Commit-ID: EMFrSP8lZiD
dom/base/nsGkAtomList.h
layout/xul/nsMenuPopupFrame.cpp
layout/xul/nsMenuPopupFrame.h
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsWidgetInitData.h
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1098,16 +1098,17 @@ GK_ATOM(range, "range")
 GK_ATOM(readonly, "readonly")
 GK_ATOM(rect, "rect")
 GK_ATOM(rectangle, "rectangle")
 GK_ATOM(ref, "ref")
 GK_ATOM(refresh, "refresh")
 GK_ATOM(rel, "rel")
 GK_ATOM(onreloadpage, "onreloadpage")
 GK_ATOM(rem, "rem")
+GK_ATOM(remote, "remote")
 GK_ATOM(removeelement, "removeelement")
 GK_ATOM(renderingobserverlist, "renderingobserverlist")
 GK_ATOM(repeat, "repeat")
 GK_ATOM(replace, "replace")
 GK_ATOM(required, "required")
 GK_ATOM(reserved, "reserved")
 GK_ATOM(reset, "reset")
 GK_ATOM(resizeafter, "resizeafter")
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -185,16 +185,24 @@ nsMenuPopupFrame::Init(nsIContent*      
       rootBox->SetDefaultTooltip(aContent);
     }
   }
 
   AddStateBits(NS_FRAME_IN_POPUP);
 }
 
 bool
+nsMenuPopupFrame::HasRemoteContent() const
+{
+  return (!mInContentShell && mPopupType == ePopupTypePanel &&
+          mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::remote,
+                                nsGkAtoms::_true, eIgnoreCase));
+}
+
+bool
 nsMenuPopupFrame::IsNoAutoHide() const
 {
   // Panels with noautohide="true" don't hide when the mouse is clicked
   // outside of them, or when another application is made active. Non-autohide
   // panels cannot be used in content windows.
   return (!mInContentShell && mPopupType == ePopupTypePanel &&
            mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautohide,
                                  nsGkAtoms::_true, eIgnoreCase));
@@ -235,19 +243,22 @@ nsMenuPopupFrame::PopupLevel(bool aIsNoA
   if (aIsNoAutoHide)
     return ePopupLevelParent;
 
   // Otherwise, the result depends on the platform.
   return sDefaultLevelIsTop ? ePopupLevelTop : ePopupLevelParent;
 }
 
 void
-nsMenuPopupFrame::EnsureWidget()
+nsMenuPopupFrame::EnsureWidget(bool aRecreate)
 {
   nsView* ourView = GetView();
+  if (aRecreate) {
+    ourView->DestroyWidget();
+  }
   if (!ourView->HasWidget()) {
     NS_ASSERTION(!mGeneratedChildren && !PrincipalChildList().FirstChild(),
                  "Creating widget for MenuPopupFrame with children");
     CreateWidgetForView(ourView);
   }
 }
 
 nsresult
@@ -286,21 +297,24 @@ nsMenuPopupFrame::CreateWidgetForView(ns
       if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::close,
                                 nsGkAtoms::_true, eCaseMatters)) {
         widgetData.mBorderStyle =
           static_cast<enum nsBorderStyle>(widgetData.mBorderStyle | eBorderStyle_close);
       }
     }
   }
 
+  bool remote = HasRemoteContent();
+
   nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(this, this);
   nsIContent* parentContent = GetContent()->GetParent();
   nsIAtom *tag = nullptr;
   if (parentContent && parentContent->IsXULElement())
     tag = parentContent->NodeInfo()->NameAtom();
+  widgetData.mHasRemoteContent = remote;
   widgetData.mSupportTranslucency = mode == eTransparencyTransparent;
   widgetData.mDropShadow = !(mode == eTransparencyTransparent || tag == nsGkAtoms::menulist);
   widgetData.mPopupLevel = PopupLevel(widgetData.mNoAutoHide);
 
   // panels which have a parent level need a parent widget. This allows them to
   // always appear in front of the parent window but behind other windows that
   // should be in front of it.
   nsCOMPtr<nsIWidget> parentWidget;
@@ -2229,16 +2243,23 @@ nsMenuPopupFrame::AttributeChanged(int32
 #ifndef MOZ_GTK2
   if (aAttribute == nsGkAtoms::noautohide) {
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     if (pm)
       pm->EnableRollup(mContent, !IsNoAutoHide());
   }
 #endif
 
+  if (aAttribute == nsGkAtoms::remote) {
+    // When the remote attribute changes, we need to create a new widget to
+    // ensure that it has the correct compositor and transparency settings to
+    // match the new value.
+    EnsureWidget(true);
+  }
+
   if (aAttribute == nsGkAtoms::followanchor) {
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     if (pm) {
       pm->UpdateFollowAnchor(this);
     }
   }
 
   if (aAttribute == nsGkAtoms::label) {
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -220,26 +220,31 @@ public:
                     nsIFrame*         aPrevInFlow) override;
 
   virtual nsresult AttributeChanged(int32_t aNameSpaceID,
                                     nsIAtom* aAttribute,
                                     int32_t aModType) override;
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
+  bool HasRemoteContent() const;
+
   // returns true if the popup is a panel with the noautohide attribute set to
   // true. These panels do not roll up automatically.
   bool IsNoAutoHide() const;
 
   nsPopupLevel PopupLevel() const
   {
     return PopupLevel(IsNoAutoHide()); 
   }
 
-  void EnsureWidget();
+  // Ensure that a widget has already been created for this view, and create
+  // one if it hasn't. If aRecreate is true, destroys any existing widget and
+  // creates a new one, regardless of whether one has already been created.
+  void EnsureWidget(bool aRecreate = false);
 
   nsresult CreateWidgetForView(nsView* aView);
   uint8_t GetShadowStyle();
 
   virtual void SetInitialChildList(ChildListID  aListID,
                                    nsFrameList& aChildList) override;
 
   virtual bool IsLeaf() const override;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -158,16 +158,17 @@ nsBaseWidget::nsBaseWidget()
 , mCursor(eCursor_standard)
 , mBorderStyle(eBorderStyle_none)
 , mBounds(0,0,0,0)
 , mOriginalBounds(nullptr)
 , mClipRectCount(0)
 , mSizeMode(nsSizeMode_Normal)
 , mPopupLevel(ePopupLevelTop)
 , mPopupType(ePopupTypeAny)
+, mHasRemoteContent(false)
 , mCompositorWidgetDelegate(nullptr)
 , mUpdateCursor(true)
 , mUseAttachedEvents(false)
 , mIMEHasFocus(false)
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
 , mAccessibilityInUseFlag(false)
 #endif
 {
@@ -375,16 +376,17 @@ void nsBaseWidget::BaseCreate(nsIWidget*
   }
 
   // keep a reference to the device context
   if (nullptr != aInitData) {
     mWindowType = aInitData->mWindowType;
     mBorderStyle = aInitData->mBorderStyle;
     mPopupLevel = aInitData->mPopupLevel;
     mPopupType = aInitData->mPopupHint;
+    mHasRemoteContent = aInitData->mHasRemoteContent;
   }
 
   if (aParent) {
     aParent->AddChild(this);
   }
 }
 
 //-------------------------------------------------------------------------
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -544,16 +544,18 @@ protected:
     nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
     return widget.forget();
   }
 
   LayerManager* CreateBasicLayerManager();
 
   nsPopupType PopupType() const { return mPopupType; }
 
+  bool HasRemoteContent() const { return mHasRemoteContent; }
+
   void NotifyRollupGeometryChange()
   {
     // XULPopupManager isn't interested in this notification, so only
     // send it if gRollupListener is set.
     if (gRollupListener) {
       gRollupListener->NotifyGeometryChange();
     }
   }
@@ -678,16 +680,17 @@ protected:
   LayoutDeviceIntRect* mOriginalBounds;
   // When this pointer is null, the widget is not clipped
   mozilla::UniquePtr<LayoutDeviceIntRect[]> mClipRects;
   uint32_t          mClipRectCount;
   nsSizeMode        mSizeMode;
   nsPopupLevel      mPopupLevel;
   nsPopupType       mPopupType;
   SizeConstraints   mSizeConstraints;
+  bool              mHasRemoteContent;
 
   CompositorWidgetDelegate* mCompositorWidgetDelegate;
 
   bool              mUpdateCursor;
   bool              mUseAttachedEvents;
   bool              mIMEHasFocus;
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
   bool              mAccessibilityInUseFlag;
--- a/widget/nsWidgetInitData.h
+++ b/widget/nsWidgetInitData.h
@@ -100,17 +100,18 @@ struct nsWidgetInitData {
       mDropShadow(false),
       mListenForResizes(false),
       mUnicode(true),
       mRTL(false),
       mNoAutoHide(false),
       mIsDragPopup(false),
       mIsAnimationSuppressed(false),
       mSupportTranslucency(false),
-      mMouseTransparent(false)
+      mMouseTransparent(false),
+      mHasRemoteContent(false)
   {
   }
 
   nsWindowType  mWindowType;
   nsBorderStyle mBorderStyle;
   nsPopupType   mPopupHint;
   nsPopupLevel  mPopupLevel;
   // B2G multi-screen support. Screen ID is for differentiating screens of
@@ -126,11 +127,12 @@ struct nsWidgetInitData {
   bool          mIsDragPopup;  // true for drag feedback panels
   // true if window creation animation is suppressed, e.g. for session restore
   bool          mIsAnimationSuppressed;
   // true if the window should support an alpha channel, if available.
   bool          mSupportTranslucency;
   // true if the window should be transparent to mouse events. Currently this is
   // only valid for eWindowType_popup widgets
   bool          mMouseTransparent;
+  bool          mHasRemoteContent;
 };
 
 #endif // nsWidgetInitData_h__